diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index f16b0e46ada95..aa35797d1f986 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -176,6 +176,7 @@ enabled: - x-pack/test/functional/apps/lens/group1/config.ts - x-pack/test/functional/apps/lens/group2/config.ts - x-pack/test/functional/apps/lens/group3/config.ts + - x-pack/test/functional/apps/lens/open_in_lens/config.ts - x-pack/test/functional/apps/license_management/config.ts - x-pack/test/functional/apps/logstash/config.ts - x-pack/test/functional/apps/management/config.ts diff --git a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts index c326e979b93db..b7c223b3ca595 100644 --- a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts +++ b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts @@ -59,11 +59,15 @@ function getRunGroups(bk: BuildkiteClient, allTypes: RunGroup[], typeName: strin if (tooLongs.length > 0) { bk.setAnnotation( `test-group-too-long:${typeName}`, - 'error', + 'warning', [ tooLongs.length === 1 - ? `The following "${typeName}" config has a duration that exceeds the maximum amount of time desired for a single CI job. Please split it up.` - : `The following "${typeName}" configs have durations that exceed the maximum amount of time desired for a single CI job. Please split them up.`, + ? `The following "${typeName}" config has a duration that exceeds the maximum amount of time desired for a single CI job. ` + + `This is not an error, and if you don't own this config then you can ignore this warning. ` + + `If you own this config please split it up ASAP and ask Operations if you have questions about how to do that.` + : `The following "${typeName}" configs have durations that exceed the maximum amount of time desired for a single CI job. ` + + `This is not an error, and if you don't own any of these configs then you can ignore this warning.` + + `If you own any of these configs please split them up ASAP and ask Operations if you have questions about how to do that.`, '', ...tooLongs.map(({ config, durationMin }) => ` - ${config}: ${durationMin} minutes`), ].join('\n') diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 83d63a954873b..04cd0d29b76d1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -348,12 +348,12 @@ x-pack/examples/files_example @elastic/kibana-app-services /x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/response-ops /docs/user/alerting/ @elastic/response-ops @elastic/mlr-docs /docs/management/connectors/ @elastic/response-ops @elastic/mlr-docs -#CC# /x-pack/plugins/stack_alerts/ @elastic/response-ops +/x-pack/plugins/stack_alerts/ @elastic/response-ops /x-pack/plugins/cases/ @elastic/response-ops /x-pack/test/cases_api_integration/ @elastic/response-ops /x-pack/test/functional/services/cases/ @elastic/response-ops /x-pack/test/functional_with_es_ssl/apps/cases/ @elastic/response-ops -/x-pack/test/api_integration/apis/cases @elastic/response-ops +/x-pack/test/api_integration/apis/cases/ @elastic/response-ops # Enterprise Search /x-pack/plugins/enterprise_search @elastic/enterprise-search-frontend @@ -477,26 +477,31 @@ x-pack/examples/files_example @elastic/kibana-app-services /x-pack/plugins/security_solution/common/detection_engine/schemas/alerts @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/common/field_maps @elastic/security-detections-response-alerts +/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/public/detections/pages/alerts @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/server/lib/detection_engine/migrations @elastic/security-detections-response-alerts -/x-pack/plugins/security_solution/server/lib/detection_engine/notifications @elastic/security-detections-response-alerts -/x-pack/plugins/security_solution/server/lib/detection_engine/schemas @elastic/security-detections-response-alerts +/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/server/lib/detection_engine/rule_types @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/server/lib/detection_engine/signals @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/server/lib/detection_engine/routes/index @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals @elastic/security-detections-response-alerts ## Security Solution sub teams - Detections and Response Rules +/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/common/detection_engine/rule_management @elastic/security-detections-response-rules /x-pack/plugins/security_solution/common/detection_engine/rule_monitoring @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/common/detection_engine/schemas/common @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/common/detection_engine/schemas/request @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/common/detection_engine/schemas/response @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/common/detection_engine/rule_schema @elastic/security-detections-response-rules @elastic/security-detections-response-alerts /x-pack/plugins/security_solution/public/common/components/health_truncate_text @elastic/security-detections-response-rules /x-pack/plugins/security_solution/public/common/components/links_to_docs @elastic/security-detections-response-rules /x-pack/plugins/security_solution/public/common/components/ml_popover @elastic/security-detections-response-rules /x-pack/plugins/security_solution/public/common/components/popover_items @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/public/detection_engine/rule_management @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui @elastic/security-detections-response-rules /x-pack/plugins/security_solution/public/detection_engine/rule_monitoring @elastic/security-detections-response-rules /x-pack/plugins/security_solution/public/detections/components/callouts @elastic/security-detections-response-rules /x-pack/plugins/security_solution/public/detections/components/modals/ml_job_upgrade_modal @elastic/security-detections-response-rules @@ -507,17 +512,12 @@ x-pack/examples/files_example @elastic/kibana-app-services /x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules @elastic/security-detections-response-rules /x-pack/plugins/security_solution/public/rules @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route* @elastic/security-solution-platform -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route* @elastic/security-solution-platform -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route* @elastic/security-solution-platform -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route* @elastic/security-detections-response-alerts -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils @elastic/security-solution-platform -/x-pack/plugins/security_solution/server/lib/detection_engine/routes/tags @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management @elastic/security-detections-response-rules /x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/server/lib/detection_engine/rules @elastic/security-detections-response-rules -/x-pack/plugins/security_solution/server/lib/detection_engine/tags @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema @elastic/security-detections-response-rules @elastic/security-detections-response-alerts + /x-pack/plugins/security_solution/server/utils @elastic/security-detections-response-rules ## Security Solution sub teams - Security Platform @@ -527,12 +527,17 @@ x-pack/examples/files_example @elastic/kibana-app-services /x-pack/plugins/security_solution/cypress/e2e/exceptions @elastic/security-solution-platform /x-pack/plugins/security_solution/cypress/e2e/value_lists @elastic/security-solution-platform +/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions @elastic/security-solution-platform + /x-pack/plugins/security_solution/public/detection_engine/rule_exceptions @elastic/security-solution-platform +/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui @elastic/security-solution-platform /x-pack/plugins/security_solution/public/common/components/exceptions @elastic/security-solution-platform /x-pack/plugins/security_solution/public/exceptions @elastic/security-solution-platform /x-pack/plugins/security_solution/public/detections/containers/detection_engine/lists @elastic/security-solution-platform /x-pack/plugins/security_solution/public/common/components/sourcerer @elastic/security-solution-platform +/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy @elastic/security-solution-platform +/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions @elastic/security-solution-platform /x-pack/plugins/security_solution/server/lib/sourcerer @elastic/security-solution-platform ## Security Threat Intelligence - Under Security Platform @@ -595,7 +600,7 @@ x-pack/test/threat_intelligence_cypress @elastic/protections-experience # Security Intelligence And Analytics -/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules @elastic/security-intelligence-analytics +/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules @elastic/security-intelligence-analytics # Security Asset Management @@ -905,6 +910,7 @@ packages/kbn-ftr-common-functional-services @elastic/kibana-operations packages/kbn-ftr-screenshot-filename @elastic/kibana-operations packages/kbn-generate @elastic/kibana-operations packages/kbn-get-repo-files @elastic/kibana-operations +packages/kbn-guided-onboarding @elastic/platform-onboarding packages/kbn-handlebars @elastic/kibana-security packages/kbn-hapi-mocks @elastic/kibana-core packages/kbn-i18n @elastic/kibana-core diff --git a/.i18nrc.json b/.i18nrc.json index 0b38c816d6c69..874c4ecbcc1ba 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -43,6 +43,7 @@ "fieldFormats": "src/plugins/field_formats", "flot": "packages/kbn-flot-charts/lib", "guidedOnboarding": "src/plugins/guided_onboarding", + "guidedOnboardingPackage": "packages/kbn-guided-onboarding", "home": "src/plugins/home", "homePackages": "packages/home", "indexPatternEditor": "src/plugins/data_view_editor", diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index ff78971021336..54cc3bad36d32 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: 2022-10-19 +date: 2022-10-23 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 e3e4af06c5f82..1c616b562dbfa 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: 2022-10-19 +date: 2022-10-23 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 c526162d34ba6..a7333a73effb6 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 2e701198049b0..3178e4112dea5 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -5099,7 +5099,7 @@ "label": "status", "description": [], "signature": [ - "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"active\" | \"ok\"" + "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"ok\" | \"active\"" ], "path": "x-pack/plugins/alerting/common/rule.ts", "deprecated": false, @@ -6084,7 +6084,7 @@ "label": "RuleExecutionStatuses", "description": [], "signature": [ - "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"active\" | \"ok\"" + "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"ok\" | \"active\"" ], "path": "x-pack/plugins/alerting/common/rule.ts", "deprecated": false, diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 2885642d11ece..afa3a174932be 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index 7fd8519951fc6..da5b63f9058c4 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -753,7 +753,7 @@ "label": "APIEndpoint", "description": [], "signature": [ - "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/sorted_and_filtered_services\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service_groups/services_count\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_rate\" | \"GET /internal/apm/alerts/chart_preview/transaction_duration\" | \"GET /internal/apm/alerts/chart_preview/transaction_error_count\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"POST /internal/apm/correlations/field_stats/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\"" + "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search\" | \"POST /api/apm/services/{serviceName}/annotation\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/sorted_and_filtered_services\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service_groups/services_count\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /api/apm/settings/agent-configuration\" | \"GET /api/apm/settings/agent-configuration/view\" | \"DELETE /api/apm/settings/agent-configuration\" | \"PUT /api/apm/settings/agent-configuration\" | \"POST /api/apm/settings/agent-configuration/search\" | \"GET /api/apm/settings/agent-configuration/environments\" | \"GET /api/apm/settings/agent-configuration/agent_name\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps\" | \"POST /api/apm/sourcemaps\" | \"DELETE /api/apm/sourcemaps/{id}\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"POST /internal/apm/correlations/field_stats/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\"" ], "path": "x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts", "deprecated": false, @@ -770,7 +770,7 @@ "signature": [ "\"apm\"" ], - "path": "x-pack/plugins/apm/common/alert_types.ts", + "path": "x-pack/plugins/apm/common/rules/apm_rule_types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -2971,9 +2971,9 @@ "AgentConfiguration", "[]; }, ", "APMRouteCreateOptions", - ">; \"GET /internal/apm/alerts/chart_preview/transaction_duration\": ", + ">; \"GET /internal/apm/rule_types/transaction_duration/chart_preview\": ", "ServerRoute", - "<\"GET /internal/apm/alerts/chart_preview/transaction_duration\", ", + "<\"GET /internal/apm/rule_types/transaction_duration/chart_preview\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -2983,11 +2983,17 @@ "UnionC", "<[", "LiteralC", - "<\"avg\">, ", + "<", + "AggregationType", + ".Avg>, ", "LiteralC", - "<\"95th\">, ", + "<", + "AggregationType", + ".P95>, ", "LiteralC", - "<\"99th\">]>; serviceName: ", + "<", + "AggregationType", + ".P99>]>; serviceName: ", "StringC", "; transactionType: ", "StringC", @@ -3023,11 +3029,11 @@ "section": "def-server.APMRouteHandlerResources", "text": "APMRouteHandlerResources" }, - ", { latencyChartPreview: { x: number; y: number | null; }[]; }, ", + ", { latencyChartPreview: { name: string; data: { x: number; y: number | null; }[]; }[]; }, ", "APMRouteCreateOptions", - ">; \"GET /internal/apm/alerts/chart_preview/transaction_error_count\": ", + ">; \"GET /internal/apm/rule_types/error_count/chart_preview\": ", "ServerRoute", - "<\"GET /internal/apm/alerts/chart_preview/transaction_error_count\", ", + "<\"GET /internal/apm/rule_types/error_count/chart_preview\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -3037,11 +3043,17 @@ "UnionC", "<[", "LiteralC", - "<\"avg\">, ", + "<", + "AggregationType", + ".Avg>, ", "LiteralC", - "<\"95th\">, ", + "<", + "AggregationType", + ".P95>, ", "LiteralC", - "<\"99th\">]>; serviceName: ", + "<", + "AggregationType", + ".P99>]>; serviceName: ", "StringC", "; transactionType: ", "StringC", @@ -3079,9 +3091,9 @@ }, ", { errorCountChartPreview: { x: number; y: number; }[]; }, ", "APMRouteCreateOptions", - ">; \"GET /internal/apm/alerts/chart_preview/transaction_error_rate\": ", + ">; \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\": ", "ServerRoute", - "<\"GET /internal/apm/alerts/chart_preview/transaction_error_rate\", ", + "<\"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -3091,11 +3103,17 @@ "UnionC", "<[", "LiteralC", - "<\"avg\">, ", + "<", + "AggregationType", + ".Avg>, ", "LiteralC", - "<\"95th\">, ", + "<", + "AggregationType", + ".P95>, ", "LiteralC", - "<\"99th\">]>; serviceName: ", + "<", + "AggregationType", + ".P99>]>; serviceName: ", "StringC", "; transactionType: ", "StringC", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index e2b036c4b7a71..51ce445c4aefb 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; @@ -21,7 +21,7 @@ Contact [APM UI](https://github.com/orgs/elastic/teams/apm-ui) for questions reg | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 38 | 0 | 38 | 52 | +| 38 | 0 | 38 | 53 | ## Client diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index e049ff449ade3..80cb4cd80d7cc 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: 2022-10-19 +date: 2022-10-23 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 b7da8c12baeba..7ea8143445eed 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: 2022-10-19 +date: 2022-10-23 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 5d3824a7f973c..68a932b505c75 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: 2022-10-19 +date: 2022-10-23 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 5782d48ee14bb..8311e2257474e 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: 2022-10-19 +date: 2022-10-23 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 dfe11ab7548bc..82d78f3934e29 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: 2022-10-19 +date: 2022-10-23 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 537429792d58c..7eba69a253a0f 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_chat.mdx b/api_docs/cloud_chat.mdx index e3efdcf8833ea..2c4b0bc9627a5 100644 --- a/api_docs/cloud_chat.mdx +++ b/api_docs/cloud_chat.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChat title: "cloudChat" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChat plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index 9d7c2ada71fcc..f3b81492c3aa3 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: 2022-10-19 +date: 2022-10-23 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 44e179b285fb5..7593b2ef8b517 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: 2022-10-19 +date: 2022-10-23 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 0216834c30740..f4a4093565341 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.devdocs.json b/api_docs/controls.devdocs.json index 0768321579c9b..c83780deefca3 100644 --- a/api_docs/controls.devdocs.json +++ b/api_docs/controls.devdocs.json @@ -78,6 +78,38 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.onFiltersPublished$", + "type": "Object", + "tags": [], + "label": "onFiltersPublished$", + "description": [], + "signature": [ + "Subject", + "<", + "Filter", + "[]>" + ], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.onControlRemoved$", + "type": "Object", + "tags": [], + "label": "onControlRemoved$", + "description": [], + "signature": [ + "Subject", + "" + ], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "controls", "id": "def-public.ControlGroupContainer.setLastUsedDataViewId", @@ -174,6 +206,130 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.addDataControlFromField", + "type": "Function", + "tags": [], + "label": "addDataControlFromField", + "description": [], + "signature": [ + "({ uuid, dataViewId, fieldName, title, }: { uuid?: string | undefined; dataViewId: string; fieldName: string; title?: string | undefined; }) => Promise<", + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.ErrorEmbeddable", + "text": "ErrorEmbeddable" + }, + " | ", + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.IEmbeddable", + "text": "IEmbeddable" + }, + "<{ viewMode: ", + { + "pluginId": "embeddable", + "scope": "common", + "docId": "kibEmbeddablePluginApi", + "section": "def-common.ViewMode", + "text": "ViewMode" + }, + "; title: string; id: string; lastReloadRequestTime: number; hidePanelTitles: boolean; enhancements: ", + "SerializableRecord", + "; disabledActions: string[]; disableTriggers: boolean; searchSessionId: string; syncColors: boolean; syncCursor: boolean; syncTooltips: boolean; executionContext: ", + "KibanaExecutionContext", + "; query: ", + "Query", + "; filters: ", + "Filter", + "[]; timeRange: ", + "TimeRange", + "; timeslice: [number, number]; controlStyle: \"twoLine\" | \"oneLine\"; ignoreParentSettings: ", + "ParentIgnoreSettings", + "; fieldName: string; parentFieldName: string; childFieldName: string; dataViewId: string; }, ", + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableOutput", + "text": "EmbeddableOutput" + }, + ">>" + ], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.addDataControlFromField.$1", + "type": "Object", + "tags": [], + "label": "{\n uuid,\n dataViewId,\n fieldName,\n title,\n }", + "description": [], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.addDataControlFromField.$1.uuid", + "type": "string", + "tags": [], + "label": "uuid", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.addDataControlFromField.$1.dataViewId", + "type": "string", + "tags": [], + "label": "dataViewId", + "description": [], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.addDataControlFromField.$1.fieldName", + "type": "string", + "tags": [], + "label": "fieldName", + "description": [], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.addDataControlFromField.$1.title", + "type": "string", + "tags": [], + "label": "title", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, { "parentPluginId": "controls", "id": "def-public.ControlGroupContainer.getCreateControlButton", @@ -400,6 +556,41 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.updateFilterContext", + "type": "Function", + "tags": [], + "label": "updateFilterContext", + "description": [], + "signature": [ + "(filters: ", + "Filter", + "[]) => void" + ], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupContainer.updateFilterContext.$1", + "type": "Array", + "tags": [], + "label": "filters", + "description": [], + "signature": [ + "Filter", + "[]" + ], + "path": "src/plugins/controls/public/control_group/embeddable/control_group_container.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "controls", "id": "def-public.ControlGroupContainer.createNewPanelState", @@ -2847,6 +3038,54 @@ } ], "functions": [ + { + "parentPluginId": "controls", + "id": "def-public.LazyControlGroupRenderer", + "type": "Function", + "tags": [], + "label": "LazyControlGroupRenderer", + "description": [], + "signature": [ + "React.ExoticComponent<", + { + "pluginId": "controls", + "scope": "public", + "docId": "kibControlsPluginApi", + "section": "def-public.ControlGroupRendererProps", + "text": "ControlGroupRendererProps" + }, + "> & { readonly _result: ({ input, onEmbeddableLoad }: ", + { + "pluginId": "controls", + "scope": "public", + "docId": "kibControlsPluginApi", + "section": "def-public.ControlGroupRendererProps", + "text": "ControlGroupRendererProps" + }, + ") => JSX.Element; }" + ], + "path": "src/plugins/controls/public/control_group/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "controls", + "id": "def-public.LazyControlGroupRenderer.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "controls", "id": "def-public.LazyControlsCallout", @@ -3170,6 +3409,88 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupRendererProps", + "type": "Interface", + "tags": [], + "label": "ControlGroupRendererProps", + "description": [], + "path": "src/plugins/controls/public/control_group/control_group_renderer.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupRendererProps.input", + "type": "Object", + "tags": [], + "label": "input", + "description": [], + "signature": [ + "Partial> | undefined" + ], + "path": "src/plugins/controls/public/control_group/control_group_renderer.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupRendererProps.onEmbeddableLoad", + "type": "Function", + "tags": [], + "label": "onEmbeddableLoad", + "description": [], + "signature": [ + "(controlGroupContainer: ", + { + "pluginId": "controls", + "scope": "public", + "docId": "kibControlsPluginApi", + "section": "def-public.ControlGroupContainer", + "text": "ControlGroupContainer" + }, + ") => void" + ], + "path": "src/plugins/controls/public/control_group/control_group_renderer.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "controls", + "id": "def-public.ControlGroupRendererProps.onEmbeddableLoad.$1", + "type": "Object", + "tags": [], + "label": "controlGroupContainer", + "description": [], + "signature": [ + { + "pluginId": "controls", + "scope": "public", + "docId": "kibControlsPluginApi", + "section": "def-public.ControlGroupContainer", + "text": "ControlGroupContainer" + } + ], + "path": "src/plugins/controls/public/control_group/control_group_renderer.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "controls", "id": "def-public.IEditableControlFactory", diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index cf415f7d05127..bebe38125fa4e 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-prese | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 213 | 0 | 205 | 7 | +| 229 | 0 | 220 | 7 | ## Client diff --git a/api_docs/core.devdocs.json b/api_docs/core.devdocs.json index 6ef18a3a1a34a..a84a901314a3f 100644 --- a/api_docs/core.devdocs.json +++ b/api_docs/core.devdocs.json @@ -10552,6 +10552,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "core", + "id": "def-public.SavedObject.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [ + "Timestamp of the time this document had been created." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-common/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "core", "id": "def-public.SavedObject.updated_at", @@ -11160,19 +11176,19 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts" }, { "plugin": "taskManager", @@ -13866,6 +13882,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "core", + "id": "def-public.SimpleSavedObject.createdAt", + "type": "string", + "tags": [], + "label": "createdAt", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-api-browser/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "core", "id": "def-public.SimpleSavedObject.namespaces", @@ -26263,6 +26293,44 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.HttpResourcesServiceToolkit.renderCss", + "type": "Function", + "tags": [], + "label": "renderCss", + "description": [ + "To respond with a custom CSS script file." + ], + "signature": [ + "(options: ", + "HttpResponseOptions", + ") => ", + "IKibanaResponse", + "" + ], + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.HttpResourcesServiceToolkit.renderCss.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "HttpResponseOptions" + ], + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false @@ -27418,7 +27486,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -27426,8 +27494,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -32591,7 +32657,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -32599,8 +32665,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -33795,7 +33859,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -33803,8 +33867,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -38349,7 +38411,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -38357,8 +38419,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -40232,6 +40292,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "core", + "id": "def-server.SavedObject.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [ + "Timestamp of the time this document had been created." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-common/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "core", "id": "def-server.SavedObject.updated_at", @@ -40840,19 +40916,19 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts" }, { "plugin": "taskManager", @@ -46311,6 +46387,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsRawDocSource.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-server/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "core", "id": "def-server.SavedObjectsRawDocSource.references", @@ -50665,7 +50755,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -50673,8 +50763,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", diff --git a/api_docs/core.mdx b/api_docs/core.mdx index 466346f5b02d4..e4f99453eb4ac 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github description: API docs for the core plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] --- import coreObj from './core.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2691 | 0 | 23 | 0 | +| 2697 | 0 | 23 | 0 | ## Client diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 2cd63b73ae98d..8257f56b439fd 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: 2022-10-19 +date: 2022-10-23 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 14fa338b94fc7..16e3b24a27622 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: 2022-10-19 +date: 2022-10-23 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 bc0f1904ce731..b7474702284f1 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 89cc06f810dc9..05b50b5458779 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -2588,7 +2588,7 @@ "description": [], "signature": [ "PluginInitializerContext", - "; }>; asyncSearch: Readonly<{} & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" + "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" ], "path": "src/plugins/data/public/plugin.ts", "deprecated": false, @@ -3509,7 +3509,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts" } ], "children": [], @@ -3823,19 +3823,19 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "inputControlVis", @@ -8035,6 +8035,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-public.SavedObject.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [ + "Timestamp of the time this document had been created." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-common/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-public.SavedObject.updated_at", @@ -11485,14 +11501,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "unifiedSearch", - "path": "src/plugins/unified_search/public/query_string_input/query_string_input.tsx" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/plugin.tsx" - }, { "plugin": "maps", "path": "x-pack/plugins/maps/public/kibana_services.ts" @@ -11780,7 +11788,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; }>; asyncSearch: Readonly<{} & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" + "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" ], "path": "src/plugins/data/server/plugin.ts", "deprecated": false, @@ -12059,14 +12067,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/containers/source/index.tsx" @@ -12077,15 +12077,15 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" + "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" + "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" + "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" }, { "plugin": "securitySolution", @@ -12211,38 +12211,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/hooks/use_es_doc_search.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/hooks/use_data.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx" - }, { "plugin": "aiops", "path": "x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx" @@ -12589,7 +12557,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx" + "path": "x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx" }, { "plugin": "securitySolution", @@ -12875,10 +12843,6 @@ "plugin": "visTypeTimeseries", "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/common/data_views/data_views.ts" @@ -16715,7 +16679,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -16723,8 +16687,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -19577,14 +19539,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/containers/source/index.tsx" @@ -19595,15 +19549,15 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" + "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" + "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" + "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" }, { "plugin": "securitySolution", @@ -19729,38 +19683,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/hooks/use_es_doc_search.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/hooks/use_data.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx" - }, { "plugin": "aiops", "path": "x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx" @@ -20107,7 +20029,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx" + "path": "x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx" }, { "plugin": "securitySolution", @@ -20393,10 +20315,6 @@ "plugin": "visTypeTimeseries", "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts" - }, { "plugin": "dataViews", "path": "src/plugins/data_views/common/data_views/data_views.ts" @@ -25732,6 +25650,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-common.SavedObject.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [ + "Timestamp of the time this document had been created." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-common/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-common.SavedObject.updated_at", diff --git a/api_docs/data.mdx b/api_docs/data.mdx index f7059a9d97173..ff3f642bbdc20 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3242 | 33 | 2516 | 24 | +| 3245 | 33 | 2517 | 24 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 7e8e0f24260a2..02692af299725 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3242 | 33 | 2516 | 24 | +| 3245 | 33 | 2517 | 24 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index a48ebb4f806f4..d3cf37cb35cdd 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -1485,7 +1485,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{} & { search: Readonly<{} & { aggs: Readonly<{} & { shardDelay: Readonly<{} & { enabled: boolean; }>; }>; asyncSearch: Readonly<{} & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>" + "Readonly<{} & { search: Readonly<{} & { aggs: Readonly<{} & { shardDelay: Readonly<{} & { enabled: boolean; }>; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -9881,7 +9881,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts" } ], "children": [], @@ -10195,19 +10195,19 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts" }, { "plugin": "inputControlVis", @@ -16145,7 +16145,7 @@ "id": "def-common.pollSearch.$3", "type": "Object", "tags": [], - "label": "{ pollInterval = 1000, abortSignal }", + "label": "{ pollInterval, abortSignal }", "description": [], "signature": [ { @@ -26214,7 +26214,7 @@ "tags": [], "label": "pollInterval", "description": [ - "\nThe number of milliseconds to wait between receiving a response and sending another request" + "\nThe number of milliseconds to wait between receiving a response and sending another request\nIf not provided, then a default 1 second interval with back-off up to 5 seconds interval is used" ], "signature": [ "number | undefined" @@ -28804,6 +28804,20 @@ "path": "src/plugins/data/common/search/session/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.SearchSessionStatusResponse.errors", + "type": "Array", + "tags": [], + "label": "errors", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "src/plugins/data/common/search/session/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 6b162ba8ec21d..809ddb0d16ab6 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3242 | 33 | 2516 | 24 | +| 3245 | 33 | 2517 | 24 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index c3711d5fc355c..5a76611b80dd2 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: 2022-10-19 +date: 2022-10-23 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 5b0551e6a3fb4..04513522d63d9 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: 2022-10-19 +date: 2022-10-23 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 41b319812755c..c2db9979d86b4 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index 226184e386e0f..38860d23cee6a 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -57,14 +57,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/containers/source/index.tsx" @@ -75,15 +67,15 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" + "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" + "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" + "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" }, { "plugin": "securitySolution", @@ -217,38 +209,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/hooks/use_es_doc_search.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/hooks/use_data.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx" - }, { "plugin": "aiops", "path": "x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx" @@ -595,7 +555,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx" + "path": "x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx" }, { "plugin": "securitySolution", @@ -913,10 +873,6 @@ "plugin": "visTypeTimeseries", "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.test.ts" @@ -8016,14 +7972,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/containers/source/index.tsx" @@ -8034,15 +7982,15 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" + "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" + "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" + "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" }, { "plugin": "securitySolution", @@ -8176,38 +8124,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/hooks/use_es_doc_search.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/hooks/use_data.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx" - }, { "plugin": "aiops", "path": "x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx" @@ -8554,7 +8470,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx" + "path": "x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx" }, { "plugin": "securitySolution", @@ -8872,10 +8788,6 @@ "plugin": "visTypeTimeseries", "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.test.ts" @@ -13993,7 +13905,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -14001,8 +13913,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -15124,14 +15034,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, - { - "plugin": "timelines", - "path": "x-pack/plugins/timelines/public/container/source/index.tsx" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/containers/source/index.tsx" @@ -15142,15 +15044,15 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" + "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" + "path": "x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts" + "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts" }, { "plugin": "securitySolution", @@ -15284,38 +15186,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/hooks/use_es_doc_search.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/utils/resolve_data_view.ts" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx" - }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/hooks/use_data.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts" - }, - { - "plugin": "aiops", - "path": "x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx" - }, { "plugin": "aiops", "path": "x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx" @@ -15662,7 +15532,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx" + "path": "x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx" }, { "plugin": "securitySolution", @@ -15980,10 +15850,6 @@ "plugin": "visTypeTimeseries", "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, - { - "plugin": "discover", - "path": "src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.test.ts" @@ -23311,6 +23177,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "dataViews", + "id": "def-common.SavedObject.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [ + "Timestamp of the time this document had been created." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-common/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "dataViews", "id": "def-common.SavedObject.updated_at", diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 81e9e256c6019..403656d6a3ce6 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1020 | 0 | 229 | 2 | +| 1021 | 0 | 229 | 2 | ## Client diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index e0047a10a27f9..5c9328219afe8 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: 2022-10-19 +date: 2022-10-23 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 396507d79f860..cebf0dbaafe01 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -27,21 +27,19 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | savedObjects, embeddable, fleet, visualizations, dashboard, infra, canvas, graph, actions, alerting, enterpriseSearch, securitySolution, taskManager, savedSearch, ml, @kbn/core-saved-objects-server-internal | - | | | savedObjects, embeddable, fleet, visualizations, dashboard, infra, canvas, graph, actions, alerting, enterpriseSearch, securitySolution, taskManager, savedSearch, ml, @kbn/core-saved-objects-server-internal | - | | | discover, maps, monitoring | - | -| | unifiedSearch, discover, maps, infra, graph, securitySolution, stackAlerts, inputControlVis, savedObjects | - | -| | timelines, securitySolution, lists, threatIntelligence, dataViews, dataViewEditor, unifiedSearch, triggersActionsUi, savedObjectsManagement, unifiedFieldList, discover, aiops, presentationUtil, controls, lens, observability, infra, maps, dataVisualizer, ml, fleet, visTypeTimeseries, apm, reporting, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, dataViewManagement, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega, data | - | -| | timelines, securitySolution, lists, threatIntelligence, dataViews, dataViewEditor, unifiedSearch, triggersActionsUi, savedObjectsManagement, unifiedFieldList, discover, aiops, presentationUtil, controls, lens, observability, infra, maps, dataVisualizer, ml, fleet, visTypeTimeseries, apm, reporting, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, dataViewManagement, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega, data | - | -| | timelines, securitySolution, lists, threatIntelligence, data, dataViewEditor, unifiedSearch, triggersActionsUi, savedObjectsManagement, unifiedFieldList, discover, aiops, presentationUtil, controls, lens, observability, infra, maps, dataVisualizer, ml, fleet, visTypeTimeseries, apm, reporting, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, dataViewManagement, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega | - | +| | securitySolution, timelines, lists, threatIntelligence, dataViews, dataViewEditor, unifiedSearch, triggersActionsUi, savedObjectsManagement, unifiedFieldList, aiops, presentationUtil, controls, lens, observability, infra, maps, dataVisualizer, ml, fleet, visTypeTimeseries, apm, reporting, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, dataViewManagement, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega, discover, data | - | +| | securitySolution, timelines, lists, threatIntelligence, dataViews, dataViewEditor, unifiedSearch, triggersActionsUi, savedObjectsManagement, unifiedFieldList, aiops, presentationUtil, controls, lens, observability, infra, maps, dataVisualizer, ml, fleet, visTypeTimeseries, apm, reporting, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, dataViewManagement, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega, discover, data | - | +| | securitySolution, timelines, lists, threatIntelligence, data, dataViewEditor, unifiedSearch, triggersActionsUi, savedObjectsManagement, unifiedFieldList, aiops, presentationUtil, controls, lens, observability, infra, maps, dataVisualizer, ml, fleet, visTypeTimeseries, apm, reporting, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, dataViewManagement, inputControlVis, visDefaultEditor, visTypeTimelion, visTypeVega, discover | - | | | data, discover, embeddable | - | | | advancedSettings, discover | - | | | advancedSettings, discover | - | +| | maps, infra, graph, securitySolution, stackAlerts, inputControlVis, savedObjects | - | | | securitySolution | - | | | encryptedSavedObjects, actions, data, ml, logstash, securitySolution, cloudChat | - | | | dashboard, dataVisualizer, stackAlerts, expressionPartitionVis | - | | | dataViews, maps | - | | | dataViews, maps | - | | | maps | - | -| | unifiedSearch | - | -| | unifiedSearch | - | | | visTypeTimeseries, graph, dataViewManagement, dataViews | - | | | visTypeTimeseries, graph, dataViewManagement, dataViews | - | | | visTypeTimeseries, graph, dataViewManagement | - | @@ -51,6 +49,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | dataViews, dataViewManagement | - | | | dataViewManagement, dataViews | - | | | dataViews, dataViewManagement | - | +| | unifiedSearch | - | +| | unifiedSearch | - | | | home, data, esUiShared, spaces, savedObjectsManagement, fleet, observability, ml, apm, indexLifecycleManagement, synthetics, upgradeAssistant, ux, kibanaOverview | - | | | spaces, savedObjectsManagement | - | | | spaces, savedObjectsManagement | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 4b092aa500694..26233cbd00341 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -129,9 +129,9 @@ so TS and code-reference navigation might not highlight them. | | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [use_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/hooks/use_data.ts#:~:text=title), [full_time_range_selector_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts#:~:text=title), [explain_log_rate_spikes_analysis.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx#:~:text=title), [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title), [use_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/hooks/use_data.ts#:~:text=title), [full_time_range_selector_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts#:~:text=title), [explain_log_rate_spikes_analysis.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx#:~:text=title), [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title) | - | -| | [use_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/hooks/use_data.ts#:~:text=title), [full_time_range_selector_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts#:~:text=title), [explain_log_rate_spikes_analysis.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx#:~:text=title), [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title), [use_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/hooks/use_data.ts#:~:text=title), [full_time_range_selector_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts#:~:text=title), [explain_log_rate_spikes_analysis.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx#:~:text=title), [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title) | - | -| | [use_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/hooks/use_data.ts#:~:text=title), [full_time_range_selector_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts#:~:text=title), [explain_log_rate_spikes_analysis.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx#:~:text=title), [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title) | - | +| | [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title), [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title) | - | +| | [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title), [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title) | - | +| | [log_categorization_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx#:~:text=title) | - | @@ -320,11 +320,10 @@ so TS and code-reference navigation might not highlight them. | | ---------------|-----------|-----------| | | [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx#:~:text=create), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx#:~:text=create) | - | | | [discover_state.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/services/discover_state.ts#:~:text=syncQueryStateWithUrl), [discover_state.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/services/discover_state.ts#:~:text=syncQueryStateWithUrl) | - | -| | [plugin.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/plugin.tsx#:~:text=indexPatterns) | - | -| | [use_es_doc_search.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/hooks/use_es_doc_search.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [discover_sidebar.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx#:~:text=title), [discover_topnav.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx#:~:text=title), [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title), [get_layout_props.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts#:~:text=title), [use_es_doc_search.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/hooks/use_es_doc_search.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title)+ 4 more | - | +| | [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title), [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title) | - | | | [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx#:~:text=create), [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx#:~:text=create) | - | -| | [use_es_doc_search.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/hooks/use_es_doc_search.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [discover_sidebar.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx#:~:text=title), [discover_topnav.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx#:~:text=title), [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title), [get_layout_props.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts#:~:text=title), [use_es_doc_search.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/hooks/use_es_doc_search.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title)+ 4 more | - | -| | [use_es_doc_search.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/hooks/use_es_doc_search.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [resolve_data_view.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/utils/resolve_data_view.ts#:~:text=title), [discover_sidebar.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx#:~:text=title), [discover_topnav.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx#:~:text=title), [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title), [get_layout_props.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts#:~:text=title) | - | +| | [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title), [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title) | - | +| | [use_adhoc_data_views.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/hooks/use_adhoc_data_views.test.ts#:~:text=title) | - | | | [on_save_search.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx#:~:text=SavedObjectSaveModal), [on_save_search.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | | | [saved_search_embeddable.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx#:~:text=executeTriggerActions), [search_embeddable_factory.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/embeddable/search_embeddable_factory.ts#:~:text=executeTriggerActions), [plugin.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/discover/public/plugin.tsx#:~:text=executeTriggerActions) | - | | | [ui_settings.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/server/ui_settings.ts#:~:text=metric), [ui_settings.ts](https://github.com/elastic/kibana/tree/main/src/plugins/discover/server/ui_settings.ts#:~:text=metric) | - | @@ -740,23 +739,23 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.ts#:~:text=create) | - | -| | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch) | - | +| | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts#:~:text=create) | - | +| | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch) | - | | | [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=indexPatterns), [dependencies_start_mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/endpoint/dependencies_start_mock.ts#:~:text=indexPatterns) | - | -| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [get_es_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts#:~:text=title), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=title), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts#:~:text=title), [get_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts#:~:text=title), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/alerts_actions/utils.test.ts#:~:text=title), [validators.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx#:~:text=title)+ 18 more | - | -| | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.ts#:~:text=create) | - | -| | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts#:~:text=fetch) | - | +| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts#:~:text=title), [get_es_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts#:~:text=title), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=title), [get_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts#:~:text=title), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/alerts_actions/utils.test.ts#:~:text=title), [validators.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx#:~:text=title)+ 18 more | - | +| | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts#:~:text=create) | - | +| | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch) | - | | | [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/eql/api.ts#:~:text=options) | - | -| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [get_es_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts#:~:text=title), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=title), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts#:~:text=title), [get_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts#:~:text=title), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/alerts_actions/utils.test.ts#:~:text=title), [validators.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx#:~:text=title)+ 18 more | - | -| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [get_es_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts#:~:text=title), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=title), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts#:~:text=title), [get_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts#:~:text=title), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/alerts_actions/utils.test.ts#:~:text=title), [validators.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx#:~:text=title)+ 4 more | - | -| | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 5 more | 8.8.0 | -| | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 5 more | 8.8.0 | +| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts#:~:text=title), [get_es_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts#:~:text=title), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=title), [get_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts#:~:text=title), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/alerts_actions/utils.test.ts#:~:text=title), [validators.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx#:~:text=title)+ 18 more | - | +| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#:~:text=title), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts#:~:text=title), [get_es_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts#:~:text=title), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=title), [get_query_filter.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/mock/index_pattern.ts#:~:text=title), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/alerts_actions/utils.test.ts#:~:text=title), [validators.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/validators.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx#:~:text=title)+ 4 more | - | +| | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 6 more | 8.8.0 | +| | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 6 more | 8.8.0 | | | [query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts#:~:text=license%24) | 8.8.0 | -| | [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [create_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts#:~:text=authc), [delete_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts#:~:text=authc), [finalize_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts#:~:text=authc), [open_close_signals_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts#:~:text=authc), [preview_rules_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts#:~:text=authc), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts#:~:text=authc) | - | +| | [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts#:~:text=authc), [create_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts#:~:text=authc), [delete_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts#:~:text=authc), [finalize_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts#:~:text=authc), [open_close_signals_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts#:~:text=authc), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts#:~:text=authc) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/index.tsx#:~:text=onAppLeave), [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/plugin.tsx#:~:text=onAppLeave) | 8.8.0 | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [use_timeline_save_prompt.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts#:~:text=AppLeaveHandler)+ 1 more | 8.8.0 | -| | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | -| | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | +| | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | +| | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | @@ -830,9 +829,9 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title) | - | -| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title) | - | -| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/container/source/index.tsx#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title) | - | +| | [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title) | - | +| | [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title), [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title) | - | +| | [index_pattern.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/public/mock/index_pattern.ts#:~:text=title), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts#:~:text=title) | - | @@ -871,7 +870,6 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [query_string_input.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/query_string_input/query_string_input.tsx#:~:text=indexPatterns) | - | | | [value_suggestion_provider.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/autocomplete/providers/value_suggestion_provider.ts#:~:text=title), [fetch_index_patterns.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/query_string_input/fetch_index_patterns.ts#:~:text=title), [change_dataview.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx#:~:text=title), [value_suggestion_provider.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/autocomplete/providers/value_suggestion_provider.ts#:~:text=title), [fetch_index_patterns.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/query_string_input/fetch_index_patterns.ts#:~:text=title), [change_dataview.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx#:~:text=title) | - | | | [value_suggestion_provider.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/autocomplete/providers/value_suggestion_provider.ts#:~:text=title), [fetch_index_patterns.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/query_string_input/fetch_index_patterns.ts#:~:text=title), [change_dataview.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx#:~:text=title), [value_suggestion_provider.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/autocomplete/providers/value_suggestion_provider.ts#:~:text=title), [fetch_index_patterns.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/query_string_input/fetch_index_patterns.ts#:~:text=title), [change_dataview.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx#:~:text=title) | - | | | [value_suggestion_provider.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/autocomplete/providers/value_suggestion_provider.ts#:~:text=title), [fetch_index_patterns.ts](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/query_string_input/fetch_index_patterns.ts#:~:text=title), [change_dataview.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx#:~:text=title) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index d55cd50f5d4ce..d2a02861d0e0c 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -163,8 +163,8 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| -| securitySolution | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 5 more | 8.8.0 | -| securitySolution | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 5 more | 8.8.0 | +| securitySolution | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 6 more | 8.8.0 | +| securitySolution | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode)+ 6 more | 8.8.0 | | securitySolution | | [query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts#:~:text=license%24) | 8.8.0 | | securitySolution | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/index.tsx#:~:text=onAppLeave), [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/plugin.tsx#:~:text=onAppLeave) | 8.8.0 | | securitySolution | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [use_timeline_save_prompt.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts#:~:text=AppLeaveHandler)+ 1 more | 8.8.0 | diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 475f18fd17c60..a956ce2a8b26b 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 4e846b4c8c402..09042927909c3 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 88e0017d2dfbc..6aae06de7d242 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index 21a6b55795244..d82dd8df9db25 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -1253,7 +1253,7 @@ "section": "def-public.IEmbeddable", "text": "IEmbeddable" }, - ">(type: string, explicitInput: Partial) => Promise<", + ">(type: string, explicitInput: Partial) => Promise" + ">" ], "path": "src/plugins/embeddable/public/lib/containers/container.ts", "deprecated": false, diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index d9aa4244cca26..0d49f8267ebee 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: 2022-10-19 +date: 2022-10-23 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 789b736ce7763..e78fd82e2e38e 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: 2022-10-19 +date: 2022-10-23 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 d26167d4d648d..36b814915bdf3 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: 2022-10-19 +date: 2022-10-23 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 c4869c94766ef..d616d64dd8932 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: 2022-10-19 +date: 2022-10-23 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 57359193d1f79..06bc5df53e271 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: 2022-10-19 +date: 2022-10-23 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 d9de10cfdc2cc..bbb9088940ff1 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.devdocs.json b/api_docs/event_log.devdocs.json index 697461ca39d3c..6018838914f57 100644 --- a/api_docs/event_log.devdocs.json +++ b/api_docs/event_log.devdocs.json @@ -1312,7 +1312,7 @@ "label": "data", "description": [], "signature": [ - "(Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ active?: string | number | undefined; recovered?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; outcome?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined)[]" + "(Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; uuid?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; outcome?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; uuid?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined)[]" ], "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", "deprecated": false, @@ -1332,7 +1332,7 @@ "label": "IEvent", "description": [], "signature": [ - "DeepPartial | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ active?: string | number | undefined; recovered?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; outcome?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; uuid?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; outcome?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; uuid?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, @@ -1347,7 +1347,7 @@ "label": "IValidatedEvent", "description": [], "signature": [ - "Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ active?: string | number | undefined; recovered?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; outcome?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined" + "Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; uuid?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; outcome?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; uuid?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 64e95f1c9b335..065b80149711d 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 2954c9b6b39f4..7d820bb73382e 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: 2022-10-19 +date: 2022-10-23 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 d8e240b3fad58..d8b1fffc337db 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: 2022-10-19 +date: 2022-10-23 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 111be86e0f4b1..b2cd2fe4f7cc8 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: 2022-10-19 +date: 2022-10-23 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 1ba388fe98a3a..c22351080534a 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: 2022-10-19 +date: 2022-10-23 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 b0a7ded868a31..c859f4cd30f90 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: 2022-10-19 +date: 2022-10-23 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 7825eb68c5d7a..c79c71ed72202 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: 2022-10-19 +date: 2022-10-23 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 c8116cbc576fc..9c03a3f94cb45 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: 2022-10-19 +date: 2022-10-23 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 6e2ab61f27a30..09332bf98297d 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: 2022-10-19 +date: 2022-10-23 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 9af2fe420e453..7caf1ba02c300 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: 2022-10-19 +date: 2022-10-23 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 9f9ffcc86edcc..0cefcc590b6a6 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: 2022-10-19 +date: 2022-10-23 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 7404707dfe24e..12fa794207d48 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: 2022-10-19 +date: 2022-10-23 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 497e0613dff94..39e36c19b4f0a 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: 2022-10-19 +date: 2022-10-23 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 868cba6ee7c88..70dee18af479f 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: 2022-10-19 +date: 2022-10-23 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 b89c92eaf354c..044295ea4d66d 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: 2022-10-19 +date: 2022-10-23 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 281c225d0d5c0..856885c3726c1 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: 2022-10-19 +date: 2022-10-23 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 7971377311b71..8d1182342c901 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: 2022-10-19 +date: 2022-10-23 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 365e7a671597b..09086e7fc0587 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.devdocs.json b/api_docs/files.devdocs.json index 86537866c421c..520b91977324a 100644 --- a/api_docs/files.devdocs.json +++ b/api_docs/files.devdocs.json @@ -1650,7 +1650,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -1658,8 +1658,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 8673b87257078..ffcdd61002c3b 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 21d05ee976bb4..f9525660b4ded 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -8328,7 +8328,7 @@ "label": "status", "description": [], "signature": [ - "\"inactive\" | \"active\"" + "\"active\" | \"inactive\"" ], "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", "deprecated": false, @@ -13176,7 +13176,7 @@ { "parentPluginId": "fleet", "id": "def-common.RegistryElasticsearch.index_template.settings", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "'index_template.settings'", "description": [], diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 63e6e2212cf75..e59ef75835f52 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: 2022-10-19 +date: 2022-10-23 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 c0d719636ff2c..67fe8af5d61e5 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.devdocs.json b/api_docs/guided_onboarding.devdocs.json index 701721e92edd3..2fcc0495ff8d7 100644 --- a/api_docs/guided_onboarding.devdocs.json +++ b/api_docs/guided_onboarding.devdocs.json @@ -6,111 +6,467 @@ "interfaces": [ { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideState", + "id": "def-public.GuidedOnboardingApi", "type": "Interface", "tags": [], - "label": "GuideState", + "label": "GuidedOnboardingApi", "description": [], - "path": "src/plugins/guided_onboarding/common/types.ts", + "path": "src/plugins/guided_onboarding/public/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideState.guideId", - "type": "CompoundType", + "id": "def-public.GuidedOnboardingApi.setup", + "type": "Function", "tags": [], - "label": "guideId", + "label": "setup", "description": [], "signature": [ - "\"search\" | \"security\" | \"observability\"" + "(httpClient: ", + "HttpSetup", + ") => void" ], - "path": "src/plugins/guided_onboarding/common/types.ts", + "path": "src/plugins/guided_onboarding/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.setup.$1", + "type": "Object", + "tags": [], + "label": "httpClient", + "description": [], + "signature": [ + "HttpSetup" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] }, { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideState.status", - "type": "CompoundType", + "id": "def-public.GuidedOnboardingApi.fetchActiveGuideState$", + "type": "Function", "tags": [], - "label": "status", + "label": "fetchActiveGuideState$", "description": [], "signature": [ - "\"complete\" | \"in_progress\" | \"ready_to_complete\"" + "() => ", + "Observable", + "<", + "GuideState", + " | undefined>" ], - "path": "src/plugins/guided_onboarding/common/types.ts", + "path": "src/plugins/guided_onboarding/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [], + "returnComment": [] }, { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideState.isActive", - "type": "CompoundType", + "id": "def-public.GuidedOnboardingApi.fetchAllGuidesState", + "type": "Function", "tags": [], - "label": "isActive", + "label": "fetchAllGuidesState", "description": [], "signature": [ - "boolean | undefined" + "() => Promise<{ state: ", + "GuideState", + "[]; } | undefined>" ], - "path": "src/plugins/guided_onboarding/common/types.ts", + "path": "src/plugins/guided_onboarding/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [], + "returnComment": [] }, { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideState.steps", - "type": "Array", + "id": "def-public.GuidedOnboardingApi.updateGuideState", + "type": "Function", "tags": [], - "label": "steps", + "label": "updateGuideState", "description": [], "signature": [ - "GuideStep", - "[]" + "(newState: ", + "GuideState", + ", panelState: boolean) => Promise<{ state: ", + "GuideState", + "; } | undefined>" ], - "path": "src/plugins/guided_onboarding/common/types.ts", + "path": "src/plugins/guided_onboarding/public/types.ts", "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideStep", - "type": "Interface", - "tags": [], - "label": "GuideStep", - "description": [], - "path": "src/plugins/guided_onboarding/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.updateGuideState.$1", + "type": "Object", + "tags": [], + "label": "newState", + "description": [], + "signature": [ + "GuideState" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.updateGuideState.$2", + "type": "boolean", + "tags": [], + "label": "panelState", + "description": [], + "signature": [ + "boolean" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideStep.id", - "type": "CompoundType", + "id": "def-public.GuidedOnboardingApi.activateGuide", + "type": "Function", "tags": [], - "label": "id", + "label": "activateGuide", "description": [], "signature": [ - "\"add_data\" | \"view_dashboard\" | \"tour_observability\" | \"rules\" | \"alertsCases\" | \"browse_docs\" | \"search_experience\"" + "(guideId: ", + "GuideId", + ", guide?: ", + "GuideState", + " | undefined) => Promise<{ state: ", + "GuideState", + "; } | undefined>" ], - "path": "src/plugins/guided_onboarding/common/types.ts", + "path": "src/plugins/guided_onboarding/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.activateGuide.$1", + "type": "CompoundType", + "tags": [], + "label": "guideId", + "description": [], + "signature": [ + "GuideId" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.activateGuide.$2", + "type": "Object", + "tags": [], + "label": "guide", + "description": [], + "signature": [ + "GuideState", + " | undefined" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.completeGuide", + "type": "Function", + "tags": [], + "label": "completeGuide", + "description": [], + "signature": [ + "(guideId: ", + "GuideId", + ") => Promise<{ state: ", + "GuideState", + "; } | undefined>" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.completeGuide.$1", + "type": "CompoundType", + "tags": [], + "label": "guideId", + "description": [], + "signature": [ + "GuideId" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.isGuideStepActive$", + "type": "Function", + "tags": [], + "label": "isGuideStepActive$", + "description": [], + "signature": [ + "(guideId: ", + "GuideId", + ", stepId: ", + "GuideStepIds", + ") => ", + "Observable", + "" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.isGuideStepActive$.$1", + "type": "CompoundType", + "tags": [], + "label": "guideId", + "description": [], + "signature": [ + "GuideId" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.isGuideStepActive$.$2", + "type": "CompoundType", + "tags": [], + "label": "stepId", + "description": [], + "signature": [ + "GuideStepIds" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.startGuideStep", + "type": "Function", + "tags": [], + "label": "startGuideStep", + "description": [], + "signature": [ + "(guideId: ", + "GuideId", + ", stepId: ", + "GuideStepIds", + ") => Promise<{ state: ", + "GuideState", + "; } | undefined>" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.startGuideStep.$1", + "type": "CompoundType", + "tags": [], + "label": "guideId", + "description": [], + "signature": [ + "GuideId" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.startGuideStep.$2", + "type": "CompoundType", + "tags": [], + "label": "stepId", + "description": [], + "signature": [ + "GuideStepIds" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] }, { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideStep.status", - "type": "CompoundType", + "id": "def-public.GuidedOnboardingApi.completeGuideStep", + "type": "Function", "tags": [], - "label": "status", + "label": "completeGuideStep", "description": [], "signature": [ - "\"complete\" | \"in_progress\" | \"ready_to_complete\" | \"inactive\" | \"active\"" + "(guideId: ", + "GuideId", + ", stepId: ", + "GuideStepIds", + ") => Promise<{ state: ", + "GuideState", + "; } | undefined>" ], - "path": "src/plugins/guided_onboarding/common/types.ts", + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.completeGuideStep.$1", + "type": "CompoundType", + "tags": [], + "label": "guideId", + "description": [], + "signature": [ + "GuideId" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.completeGuideStep.$2", + "type": "CompoundType", + "tags": [], + "label": "stepId", + "description": [], + "signature": [ + "GuideStepIds" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.isGuidedOnboardingActiveForIntegration$", + "type": "Function", + "tags": [], + "label": "isGuidedOnboardingActiveForIntegration$", + "description": [], + "signature": [ + "(integration?: string | undefined) => ", + "Observable", + "" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.isGuidedOnboardingActiveForIntegration$.$1", + "type": "string", + "tags": [], + "label": "integration", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.completeGuidedOnboardingForIntegration", + "type": "Function", + "tags": [], + "label": "completeGuidedOnboardingForIntegration", + "description": [], + "signature": [ + "(integration?: string | undefined) => Promise<{ state: ", + "GuideState", + "; } | undefined>" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.completeGuidedOnboardingForIntegration.$1", + "type": "string", + "tags": [], + "label": "integration", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuidedOnboardingApi.isGuidePanelOpen$", + "type": "Object", + "tags": [], + "label": "isGuidePanelOpen$", + "description": [], + "signature": [ + "Observable", + "" + ], + "path": "src/plugins/guided_onboarding/public/types.ts", "deprecated": false, "trackAdoption": false } @@ -119,38 +475,7 @@ } ], "enums": [], - "misc": [ - { - "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideId", - "type": "Type", - "tags": [], - "label": "GuideId", - "description": [], - "signature": [ - "\"search\" | \"security\" | \"observability\"" - ], - "path": "src/plugins/guided_onboarding/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "guidedOnboarding", - "id": "def-public.GuideStepIds", - "type": "Type", - "tags": [], - "label": "GuideStepIds", - "description": [], - "signature": [ - "\"add_data\" | \"view_dashboard\" | \"tour_observability\" | \"rules\" | \"alertsCases\" | \"browse_docs\" | \"search_experience\"" - ], - "path": "src/plugins/guided_onboarding/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], + "misc": [], "objects": [ { "parentPluginId": "guidedOnboarding", @@ -242,7 +567,13 @@ "label": "guidedOnboardingApi", "description": [], "signature": [ - "GuidedOnboardingApi", + { + "pluginId": "guidedOnboarding", + "scope": "public", + "docId": "kibGuidedOnboardingPluginApi", + "section": "def-public.GuidedOnboardingApi", + "text": "GuidedOnboardingApi" + }, " | undefined" ], "path": "src/plugins/guided_onboarding/public/types.ts", diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index f7d6bbb5fed3a..6340b64fe54b0 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onbo | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 19 | 0 | 19 | 3 | +| 36 | 0 | 36 | 1 | ## Client @@ -37,9 +37,6 @@ Contact [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onbo ### Interfaces -### Consts, variables and types - - ## Server ### Setup diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 40f45ae1b37e7..13012d42b1d35 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 22712915cb6af..d7fc448f9f7c1 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: 2022-10-19 +date: 2022-10-23 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 4ea69ba0e2119..47787f43aab92 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: 2022-10-19 +date: 2022-10-23 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 1c20f2ab32c62..c881c2ce25c57 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: 2022-10-19 +date: 2022-10-23 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 ae5b4beb33212..19819779b5770 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: 2022-10-19 +date: 2022-10-23 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 e186edc03196e..52b209dff052b 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: 2022-10-19 +date: 2022-10-23 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 446654d570ef2..d43bfc6dd5dec 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: 2022-10-19 +date: 2022-10-23 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 5dda17615eb00..ddcb6c77e6a79 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: 2022-10-19 +date: 2022-10-23 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 52055a044668e..f62b95d2df38f 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index d0766b58a9d73..deefb9635ebe0 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 4107ef2ffa6eb..08bee61a23188 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.devdocs.json b/api_docs/kbn_analytics_client.devdocs.json index e9f518ba24c3f..f4bf073a712a2 100644 --- a/api_docs/kbn_analytics_client.devdocs.json +++ b/api_docs/kbn_analytics_client.devdocs.json @@ -1836,7 +1836,7 @@ "Types matching number values" ], "signature": [ - "\"date\" | \"long\" | \"double\" | \"short\" | \"float\" | \"integer\" | \"byte\"" + "\"date\" | \"long\" | \"double\" | \"short\" | \"byte\" | \"float\" | \"integer\"" ], "path": "packages/analytics/client/src/schema/types.ts", "deprecated": false, @@ -1870,7 +1870,7 @@ "\nPossible type values in the schema" ], "signature": [ - "\"boolean\" | \"date\" | \"keyword\" | \"text\" | \"long\" | \"double\" | \"short\" | \"float\" | \"integer\" | \"byte\"" + "\"boolean\" | \"date\" | \"keyword\" | \"text\" | \"long\" | \"double\" | \"short\" | \"byte\" | \"float\" | \"integer\"" ], "path": "packages/analytics/client/src/schema/types.ts", "deprecated": false, diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index 34ddb4f5b3318..8f789f57d711b 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: 2022-10-19 +date: 2022-10-23 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 8baf418b9746b..c863dda03cd2d 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: 2022-10-19 +date: 2022-10-23 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 cfd51c356e643..ebbae5c06d2d9 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: 2022-10-19 +date: 2022-10-23 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 5292e58c0faab..6ce1f1da9bdaf 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: 2022-10-19 +date: 2022-10-23 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 d99d222cce727..fe35c81ad0f53 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_analytics_shippers_gainsight.devdocs.json new file mode 100644 index 0000000000000..00e50bd404a3d --- /dev/null +++ b/api_docs/kbn_analytics_shippers_gainsight.devdocs.json @@ -0,0 +1,332 @@ +{ + "id": "@kbn/analytics-shippers-gainsight", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper", + "type": "Class", + "tags": [], + "label": "GainsightShipper", + "description": [ + "\ngainsight shipper." + ], + "signature": [ + { + "pluginId": "@kbn/analytics-shippers-gainsight", + "scope": "common", + "docId": "kibKbnAnalyticsShippersGainsightPluginApi", + "section": "def-common.GainsightShipper", + "text": "GainsightShipper" + }, + " implements ", + "IShipper" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.shipperName", + "type": "string", + "tags": [], + "label": "shipperName", + "description": [ + "Shipper's unique name" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [ + "\nCreates a new instance of the gainsightShipper." + ], + "signature": [ + "any" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [ + "{@link GainsightSnippetConfig }" + ], + "signature": [ + { + "pluginId": "@kbn/analytics-shippers-gainsight", + "scope": "common", + "docId": "kibKbnAnalyticsShippersGainsightPluginApi", + "section": "def-common.GainsightSnippetConfig", + "text": "GainsightSnippetConfig" + } + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "initContext", + "description": [ + "{@link AnalyticsClientInitContext }" + ], + "signature": [ + "AnalyticsClientInitContext" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.extendContext", + "type": "Function", + "tags": [], + "label": "extendContext", + "description": [ + "\nCalls track or set on the fields provided in the newContext." + ], + "signature": [ + "(newContext: ", + "EventContext", + ") => void" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.extendContext.$1", + "type": "Object", + "tags": [], + "label": "newContext", + "description": [ + "The full new context to set {@link EventContext }" + ], + "signature": [ + "EventContext" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nStops/restarts the shipping mechanism based on the value of isOptedIn" + ], + "signature": [ + "(isOptedIn: boolean) => void" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.optIn.$1", + "type": "boolean", + "tags": [], + "label": "isOptedIn", + "description": [ + "`true` for resume sending events. `false` to stop." + ], + "signature": [ + "boolean" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.reportEvents", + "type": "Function", + "tags": [], + "label": "reportEvents", + "description": [ + "\nTransforms the event into a valid format and calls `track`." + ], + "signature": [ + "(events: ", + "Event", + ">[]) => void" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.reportEvents.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [ + "batched events {@link Event }" + ], + "signature": [ + "Event", + ">[]" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightShipper.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nShuts down the shipper.\nIt doesn't really do anything inside because this shipper doesn't hold any internal queues." + ], + "signature": [ + "() => void" + ], + "path": "packages/analytics/shippers/gainsight/src/gainsight_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightSnippetConfig", + "type": "Interface", + "tags": [], + "label": "GainsightSnippetConfig", + "description": [ + "\ngainsight basic configuration." + ], + "path": "packages/analytics/shippers/gainsight/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightSnippetConfig.gainsightOrgId", + "type": "string", + "tags": [], + "label": "gainsightOrgId", + "description": [ + "\nThe gainsight account id." + ], + "path": "packages/analytics/shippers/gainsight/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightSnippetConfig.scriptUrl", + "type": "string", + "tags": [], + "label": "scriptUrl", + "description": [ + "\nThe URL to load the gainsight client from. Falls back to `web-sdk.aptrinsic.com` if not specified." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/shippers/gainsight/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightSnippetConfig.cssFileEndpoint", + "type": "string", + "tags": [], + "label": "cssFileEndpoint", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/shippers/gainsight/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/analytics-shippers-gainsight", + "id": "def-common.GainsightSnippetConfig.widgetFileEndpoint", + "type": "string", + "tags": [], + "label": "widgetFileEndpoint", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/shippers/gainsight/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx new file mode 100644 index 0000000000000..8af719a3f78c9 --- /dev/null +++ b/api_docs/kbn_analytics_shippers_gainsight.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: kibKbnAnalyticsShippersGainsightPluginApi +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: 2022-10-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] +--- +import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 17 | 0 | 2 | 0 | + +## Common + +### Classes + + +### Interfaces + + diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 53522181ad06c..c4ecaca060edd 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: 2022-10-19 +date: 2022-10-23 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 2f19734d7cc45..4d6f8810b78a1 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 249e6168a7326..5ed2c5b178172 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: 2022-10-19 +date: 2022-10-23 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 7e1237f0a78bc..154cd9b596024 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: 2022-10-19 +date: 2022-10-23 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 c6ee29e8451aa..8d6ffd0fad392 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index ac7e69504bdb0..1c18e18a667fc 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: 2022-10-19 +date: 2022-10-23 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 f8b5322c42061..6b181fa7167bd 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: 2022-10-19 +date: 2022-10-23 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 93bed0efb5c2a..628eb692dac71 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: 2022-10-19 +date: 2022-10-23 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 f8f18847a7fb8..a5190feffd7fd 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: 2022-10-19 +date: 2022-10-23 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 cbbe45966ba68..5bd69b54252bc 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index deb7e9f9d9e03..2d6f801d9aa31 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: 2022-10-19 +date: 2022-10-23 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 71b53e7466a50..4de6d11020640 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: 2022-10-19 +date: 2022-10-23 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 5d0a3a134d110..25eec4bc0dabc 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: 2022-10-19 +date: 2022-10-23 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 1c68ce59532d6..7b1075c5f8238 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list.mdx b/api_docs/kbn_content_management_table_list.mdx index b69e4c406d6b8..6acca27629c54 100644 --- a/api_docs/kbn_content_management_table_list.mdx +++ b/api_docs/kbn_content_management_table_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list title: "@kbn/content-management-table-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list'] --- import kbnContentManagementTableListObj from './kbn_content_management_table_list.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index d287ff13c4d2b..a86388b94f81f 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: 2022-10-19 +date: 2022-10-23 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 3165b2bf055a7..ab10efb0c30a4 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: 2022-10-19 +date: 2022-10-23 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 aa9134c962a6e..c3c6eaa526fd3 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: 2022-10-19 +date: 2022-10-23 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 7e474360cce43..2b76480d8f1b4 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: 2022-10-19 +date: 2022-10-23 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 f1bb50f7b521c..54ff26b1c5063 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: 2022-10-19 +date: 2022-10-23 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 40537036a8d26..68fecd703c084 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: 2022-10-19 +date: 2022-10-23 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 c7372c687550f..5329d3993e805 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: 2022-10-19 +date: 2022-10-23 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 1ebf326bff5ab..7d521e4e99385 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: 2022-10-19 +date: 2022-10-23 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 1b8d5fd849764..1a4718d96c005 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: 2022-10-19 +date: 2022-10-23 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 4b61285c56341..bb0411611f3f7 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: 2022-10-19 +date: 2022-10-23 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 54d77d024c0fa..3f139c6fcecc8 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: 2022-10-19 +date: 2022-10-23 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 52c3d1963add5..090001a63414a 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: 2022-10-19 +date: 2022-10-23 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_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index c224fde8a1d47..c86cc78cad051 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: 2022-10-19 +date: 2022-10-23 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 72a1ba60cc5ed..ced70f16befbf 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: 2022-10-19 +date: 2022-10-23 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 aed83272bee3e..1610e09600ec5 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: 2022-10-19 +date: 2022-10-23 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 83f6a1aa6a039..198c2e463bfc7 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: 2022-10-19 +date: 2022-10-23 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 e1846ade17c0b..3a828869dc29b 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: 2022-10-19 +date: 2022-10-23 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 1ce53aa31371d..0eab4b80a7c17 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: 2022-10-19 +date: 2022-10-23 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 b392e538f2c30..3845f1f3adccc 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: 2022-10-19 +date: 2022-10-23 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 77372a00d80f2..eef624b8d78f4 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: 2022-10-19 +date: 2022-10-23 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 ef5f6b75366a0..e6dcd8fb67da8 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: 2022-10-19 +date: 2022-10-23 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 167bf06f71e49..e225ede8cb9bd 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: 2022-10-19 +date: 2022-10-23 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 e269997a9b00f..1996ae3277d8d 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: 2022-10-19 +date: 2022-10-23 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_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index f716a3048b121..251305e37f3f1 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: 2022-10-19 +date: 2022-10-23 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 09e87f10a55d6..7fba6bb3552ce 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: 2022-10-19 +date: 2022-10-23 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 f2b7cf7b5b3c4..5c9020e6607cd 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: 2022-10-19 +date: 2022-10-23 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 198a27325d900..7d7b84e01937d 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: 2022-10-19 +date: 2022-10-23 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 a99670bb7acba..df13908bd8e07 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: 2022-10-19 +date: 2022-10-23 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 55b3ba01161ef..d5973596c9c2b 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: 2022-10-19 +date: 2022-10-23 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 d0caba62acac1..4138188ba93d5 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: 2022-10-19 +date: 2022-10-23 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 cb2df38aece21..a35a3d497a646 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: 2022-10-19 +date: 2022-10-23 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 2e7ae9db62e3a..541d5e8af4bdf 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: 2022-10-19 +date: 2022-10-23 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 2ef1163ae81fb..1dce74af3a09d 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: 2022-10-19 +date: 2022-10-23 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 eb5add0d929ff..e2a780f8e8a28 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: 2022-10-19 +date: 2022-10-23 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 ed19d51e444f6..1966735dd9907 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json index 4a5e46fda1b9f..570636f16f3a8 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json @@ -422,7 +422,7 @@ }, "<", "default", - ">; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -454,17 +454,7 @@ "default", ", [opts: ", "ClientOptions", - "]>; Internal: ", - { - "pluginId": "@kbn/core-elasticsearch-client-server-mocks", - "scope": "server", - "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", - "section": "def-server.DeeplyMockedApi", - "text": "DeeplyMockedApi" - }, - "<", - "default", - ">; autoscaling: ", + "]>; autoscaling: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -1533,7 +1523,7 @@ }, "<", "default", - ">; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -1565,17 +1555,7 @@ "default", ", [opts: ", "ClientOptions", - "]>; Internal: ", - { - "pluginId": "@kbn/core-elasticsearch-client-server-mocks", - "scope": "server", - "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", - "section": "def-server.DeeplyMockedApi", - "text": "DeeplyMockedApi" - }, - "<", - "default", - ">; autoscaling: ", + "]>; autoscaling: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -2598,7 +2578,7 @@ }, "<", "default", - ">; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -2630,17 +2610,7 @@ "default", ", [opts: ", "ClientOptions", - "]>; Internal: ", - { - "pluginId": "@kbn/core-elasticsearch-client-server-mocks", - "scope": "server", - "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", - "section": "def-server.DeeplyMockedApi", - "text": "DeeplyMockedApi" - }, - "<", - "default", - ">; autoscaling: ", + "]>; autoscaling: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -3730,7 +3700,7 @@ }, "<", "default", - ">; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -3762,17 +3732,7 @@ "default", ", [opts: ", "ClientOptions", - "]>; Internal: ", - { - "pluginId": "@kbn/core-elasticsearch-client-server-mocks", - "scope": "server", - "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", - "section": "def-server.DeeplyMockedApi", - "text": "DeeplyMockedApi" - }, - "<", - "default", - ">; autoscaling: ", + "]>; autoscaling: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index aecb2f1930af7..b94b8bada0d51 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_elasticsearch_server.devdocs.json index 6137810e54074..3644958164e4d 100644 --- a/api_docs/kbn_core_elasticsearch_server.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_server.devdocs.json @@ -1080,7 +1080,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -1088,8 +1088,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -2725,7 +2723,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -2733,8 +2731,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -3929,7 +3925,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -3937,8 +3933,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -5380,7 +5374,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -5388,8 +5382,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 0ab654297fa25..bb2bcde70e470 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json index 92b9cc5394746..476751b714f15 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json @@ -218,7 +218,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -226,8 +226,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -1801,7 +1799,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -1809,8 +1807,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 9f41537471ddb..9b5794e3f702d 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: 2022-10-19 +date: 2022-10-23 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 1ee2eeec1b480..add30ae433ea2 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: 2022-10-19 +date: 2022-10-23 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 723e970800918..2ea7552352c90 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: 2022-10-19 +date: 2022-10-23 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 4bf83d8371fbf..3f5da58c5d2eb 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: 2022-10-19 +date: 2022-10-23 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 3674079f3ada2..cae5178a65972 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: 2022-10-19 +date: 2022-10-23 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 7f74ad2005a6b..17619f9d6bfa6 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: 2022-10-19 +date: 2022-10-23 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 ce92ee4570483..aff8a93cdbbe4 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: 2022-10-19 +date: 2022-10-23 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 7a0f272b4b6a3..271e60f4809ba 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: 2022-10-19 +date: 2022-10-23 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 6a247724b89f4..d4b8ded8a9ec7 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: 2022-10-19 +date: 2022-10-23 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 62c7364d3f8f6..76c0184b2c8db 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: 2022-10-19 +date: 2022-10-23 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 3280a31e3d02e..436b7ed0df910 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: 2022-10-19 +date: 2022-10-23 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 c44763c7ef79e..722edaabd1748 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: 2022-10-19 +date: 2022-10-23 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 5237ac859121c..5a394406a4de9 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: 2022-10-19 +date: 2022-10-23 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 ba7813fda48be..a730122f9eb56 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: 2022-10-19 +date: 2022-10-23 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 e607dfc7c31f6..edc9c67806f23 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: 2022-10-19 +date: 2022-10-23 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 d5704737d41ab..c3a4d86490d56 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: 2022-10-19 +date: 2022-10-23 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 ceccb5fb802a7..5e11493ce8694 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: 2022-10-19 +date: 2022-10-23 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 aef04818d7313..c861e9f56c967 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: 2022-10-19 +date: 2022-10-23 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 2e16b8bd248ae..6ea5e9918c02f 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_http_resources_server.devdocs.json index 4a58d5e1ad9ef..bc5b87b070efc 100644 --- a/api_docs/kbn_core_http_resources_server.devdocs.json +++ b/api_docs/kbn_core_http_resources_server.devdocs.json @@ -322,6 +322,44 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderCss", + "type": "Function", + "tags": [], + "label": "renderCss", + "description": [ + "To respond with a custom CSS script file." + ], + "signature": [ + "(options: ", + "HttpResponseOptions", + ") => ", + "IKibanaResponse", + "" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderCss.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "HttpResponseOptions" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 8df0ff2e8eb71..d40c1071cc16a 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 20 | 0 | 6 | 0 | +| 22 | 0 | 7 | 0 | ## Server diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 2606079116a4d..8134adf1f8d9e 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_http_resources_server_mocks.devdocs.json index 619ba47e29df4..edc6ab2842489 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.devdocs.json +++ b/api_docs/kbn_core_http_resources_server_mocks.devdocs.json @@ -179,6 +179,14 @@ "HttpResponseOptions", ") => ", "IKibanaResponse", + "); renderCss: jest.MockInstance<", + "IKibanaResponse", + ", [options: ", + "HttpResponseOptions", + "]> & ((options: ", + "HttpResponseOptions", + ") => ", + "IKibanaResponse", "); ok: jest.MockInstance<", "IKibanaResponse", ", [options?: ", diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index 24879c993505b..73869cb681493 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: 2022-10-19 +date: 2022-10-23 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 aa77355fcd737..96c8a2caaec76 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: 2022-10-19 +date: 2022-10-23 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 d08cc23f204f5..6a6afe3f35b7f 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: 2022-10-19 +date: 2022-10-23 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.mdx b/api_docs/kbn_core_http_server.mdx index d39a8fe599656..8a621936254b6 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_http_server_internal.devdocs.json index e02589c7657c0..1a51d9c4ae675 100644 --- a/api_docs/kbn_core_http_server_internal.devdocs.json +++ b/api_docs/kbn_core_http_server_internal.devdocs.json @@ -759,7 +759,7 @@ "label": "HttpConfigType", "description": [], "signature": [ - "{ readonly basePath?: string | undefined; readonly uuid?: string | undefined; readonly publicBaseUrl?: string | undefined; readonly name: string; readonly host: string; readonly compression: Readonly<{ referrerWhitelist?: string[] | undefined; } & { enabled: boolean; }>; readonly ssl: Readonly<{ key?: string | undefined; certificateAuthorities?: string | string[] | undefined; certificate?: string | undefined; keyPassphrase?: string | undefined; redirectHttpFromPort?: number | undefined; } & { enabled: boolean; keystore: Readonly<{ path?: string | undefined; password?: string | undefined; } & {}>; truststore: Readonly<{ path?: string | undefined; password?: string | undefined; } & {}>; cipherSuites: string[]; supportedProtocols: string[]; clientAuthentication: \"optional\" | \"none\" | \"required\"; }>; readonly port: number; readonly cors: Readonly<{} & { enabled: boolean; allowCredentials: boolean; allowOrigin: string[] | \"*\"[]; }>; readonly autoListen: boolean; readonly shutdownTimeout: moment.Duration; readonly securityResponseHeaders: Readonly<{} & { referrerPolicy: \"origin\" | \"no-referrer\" | \"no-referrer-when-downgrade\" | \"origin-when-cross-origin\" | \"same-origin\" | \"strict-origin\" | \"strict-origin-when-cross-origin\" | \"unsafe-url\" | null; disableEmbedding: boolean; strictTransportSecurity: string | null; xContentTypeOptions: \"nosniff\" | null; permissionsPolicy: string | null; }>; readonly customResponseHeaders: Record; readonly maxPayload: ", + "{ readonly uuid?: string | undefined; readonly basePath?: string | undefined; readonly publicBaseUrl?: string | undefined; readonly name: string; readonly host: string; readonly compression: Readonly<{ referrerWhitelist?: string[] | undefined; } & { enabled: boolean; }>; readonly ssl: Readonly<{ key?: string | undefined; certificateAuthorities?: string | string[] | undefined; certificate?: string | undefined; keyPassphrase?: string | undefined; redirectHttpFromPort?: number | undefined; } & { enabled: boolean; keystore: Readonly<{ path?: string | undefined; password?: string | undefined; } & {}>; truststore: Readonly<{ path?: string | undefined; password?: string | undefined; } & {}>; cipherSuites: string[]; supportedProtocols: string[]; clientAuthentication: \"optional\" | \"none\" | \"required\"; }>; readonly port: number; readonly cors: Readonly<{} & { enabled: boolean; allowCredentials: boolean; allowOrigin: string[] | \"*\"[]; }>; readonly autoListen: boolean; readonly shutdownTimeout: moment.Duration; readonly securityResponseHeaders: Readonly<{} & { referrerPolicy: \"origin\" | \"no-referrer\" | \"no-referrer-when-downgrade\" | \"origin-when-cross-origin\" | \"same-origin\" | \"strict-origin\" | \"strict-origin-when-cross-origin\" | \"unsafe-url\" | null; disableEmbedding: boolean; strictTransportSecurity: string | null; xContentTypeOptions: \"nosniff\" | null; permissionsPolicy: string | null; }>; readonly customResponseHeaders: Record; readonly maxPayload: ", "ByteSizeValue", "; readonly rewriteBasePath: boolean; readonly keepaliveTimeout: number; readonly socketTimeout: number; readonly xsrf: Readonly<{} & { disableProtection: boolean; allowlist: string[]; }>; readonly requestId: Readonly<{} & { allowFromAnyIp: boolean; ipAllowlist: string[]; }>; }" ], diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 98f14a7aae328..037bc07e87c2e 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: 2022-10-19 +date: 2022-10-23 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 5ac42cd531318..d4967d82bba6f 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: 2022-10-19 +date: 2022-10-23 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 90da98f3c39a4..e9543644c45df 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: 2022-10-19 +date: 2022-10-23 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 d7652774d0efb..5611c65cb3a3f 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: 2022-10-19 +date: 2022-10-23 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 fbb61172cad82..f4005c5ea6298 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: 2022-10-19 +date: 2022-10-23 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 9ac4a9cef0bd1..95a972052fc16 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: 2022-10-19 +date: 2022-10-23 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 141c21baa6893..8f3eaffefc8cb 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: 2022-10-19 +date: 2022-10-23 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.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index 0f878fc9c5543..b3494c6cc0416 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] --- import kbnCoreInjectedMetadataBrowserObj from './kbn_core_injected_metadata_browser.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 7dce99eff047a..6ea2d54b7e527 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: 2022-10-19 +date: 2022-10-23 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 3e4abe8339744..f6ad332885339 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: 2022-10-19 +date: 2022-10-23 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 f5550a93b8094..84c161c14d8b8 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: 2022-10-19 +date: 2022-10-23 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 010ee2febc050..4917033f15bb3 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: 2022-10-19 +date: 2022-10-23 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 8d265117a7f83..a0adbaa57dfe7 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: 2022-10-19 +date: 2022-10-23 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_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 2c89ee1213bef..4e21ef3ae26f6 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: 2022-10-19 +date: 2022-10-23 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 d0558ebffb316..7a3a49d8ad49b 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: 2022-10-19 +date: 2022-10-23 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 7988b50a8373d..badcf42a4aaef 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: 2022-10-19 +date: 2022-10-23 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 88e7af31d8d7e..e5b26e754d06b 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: 2022-10-19 +date: 2022-10-23 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 6fbb17814747b..2091f01af9b71 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: 2022-10-19 +date: 2022-10-23 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 27bd73d3a119e..cecfb4ef4f35b 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: 2022-10-19 +date: 2022-10-23 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 f34820450742b..c92d919b033f5 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: 2022-10-19 +date: 2022-10-23 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 573bc1c2860f2..b61aedf77734e 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: 2022-10-19 +date: 2022-10-23 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 bc2dfbf365a3c..d1cdd7e4ca9a3 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: 2022-10-19 +date: 2022-10-23 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 1aabf851c14f0..ad2bed676ccf9 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: 2022-10-19 +date: 2022-10-23 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 6a04383e2dcb8..7324433eeb530 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: 2022-10-19 +date: 2022-10-23 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 73ee3e0156fb8..53c4370eb4a69 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: 2022-10-19 +date: 2022-10-23 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 2fdfdf4848d8f..22a69098a694a 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: 2022-10-19 +date: 2022-10-23 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 b887670bc094b..871ba8e036712 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: 2022-10-19 +date: 2022-10-23 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 192b6e77b8479..4275c4bca04c2 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: 2022-10-19 +date: 2022-10-23 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 9b0cc95c75628..4da5cb0a7cf31 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: 2022-10-19 +date: 2022-10-23 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 296f01d072d81..22e60f439725e 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: 2022-10-19 +date: 2022-10-23 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 ed4ef67d79aee..921e335011718 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: 2022-10-19 +date: 2022-10-23 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 38b7bc07954b5..d9b3dc02964b8 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: 2022-10-19 +date: 2022-10-23 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 9a769b14e84e4..8ff9e605f0bb1 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: 2022-10-19 +date: 2022-10-23 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_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 5e129bd957f52..bda79458784f8 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: 2022-10-19 +date: 2022-10-23 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 7297dd5e70c6d..18fedbd4b70d9 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: 2022-10-19 +date: 2022-10-23 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 570e7de0a2ed4..d36d98d0b1b15 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: 2022-10-19 +date: 2022-10-23 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 e0cd1169a557d..78560b09f5dbe 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: 2022-10-19 +date: 2022-10-23 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 4aaa8ffb9701f..d862251f20c7f 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: 2022-10-19 +date: 2022-10-23 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_saved_objects_api_browser.devdocs.json b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json index 19434ae87b701..06e843f3cd6f5 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json @@ -1793,6 +1793,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-saved-objects-api-browser", + "id": "def-common.SimpleSavedObject.createdAt", + "type": "string", + "tags": [], + "label": "createdAt", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-api-browser/src/simple_saved_object.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-saved-objects-api-browser", "id": "def-common.SimpleSavedObject.namespaces", diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 68c0e3435be07..e83091436da20 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 106 | 1 | 75 | 0 | +| 107 | 1 | 76 | 0 | ## Common diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index aff7fb24ae9c2..4178827611d98 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: 2022-10-19 +date: 2022-10-23 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_internal.mdx b/api_docs/kbn_core_saved_objects_api_server_internal.mdx index 91aba7a48a6a4..21fb41eda3f41 100644 --- a/api_docs/kbn_core_saved_objects_api_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-internal title: "@kbn/core-saved-objects-api-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-internal plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-internal'] --- import kbnCoreSavedObjectsApiServerInternalObj from './kbn_core_saved_objects_api_server_internal.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 01c549ef1fc54..a7fcb7ba1d349 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: 2022-10-19 +date: 2022-10-23 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 e6da451b8c0e5..aeb9ee202eb91 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: 2022-10-19 +date: 2022-10-23 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 e001d6d4d3aea..e89c7a7bc54c3 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: 2022-10-19 +date: 2022-10-23 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 a84497aa2a947..ff6e41e4bd0e6 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: 2022-10-19 +date: 2022-10-23 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 24315a85ff013..90174d84a3b8a 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: 2022-10-19 +date: 2022-10-23 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 ad524286dd1f5..1220d3c63e5d2 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_saved_objects_common.devdocs.json index 78a36566609fa..4a004f5e967eb 100644 --- a/api_docs/kbn_core_saved_objects_common.devdocs.json +++ b/api_docs/kbn_core_saved_objects_common.devdocs.json @@ -83,6 +83,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-saved-objects-common", + "id": "def-common.SavedObject.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [ + "Timestamp of the time this document had been created." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-common/src/saved_objects.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-saved-objects-common", "id": "def-common.SavedObject.updated_at", diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index 812e98ea0dae5..8aa6ad15fdef3 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 82 | 0 | 41 | 0 | +| 83 | 0 | 41 | 0 | ## Common 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 9740ce7e72225..bbf8a08c28f98 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: 2022-10-19 +date: 2022-10-23 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 e95bb69c5c768..291b70ea8e892 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_saved_objects_migration_server_internal.devdocs.json index ac1eddca54b9b..529f203e49b32 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.devdocs.json +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.devdocs.json @@ -1929,7 +1929,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -1937,8 +1937,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", 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 eb0d58c39ede4..84d9c84cec49b 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: 2022-10-19 +date: 2022-10-23 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 e5807392eee39..51c590d75d0b8 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index f21f0a648a391..29e8376dafd9b 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -2193,6 +2193,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-saved-objects-server", + "id": "def-server.SavedObjectsRawDocSource.created_at", + "type": "string", + "tags": [], + "label": "created_at", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-server/src/serialization.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-saved-objects-server", "id": "def-server.SavedObjectsRawDocSource.references", diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index cec3eb8483dee..fc4db5442adc4 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 225 | 0 | 82 | 0 | +| 226 | 0 | 83 | 0 | ## Server diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 1bc69d6867b66..905b3e3dd6532 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: 2022-10-19 +date: 2022-10-23 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 f2ef0225efd10..eb84afd9322b1 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: 2022-10-19 +date: 2022-10-23 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 34cac905c6f5f..1e8acb5d82c46 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: 2022-10-19 +date: 2022-10-23 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 d58cbd5067912..cb19b03c9d220 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: 2022-10-19 +date: 2022-10-23 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 58b26c4eb32a1..272518ea8b0cf 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: 2022-10-19 +date: 2022-10-23 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 cbfc58c6addfa..235af6e66190b 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: 2022-10-19 +date: 2022-10-23 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 302d900f01e54..0e6e5dc28b607 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: 2022-10-19 +date: 2022-10-23 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 04a198c493595..07f20d8ba29e4 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: 2022-10-19 +date: 2022-10-23 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 31f557a753c97..e7e752d2f3eb4 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: 2022-10-19 +date: 2022-10-23 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 41b313451b622..32f0d691ab69a 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: 2022-10-19 +date: 2022-10-23 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_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 0ca58532b818c..35130c191f620 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: 2022-10-19 +date: 2022-10-23 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 0efb87ccfa287..f99dd071dac1a 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: 2022-10-19 +date: 2022-10-23 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 1592699b1dcfa..3cd504f7cdf34 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: 2022-10-19 +date: 2022-10-23 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_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index feff717532fd0..555971a74a31d 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 67ef54f880520..356a6411d66bc 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: 2022-10-19 +date: 2022-10-23 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 b3f69547feadf..501aeb79aba6d 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: 2022-10-19 +date: 2022-10-23 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 fb23742c028f8..129f6e157c650 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: 2022-10-19 +date: 2022-10-23 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 77a21d6040db2..64165075d37ff 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: 2022-10-19 +date: 2022-10-23 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 1d767679c1045..0c43aedb0f800 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: 2022-10-19 +date: 2022-10-23 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 f32f35c9e9f91..9713c10e2a647 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: 2022-10-19 +date: 2022-10-23 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 a2a4ff4f6d44f..bf67f29659d5f 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: 2022-10-19 +date: 2022-10-23 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 a952a5e1276e7..bc2a39050a17d 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: 2022-10-19 +date: 2022-10-23 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 7fe4495d0c7a8..6f2a30142e4f5 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: 2022-10-19 +date: 2022-10-23 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 b39c4fc9a28da..4718e88a46fbb 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: 2022-10-19 +date: 2022-10-23 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 e03a1479da813..0f7af5e1f783a 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: 2022-10-19 +date: 2022-10-23 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_crypto.mdx b/api_docs/kbn_crypto.mdx index 48d9f7e8710f5..1c3991c26a688 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: 2022-10-19 +date: 2022-10-23 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 0eabc61560ac8..1a266584601bf 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 1d61adfc1d92d..dd5edcb659788 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index d74db9f65684b..0b9ef7f9ebfc9 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: 2022-10-19 +date: 2022-10-23 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 48f7d4a529932..95cdcd4ef501c 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: 2022-10-19 +date: 2022-10-23 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 96b29624feccf..02fa5adcc1982 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: 2022-10-19 +date: 2022-10-23 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 d190eba974a30..26b4292405ca4 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index e656d78a1fef4..a12b3ae2f8792 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -300,7 +300,7 @@ "label": "enterpriseSearch", "description": [], "signature": [ - "{ readonly apiKeys: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsWorkplaceSearch: string; readonly crawlerGettingStarted: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly ingestPipelines: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly mailService: string; readonly start: string; readonly troubleshootSetup: string; readonly usersAccess: string; }" + "{ readonly apiKeys: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsWorkplaceSearch: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly ingestPipelines: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly mailService: string; readonly start: string; readonly troubleshootSetup: string; readonly usersAccess: 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 f2a8619d4e1d3..3310697d9d7d2 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: 2022-10-19 +date: 2022-10-23 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 7c2554660baa5..97a0cbd1202cf 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index d53ecf0d7c414..8333cb30f7e2e 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 72bf3531e4574..21029365ce66d 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: 2022-10-19 +date: 2022-10-23 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 4f0825b0f9eaf..c7236dcd055f0 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: 2022-10-19 +date: 2022-10-23 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 72f8ca7e624d2..0b33f863b20d5 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.devdocs.json b/api_docs/kbn_es_types.devdocs.json index df40e62edf33b..94d8ad37de02f 100644 --- a/api_docs/kbn_es_types.devdocs.json +++ b/api_docs/kbn_es_types.devdocs.json @@ -292,47 +292,9 @@ "AggregationsAggregate", ">>, \"hits\" | \"aggregations\"> & (TSearchRequest[\"body\"] extends TopLevelAggregationRequest ? WrapAggregationResponse> : TSearchRequest extends TopLevelAggregationRequest ? WrapAggregationResponse> : { aggregations?: unknown; }) & { hits: Omit<", "SearchHitsMetadata", - ", \"hits\" | \"total\"> & (TOptions[\"restTotalHitsAsInt\"] extends true ? { total: number; } : { total: { value: number; relation: \"gte\" | \"eq\"; }; }) & { hits: HitsOf | undefined; aggs?: Record | undefined; collapse?: ", - "SearchFieldCollapse", - " | undefined; explain?: boolean | undefined; from?: number | undefined; highlight?: ", - "SearchHighlight", - " | undefined; track_total_hits?: ", - "SearchTrackHits", - " | undefined; indices_boost?: Record[] | undefined; docvalue_fields?: (string | ", - "QueryDslFieldAndFormat", - ")[] | undefined; min_score?: number | undefined; post_filter?: ", - "QueryDslQueryContainer", - " | undefined; profile?: boolean | undefined; query?: ", - "QueryDslQueryContainer", - " | undefined; rescore?: ", - "SearchRescore", - " | ", - "SearchRescore", - "[] | undefined; script_fields?: Record | undefined; search_after?: ", - "SortResults", - " | undefined; size?: number | undefined; slice?: ", - "SlicedScroll", - " | undefined; sort?: ", - "Sort", - " | undefined; _source?: ", - "SearchSourceConfig", - " | undefined; fields?: (string | ", - "QueryDslFieldAndFormat", - ")[] | undefined; suggest?: ", - "SearchSuggester", - " | undefined; terminate_after?: number | undefined; timeout?: string | undefined; track_scores?: boolean | undefined; version?: boolean | undefined; seq_no_primary_term?: boolean | undefined; stored_fields?: ", - "Fields", - " | undefined; pit?: ", - "SearchPointInTimeReference", - " | undefined; runtime_mappings?: ", - "MappingRuntimeFields", - " | undefined; stats?: string[] | undefined; } | undefined ? TSearchRequest[\"body\"] : TSearchRequest, TDocument>; }; }" + ", \"hits\" | \"total\"> & (TOptions[\"restTotalHitsAsInt\"] extends true ? { total: number; } : { total: { value: number; relation: \"gte\" | \"eq\"; }; }) & { hits: HitsOf; }; }" ], "path": "packages/kbn-es-types/src/index.ts", "deprecated": false, @@ -368,47 +330,9 @@ "AggregationsAggregate", ">>, \"hits\" | \"aggregations\"> & (TSearchRequest[\"body\"] extends TopLevelAggregationRequest ? WrapAggregationResponse> : TSearchRequest extends TopLevelAggregationRequest ? WrapAggregationResponse> : { aggregations?: unknown; }) & { hits: Omit<", "SearchHitsMetadata", - ", \"hits\" | \"total\"> & (TOptions[\"restTotalHitsAsInt\"] extends true ? { total: number; } : { total: { value: number; relation: \"gte\" | \"eq\"; }; }) & { hits: HitsOf | undefined; aggs?: Record | undefined; collapse?: ", - "SearchFieldCollapse", - " | undefined; explain?: boolean | undefined; from?: number | undefined; highlight?: ", - "SearchHighlight", - " | undefined; track_total_hits?: ", - "SearchTrackHits", - " | undefined; indices_boost?: Record[] | undefined; docvalue_fields?: (string | ", - "QueryDslFieldAndFormat", - ")[] | undefined; min_score?: number | undefined; post_filter?: ", - "QueryDslQueryContainer", - " | undefined; profile?: boolean | undefined; query?: ", - "QueryDslQueryContainer", - " | undefined; rescore?: ", - "SearchRescore", - " | ", - "SearchRescore", - "[] | undefined; script_fields?: Record | undefined; search_after?: ", - "SortResults", - " | undefined; size?: number | undefined; slice?: ", - "SlicedScroll", - " | undefined; sort?: ", - "Sort", - " | undefined; _source?: ", - "SearchSourceConfig", - " | undefined; fields?: (string | ", - "QueryDslFieldAndFormat", - ")[] | undefined; suggest?: ", - "SearchSuggester", - " | undefined; terminate_after?: number | undefined; timeout?: string | undefined; track_scores?: boolean | undefined; version?: boolean | undefined; seq_no_primary_term?: boolean | undefined; stored_fields?: ", - "Fields", - " | undefined; pit?: ", - "SearchPointInTimeReference", - " | undefined; runtime_mappings?: ", - "MappingRuntimeFields", - " | undefined; stats?: string[] | undefined; } | undefined ? TSearchRequest[\"body\"] : TSearchRequest, TDocument>; }; }" + ", \"hits\" | \"total\"> & (TOptions[\"restTotalHitsAsInt\"] extends true ? { total: number; } : { total: { value: number; relation: \"gte\" | \"eq\"; }; }) & { hits: HitsOf; }; }" ], "path": "packages/kbn-es-types/src/search.ts", "deprecated": false, diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index d83647acc82f3..af2e7886768d9 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: 2022-10-19 +date: 2022-10-23 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 0b44cb06a63f5..c58c4ef057c2e 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 02c58def164f9..2bf10cb528b0c 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index ef5ceda0e10f0..58d2480ae3474 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: 2022-10-19 +date: 2022-10-23 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 3282e037cb441..64b1d4a42b219 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: 2022-10-19 +date: 2022-10-23 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 7ed6054459246..929fa45b3350c 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_get_repo_files.mdx b/api_docs/kbn_get_repo_files.mdx index 17354fa51739b..4aae7cd9f599e 100644 --- a/api_docs/kbn_get_repo_files.mdx +++ b/api_docs/kbn_get_repo_files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-get-repo-files title: "@kbn/get-repo-files" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/get-repo-files plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/get-repo-files'] --- import kbnGetRepoFilesObj from './kbn_get_repo_files.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.devdocs.json b/api_docs/kbn_guided_onboarding.devdocs.json new file mode 100644 index 0000000000000..01294a25e7450 --- /dev/null +++ b/api_docs/kbn_guided_onboarding.devdocs.json @@ -0,0 +1,292 @@ +{ + "id": "@kbn/guided-onboarding", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideCard", + "type": "Function", + "tags": [], + "label": "GuideCard", + "description": [], + "signature": [ + "({ useCase, guides, activateGuide, isDarkTheme, addBasePath, }: ", + "GuideCardProps", + ") => JSX.Element" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/guide_card.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideCard.$1", + "type": "Object", + "tags": [], + "label": "{\n useCase,\n guides,\n activateGuide,\n isDarkTheme,\n addBasePath,\n}", + "description": [], + "signature": [ + "GuideCardProps" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/guide_card.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard", + "type": "Function", + "tags": [], + "label": "ObservabilityLinkCard", + "description": [], + "signature": [ + "({ navigateToApp, isDarkTheme, addBasePath, }: { navigateToApp: (appId: string, options?: ", + "NavigateToAppOptions", + " | undefined) => Promise; isDarkTheme: boolean; addBasePath: (url: string) => string; }) => JSX.Element" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard.$1", + "type": "Object", + "tags": [], + "label": "{\n navigateToApp,\n isDarkTheme,\n addBasePath,\n}", + "description": [], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard.$1.navigateToApp", + "type": "Function", + "tags": [], + "label": "navigateToApp", + "description": [], + "signature": [ + "(appId: string, options?: ", + "NavigateToAppOptions", + " | undefined) => Promise" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard.$1.navigateToApp.$1", + "type": "string", + "tags": [], + "label": "appId", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard.$1.navigateToApp.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "NavigateToAppOptions", + " | undefined" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard.$1.isDarkTheme", + "type": "boolean", + "tags": [], + "label": "isDarkTheme", + "description": [], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard.$1.addBasePath", + "type": "Function", + "tags": [], + "label": "addBasePath", + "description": [], + "signature": [ + "(url: string) => string" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.ObservabilityLinkCard.$1.addBasePath.$1", + "type": "string", + "tags": [], + "label": "url", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideState", + "type": "Interface", + "tags": [], + "label": "GuideState", + "description": [], + "path": "packages/kbn-guided-onboarding/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideState.guideId", + "type": "CompoundType", + "tags": [], + "label": "guideId", + "description": [], + "signature": [ + "\"search\" | \"security\" | \"observability\"" + ], + "path": "packages/kbn-guided-onboarding/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideState.status", + "type": "CompoundType", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "\"complete\" | \"not_started\" | \"in_progress\" | \"ready_to_complete\"" + ], + "path": "packages/kbn-guided-onboarding/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideState.isActive", + "type": "CompoundType", + "tags": [], + "label": "isActive", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-guided-onboarding/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideState.steps", + "type": "Array", + "tags": [], + "label": "steps", + "description": [], + "signature": [ + "GuideStep", + "[]" + ], + "path": "packages/kbn-guided-onboarding/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.GuideId", + "type": "Type", + "tags": [], + "label": "GuideId", + "description": [], + "signature": [ + "\"search\" | \"security\" | \"observability\"" + ], + "path": "packages/kbn-guided-onboarding/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/guided-onboarding", + "id": "def-common.UseCase", + "type": "Type", + "tags": [], + "label": "UseCase", + "description": [], + "signature": [ + "\"search\" | \"security\" | \"observability\"" + ], + "path": "packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx new file mode 100644 index 0000000000000..0e00199761dde --- /dev/null +++ b/api_docs/kbn_guided_onboarding.mdx @@ -0,0 +1,36 @@ +--- +#### +#### 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: kibKbnGuidedOnboardingPluginApi +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: 2022-10-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] +--- +import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 17 | 0 | 17 | 2 | + +## Common + +### Functions + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 60af26b7cafc6..99dbd93d01a1a 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: 2022-10-19 +date: 2022-10-23 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 8ef4509886a45..cdb10f26c15a0 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index cdefddc22dcb6..e06fff48d7914 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: 2022-10-19 +date: 2022-10-23 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 d7ece579939db..b69af46fcc2cb 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: 2022-10-19 +date: 2022-10-23 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 8bfa2939f8330..33fa4fd6c4dbc 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 411d75254001a..a4ab6d852c627 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index d76738b31b35e..89d9eb0104a34 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: 2022-10-19 +date: 2022-10-23 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 663af9ee4f3f7..0a65404edf7c0 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: 2022-10-19 +date: 2022-10-23 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 10f7039618cd0..b83598f8b24a4 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: 2022-10-19 +date: 2022-10-23 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 a90eafafd372a..309e5533477f4 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index fbcf7a0ae1c96..418631402edb0 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_language_documentation_popover.devdocs.json new file mode 100644 index 0000000000000..efc5a267ed84c --- /dev/null +++ b/api_docs/kbn_language_documentation_popover.devdocs.json @@ -0,0 +1,135 @@ +{ + "id": "@kbn/language-documentation-popover", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/language-documentation-popover", + "id": "def-common.LanguageDocumentationPopover", + "type": "Function", + "tags": [], + "label": "LanguageDocumentationPopover", + "description": [], + "signature": [ + "React.NamedExoticComponent & { readonly type: ({ language, sections, buttonProps }: DocumentationPopoverProps) => JSX.Element; }" + ], + "path": "packages/kbn-language-documentation-popover/src/components/documentation_popover.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/language-documentation-popover", + "id": "def-common.LanguageDocumentationPopover.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/language-documentation-popover", + "id": "def-common.LanguageDocumentationPopoverContent", + "type": "Function", + "tags": [], + "label": "LanguageDocumentationPopoverContent", + "description": [], + "signature": [ + "React.NamedExoticComponent & { readonly type: ({ language, sections }: DocumentationProps) => JSX.Element; }" + ], + "path": "packages/kbn-language-documentation-popover/src/components/documentation_content.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/language-documentation-popover", + "id": "def-common.LanguageDocumentationPopoverContent.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/language-documentation-popover", + "id": "def-common.LanguageDocumentationSections", + "type": "Interface", + "tags": [], + "label": "LanguageDocumentationSections", + "description": [], + "path": "packages/kbn-language-documentation-popover/src/components/documentation_content.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/language-documentation-popover", + "id": "def-common.LanguageDocumentationSections.groups", + "type": "Array", + "tags": [], + "label": "groups", + "description": [], + "signature": [ + "{ label: string; description?: string | undefined; items: { label: string; description?: JSX.Element | undefined; }[]; }[]" + ], + "path": "packages/kbn-language-documentation-popover/src/components/documentation_content.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/language-documentation-popover", + "id": "def-common.LanguageDocumentationSections.initialSection", + "type": "Object", + "tags": [], + "label": "initialSection", + "description": [], + "signature": [ + "JSX.Element" + ], + "path": "packages/kbn-language-documentation-popover/src/components/documentation_content.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx new file mode 100644 index 0000000000000..7022a9561cb04 --- /dev/null +++ b/api_docs/kbn_language_documentation_popover.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: kibKbnLanguageDocumentationPopoverPluginApi +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: 2022-10-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] +--- +import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 7 | 0 | 5 | 0 | + +## Common + +### Functions + + +### Interfaces + + diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 87f6c762cb9af..6819c8b1697d6 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: 2022-10-19 +date: 2022-10-23 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 1c47e669332bc..178219ecd85f4 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: 2022-10-19 +date: 2022-10-23 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 2e04ffe2ada6d..9ce939b89f9b5 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index e359f75f5271c..90ed2bdbe939c 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index e7cb9e3fd461b..c5307d222ef54 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: 2022-10-19 +date: 2022-10-23 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_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 3eec00e875f44..c27f6f4365ec9 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: 2022-10-19 +date: 2022-10-23 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_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 4159474a42a6a..e79870c548763 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 82e083fffc925..f5e731173e0a1 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 4de513521b1b7..738cc5ac09478 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: 2022-10-19 +date: 2022-10-23 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 1b75432a979fc..c8a7e2bf41ada 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: 2022-10-19 +date: 2022-10-23 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 513dc087675e5..ba446e5b98a3d 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: 2022-10-19 +date: 2022-10-23 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 c2caeae1d5f4d..16e0a566fdd72 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: 2022-10-19 +date: 2022-10-23 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 5b8bbd4c9f96f..889df7551df37 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: 2022-10-19 +date: 2022-10-23 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 72e81c75890fa..5e9ecf01d42da 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 531eaad449333..4277b7814e85e 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 96c9cbef7924b..fadbbad0bc068 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.devdocs.json b/api_docs/kbn_rule_data_utils.devdocs.json index adb2f74e16015..bde52540e8d2c 100644 --- a/api_docs/kbn_rule_data_utils.devdocs.json +++ b/api_docs/kbn_rule_data_utils.devdocs.json @@ -957,7 +957,7 @@ "label": "AlertStatus", "description": [], "signature": [ - "\"active\" | \"recovered\"" + "\"recovered\" | \"active\"" ], "path": "packages/kbn-rule-data-utils/src/alerts_as_data_status.ts", "deprecated": false, diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 1bcf5c3171b12..0976cbdd71f23 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.devdocs.json b/api_docs/kbn_securitysolution_autocomplete.devdocs.json index f73900b7cb0b0..7623b6034551c 100644 --- a/api_docs/kbn_securitysolution_autocomplete.devdocs.json +++ b/api_docs/kbn_securitysolution_autocomplete.devdocs.json @@ -288,7 +288,7 @@ "label": "FieldComponent", "description": [], "signature": [ - "{ ({ fieldInputWidth, fieldTypeFilter, indexPattern, isClearable, isDisabled, isLoading, isRequired, onChange, placeholder, selectedField, }: React.PropsWithChildren<", + "{ ({ fieldInputWidth, fieldTypeFilter, indexPattern, isClearable, isDisabled, isLoading, isRequired, onChange, placeholder, selectedField, acceptsCustomOptions, }: React.PropsWithChildren<", "FieldProps", ">): JSX.Element; displayName: string | undefined; }" ], @@ -301,7 +301,7 @@ "id": "def-common.FieldComponent.$1", "type": "CompoundType", "tags": [], - "label": "{\n fieldInputWidth,\n fieldTypeFilter = [],\n indexPattern,\n isClearable = false,\n isDisabled = false,\n isLoading = false,\n isRequired = false,\n onChange,\n placeholder,\n selectedField,\n}", + "label": "{\n fieldInputWidth,\n fieldTypeFilter = [],\n indexPattern,\n isClearable = false,\n isDisabled = false,\n isLoading = false,\n isRequired = false,\n onChange,\n placeholder,\n selectedField,\n acceptsCustomOptions = false,\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -788,7 +788,7 @@ "label": "smallLists", "description": [], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]" + "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]" ], "path": "packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx", "deprecated": false, @@ -802,7 +802,7 @@ "label": "largeLists", "description": [], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]" + "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]" ], "path": "packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index a314665ab488c..7a00dbf487538 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.devdocs.json b/api_docs/kbn_securitysolution_es_utils.devdocs.json index e209c3759d537..6526068d5322c 100644 --- a/api_docs/kbn_securitysolution_es_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_es_utils.devdocs.json @@ -633,12 +633,10 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -1879,12 +1877,10 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index b8906a2472d28..4fb80969bbb21 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.devdocs.json b/api_docs/kbn_securitysolution_exception_list_components.devdocs.json index 97b711804af12..ed2e9262906b9 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.devdocs.json +++ b/api_docs/kbn_securitysolution_exception_list_components.devdocs.json @@ -29,7 +29,7 @@ "signature": [ "React.NamedExoticComponent" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -109,7 +109,7 @@ }, ">" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -143,7 +143,7 @@ "CriteriaConditionsProps", ">" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -183,7 +183,7 @@ }, ">" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -223,7 +223,7 @@ }, ">" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -255,7 +255,7 @@ "signature": [ "React.NamedExoticComponent" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -277,6 +277,70 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.ExceptionListHeader", + "type": "Function", + "tags": [], + "label": "ExceptionListHeader", + "description": [], + "signature": [ + "React.NamedExoticComponent" + ], + "path": "packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.ExceptionListHeader.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.HeaderMenu", + "type": "Function", + "tags": [], + "label": "HeaderMenu", + "description": [], + "signature": [ + "React.NamedExoticComponent" + ], + "path": "packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.HeaderMenu.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/securitysolution-exception-list-components", "id": "def-common.Pagination", @@ -327,7 +391,7 @@ "signature": [ "React.NamedExoticComponent" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -391,7 +455,7 @@ "tags": [], "label": "ExceptionItemCardCommentsProps", "description": [], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx", "deprecated": false, "trackAdoption": false, "children": [ @@ -406,7 +470,21 @@ "EuiCommentProps", "[]" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.ExceptionItemCardCommentsProps.dataTestSubj", + "type": "string", + "tags": [], + "label": "dataTestSubj", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx", "deprecated": false, "trackAdoption": false } @@ -420,7 +498,7 @@ "tags": [], "label": "ExceptionItemCardHeaderProps", "description": [], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx", "deprecated": false, "trackAdoption": false, "children": [ @@ -432,9 +510,9 @@ "label": "item", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx", "deprecated": false, "trackAdoption": false }, @@ -448,7 +526,7 @@ "signature": [ "{ key: string; icon: string; label: string | boolean; onClick: () => void; }[]" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx", "deprecated": false, "trackAdoption": false }, @@ -462,7 +540,7 @@ "signature": [ "boolean | undefined" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx", "deprecated": false, "trackAdoption": false }, @@ -473,7 +551,7 @@ "tags": [], "label": "dataTestSubj", "description": [], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx", "deprecated": false, "trackAdoption": false } @@ -487,7 +565,7 @@ "tags": [], "label": "ExceptionItemCardMetaInfoProps", "description": [], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, "trackAdoption": false, "children": [ @@ -499,30 +577,30 @@ "label": "item", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/securitysolution-exception-list-components", - "id": "def-common.ExceptionItemCardMetaInfoProps.references", + "id": "def-common.ExceptionItemCardMetaInfoProps.rules", "type": "Array", "tags": [], - "label": "references", + "label": "rules", "description": [], "signature": [ { "pluginId": "@kbn/securitysolution-exception-list-components", "scope": "common", "docId": "kibKbnSecuritysolutionExceptionListComponentsPluginApi", - "section": "def-common.RuleReference", - "text": "RuleReference" + "section": "def-common.Rule", + "text": "Rule" }, "[]" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, "trackAdoption": false }, @@ -533,7 +611,7 @@ "tags": [], "label": "dataTestSubj", "description": [], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, "trackAdoption": false }, @@ -545,9 +623,9 @@ "label": "formattedDateComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"source\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"input\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"source\" | \"input\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, "trackAdoption": false }, @@ -559,9 +637,9 @@ "label": "securityLinkAnchorComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"source\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"input\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"source\" | \"input\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" ], - "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx", + "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, "trackAdoption": false } @@ -615,7 +693,7 @@ "label": "exceptionItem", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -643,7 +721,14 @@ "label": "ruleReferences", "description": [], "signature": [ - "any[]" + { + "pluginId": "@kbn/securitysolution-exception-list-components", + "scope": "common", + "docId": "kibKbnSecuritysolutionExceptionListComponentsPluginApi", + "section": "def-common.Rule", + "text": "Rule" + }, + "[]" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -685,7 +770,7 @@ "label": "securityLinkAnchorComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"source\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"input\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"source\" | \"input\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -699,7 +784,7 @@ "label": "formattedDateComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"source\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"input\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | React.ComponentType | \"body\" | \"path\" | \"circle\" | \"filter\" | \"data\" | \"line\" | \"area\" | \"time\" | \"label\" | \"legend\" | \"image\" | \"link\" | \"menu\" | \"stop\" | \"base\" | \"text\" | \"title\" | \"s\" | \"small\" | \"source\" | \"input\" | \"svg\" | \"meta\" | \"script\" | \"summary\" | \"desc\" | \"q\" | \"pattern\" | \"mask\" | \"slot\" | \"style\" | \"head\" | \"section\" | \"big\" | \"sub\" | \"sup\" | \"animate\" | \"progress\" | \"view\" | \"output\" | \"var\" | \"map\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"form\" | \"main\" | \"abbr\" | \"address\" | \"article\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"canvas\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"p\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"select\" | \"span\" | \"strong\" | \"table\" | \"template\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -793,7 +878,7 @@ "label": "onEditException", "description": [], "signature": [ - "(item: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => void" + "(item: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => void" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -807,7 +892,7 @@ "label": "item", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -969,6 +1054,45 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.ListDetails", + "type": "Interface", + "tags": [], + "label": "ListDetails", + "description": [], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.ListDetails.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.ListDetails.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/securitysolution-exception-list-components", "id": "def-common.PaginationProps", @@ -1071,6 +1195,67 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.Rule", + "type": "Interface", + "tags": [], + "label": "Rule", + "description": [], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.Rule.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.Rule.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.Rule.rule_id", + "type": "string", + "tags": [], + "label": "rule_id", + "description": [], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/securitysolution-exception-list-components", + "id": "def-common.Rule.exception_lists", + "type": "Array", + "tags": [], + "label": "exception_lists", + "description": [], + "signature": [ + "{ id: string; list_id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; namespace_type: \"single\" | \"agnostic\"; }[]" + ], + "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/securitysolution-exception-list-components", "id": "def-common.RuleReference", @@ -1106,24 +1291,34 @@ }, { "parentPluginId": "@kbn/securitysolution-exception-list-components", - "id": "def-common.RuleReference.ruleId", - "type": "string", + "id": "def-common.RuleReference.referenced_rules", + "type": "Array", "tags": [], - "label": "ruleId", + "label": "referenced_rules", "description": [], + "signature": [ + { + "pluginId": "@kbn/securitysolution-exception-list-components", + "scope": "common", + "docId": "kibKbnSecuritysolutionExceptionListComponentsPluginApi", + "section": "def-common.Rule", + "text": "Rule" + }, + "[]" + ], "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/securitysolution-exception-list-components", - "id": "def-common.RuleReference.exceptionLists", - "type": "Array", + "id": "def-common.RuleReference.listId", + "type": "string", "tags": [], - "label": "exceptionLists", + "label": "listId", "description": [], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; description: string; id: string; immutable: boolean; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; updated_at: string; updated_by: string; version: number; }[]" + "string | undefined" ], "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", "deprecated": false, @@ -1148,10 +1343,17 @@ "id": "def-common.RuleReferences.Unnamed", "type": "IndexSignature", "tags": [], - "label": "[key: string]: any[]", + "label": "[key: string]: RuleReference", "description": [], "signature": [ - "[key: string]: any[]" + "[key: string]: ", + { + "pluginId": "@kbn/securitysolution-exception-list-components", + "scope": "common", + "docId": "kibKbnSecuritysolutionExceptionListComponentsPluginApi", + "section": "def-common.RuleReference", + "text": "RuleReference" + } ], "path": "packages/kbn-securitysolution-exception-list-components/src/types/index.ts", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index c0e5e93df0aec..92d222cda1ea6 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 76 | 0 | 67 | 1 | +| 89 | 0 | 78 | 1 | ## Common diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 1d278f8ae2e16..023f0a412589b 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_securitysolution_io_ts_alerting_types.devdocs.json index f9869d88c91cd..12a248d480308 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.devdocs.json +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.devdocs.json @@ -62,82 +62,58 @@ "misc": [ { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.Action", + "id": "def-common.ConcurrentSearches", "type": "Type", "tags": [], - "label": "Action", + "label": "ConcurrentSearches", "description": [], "signature": [ - "{ group: string; id: string; action_type_id: string; params: ", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - "; }" + "number" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.Actions", + "id": "def-common.ConcurrentSearchesOrUndefined", "type": "Type", "tags": [], - "label": "Actions", + "label": "ConcurrentSearchesOrUndefined", "description": [], "signature": [ - "{ group: string; id: string; action_type_id: string; params: ", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - "; }[]" + "number | undefined" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.ActionsCamel", + "id": "def-common.ItemsPerSearch", "type": "Type", "tags": [], - "label": "ActionsCamel", + "label": "ItemsPerSearch", "description": [], "signature": [ - "{ group: string; id: string; action_type_id: string; params: ", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - "; }[]" + "number" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.ConcurrentSearches", + "id": "def-common.ItemsPerSearchOrUndefined", "type": "Type", "tags": [], - "label": "ConcurrentSearches", + "label": "ItemsPerSearchOrUndefined", "description": [], "signature": [ - "number" + "number | undefined" ], "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts", "deprecated": false, @@ -146,271 +122,391 @@ }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.ConcurrentSearchesOrUndefined", + "id": "def-common.Language", "type": "Type", "tags": [], - "label": "ConcurrentSearchesOrUndefined", + "label": "Language", "description": [], "signature": [ - "number | undefined" + "\"eql\" | \"lucene\" | \"kuery\"" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.From", + "id": "def-common.LanguageOrUndefined", "type": "Type", "tags": [], - "label": "From", + "label": "LanguageOrUndefined", "description": [], "signature": [ - "string" + "\"eql\" | \"lucene\" | \"kuery\" | undefined" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.FromOrUndefined", + "id": "def-common.MachineLearningJobId", "type": "Type", "tags": [], - "label": "FromOrUndefined", + "label": "MachineLearningJobId", "description": [], "signature": [ - "string | undefined" + "string | string[]" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.ItemsPerSearch", + "id": "def-common.MachineLearningJobIdNormalized", "type": "Type", "tags": [], - "label": "ItemsPerSearch", + "label": "MachineLearningJobIdNormalized", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.MachineLearningJobIdNormalizedOrUndefined", + "type": "Type", + "tags": [], + "label": "MachineLearningJobIdNormalizedOrUndefined", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.MachineLearningJobIdOrUndefined", + "type": "Type", + "tags": [], + "label": "MachineLearningJobIdOrUndefined", + "description": [], + "signature": [ + "string | string[] | undefined" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.MaxSignals", + "type": "Type", + "tags": [], + "label": "MaxSignals", "description": [], "signature": [ "number" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.ItemsPerSearchOrUndefined", + "id": "def-common.MaxSignalsOrUndefined", "type": "Type", "tags": [], - "label": "ItemsPerSearchOrUndefined", + "label": "MaxSignalsOrUndefined", "description": [], "signature": [ "number | undefined" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.Language", + "id": "def-common.RiskScore", "type": "Type", "tags": [], - "label": "Language", - "description": [], + "label": "RiskScore", + "description": [ + "\nTypes the risk score as:\n - Natural Number (positive integer and not a float),\n - Between the values [0 and 100] inclusive." + ], "signature": [ - "\"eql\" | \"lucene\" | \"kuery\"" + "number" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.LanguageOrUndefined", + "id": "def-common.RiskScoreMapping", "type": "Type", "tags": [], - "label": "LanguageOrUndefined", + "label": "RiskScoreMapping", "description": [], "signature": [ - "\"eql\" | \"lucene\" | \"kuery\" | undefined" + "{ field: string; value: string; operator: \"equals\"; risk_score: number | undefined; }[]" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.MachineLearningJobId", + "id": "def-common.RiskScoreMappingItem", "type": "Type", "tags": [], - "label": "MachineLearningJobId", + "label": "RiskScoreMappingItem", "description": [], "signature": [ - "string | string[]" + "{ field: string; value: string; operator: \"equals\"; risk_score: number | undefined; }" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.MachineLearningJobIdNormalized", + "id": "def-common.RuleAction", "type": "Type", "tags": [], - "label": "MachineLearningJobIdNormalized", + "label": "RuleAction", "description": [], "signature": [ - "string[]" + "{ group: string; id: string; action_type_id: string; params: ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + "; }" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.MachineLearningJobIdNormalizedOrUndefined", + "id": "def-common.RuleActionArray", "type": "Type", "tags": [], - "label": "MachineLearningJobIdNormalizedOrUndefined", + "label": "RuleActionArray", "description": [], "signature": [ - "string[] | undefined" + "{ group: string; id: string; action_type_id: string; params: ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + "; }[]" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.MachineLearningJobIdOrUndefined", + "id": "def-common.RuleActionArrayCamel", "type": "Type", "tags": [], - "label": "MachineLearningJobIdOrUndefined", + "label": "RuleActionArrayCamel", "description": [], "signature": [ - "string | string[] | undefined" + "{ group: string; id: string; actionTypeId: string; params: ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + "; }[]" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.MaxSignals", + "id": "def-common.RuleActionCamel", "type": "Type", "tags": [], - "label": "MaxSignals", + "label": "RuleActionCamel", "description": [], "signature": [ - "number" + "{ group: string; id: string; actionTypeId: string; params: ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + "; }" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.MaxSignalsOrUndefined", + "id": "def-common.RuleActionGroup", "type": "Type", "tags": [], - "label": "MaxSignalsOrUndefined", + "label": "RuleActionGroup", "description": [], "signature": [ - "number | undefined" + "string" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.RiskScore", + "id": "def-common.RuleActionId", "type": "Type", "tags": [], - "label": "RiskScore", + "label": "RuleActionId", "description": [], "signature": [ - "number" + "string" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.RiskScoreC", + "id": "def-common.RuleActionParams", + "type": "Type", + "tags": [ + "see" + ], + "label": "RuleActionParams", + "description": [ + "\nParams is an \"object\", since it is a type of RuleActionParams which is action templates." + ], + "signature": [ + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + } + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RuleActionThrottle", "type": "Type", "tags": [], - "label": "RiskScoreC", + "label": "RuleActionThrottle", "description": [], "signature": [ - "Type", - "" + "string" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.RiskScoreMapping", + "id": "def-common.RuleActionTypeId", "type": "Type", "tags": [], - "label": "RiskScoreMapping", + "label": "RuleActionTypeId", "description": [], "signature": [ - "{ field: string; value: string; operator: \"equals\"; risk_score: number | undefined; }[]" + "string" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.RiskScoreMappingOrUndefined", + "id": "def-common.RuleInterval", "type": "Type", "tags": [], - "label": "RiskScoreMappingOrUndefined", + "label": "RuleInterval", "description": [], "signature": [ - "{ field: string; value: string; operator: \"equals\"; risk_score: number | undefined; }[] | undefined" + "string" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.RiskScoreOrUndefined", + "id": "def-common.RuleIntervalFrom", "type": "Type", "tags": [], - "label": "RiskScoreOrUndefined", + "label": "RuleIntervalFrom", "description": [], "signature": [ - "number | undefined" + "string" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RuleIntervalTo", + "type": "Type", + "tags": [], + "label": "RuleIntervalTo", + "description": [ + "\nTODO: Create a regular expression type or custom date math part type here" + ], + "signature": [ + "string" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -517,36 +613,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.SeverityMappingOrUndefined", - "type": "Type", - "tags": [], - "label": "SeverityMappingOrUndefined", - "description": [], - "signature": [ - "{ field: string; operator: \"equals\"; value: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; }[] | undefined" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.SeverityOrUndefined", - "type": "Type", - "tags": [], - "label": "SeverityOrUndefined", - "description": [], - "signature": [ - "\"medium\" | \"high\" | \"low\" | \"critical\" | undefined" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", "id": "def-common.Threat", @@ -847,36 +913,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.Throttle", - "type": "Type", - "tags": [], - "label": "Throttle", - "description": [], - "signature": [ - "string" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.ThrottleOrNull", - "type": "Type", - "tags": [], - "label": "ThrottleOrNull", - "description": [], - "signature": [ - "string | null" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", "id": "def-common.Type", @@ -897,229 +933,18 @@ "id": "def-common.TypeOrUndefined", "type": "Type", "tags": [], - "label": "TypeOrUndefined", - "description": [], - "signature": [ - "\"query\" | \"eql\" | \"threshold\" | \"machine_learning\" | \"saved_query\" | \"threat_match\" | \"new_terms\" | undefined" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], - "objects": [ - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.action", - "type": "Object", - "tags": [], - "label": "action", - "description": [], - "signature": [ - "ExactC", - "<", - "TypeC", - "<{ group: ", - "StringC", - "; id: ", - "StringC", - "; action_type_id: ", - "StringC", - "; params: ", - "Type", - "<", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", ", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", unknown>; }>>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.action_action_type_id", - "type": "Object", - "tags": [], - "label": "action_action_type_id", - "description": [], - "signature": [ - "StringC" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.action_group", - "type": "Object", - "tags": [ - "see" - ], - "label": "action_group", - "description": [ - "\nParams is an \"object\", since it is a type of RuleActionParams which is action templates." - ], - "signature": [ - "StringC" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.action_id", - "type": "Object", - "tags": [], - "label": "action_id", - "description": [], - "signature": [ - "StringC" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.action_params", - "type": "Object", - "tags": [], - "label": "action_params", - "description": [], - "signature": [ - "Type", - "<", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", ", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", unknown>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.actions", - "type": "Object", - "tags": [], - "label": "actions", - "description": [], - "signature": [ - "ArrayC", - "<", - "ExactC", - "<", - "TypeC", - "<{ group: ", - "StringC", - "; id: ", - "StringC", - "; action_type_id: ", - "StringC", - "; params: ", - "Type", - "<", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", ", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", unknown>; }>>>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.actionsCamel", - "type": "Object", - "tags": [], - "label": "actionsCamel", - "description": [], - "signature": [ - "ArrayC", - "<", - "ExactC", - "<", - "TypeC", - "<{ group: ", - "StringC", - "; id: ", - "StringC", - "; actionTypeId: ", - "StringC", - "; params: ", - "Type", - "<", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", ", - { - "pluginId": "@kbn/securitysolution-io-ts-alerting-types", - "scope": "common", - "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", - "section": "def-common.SavedObjectAttributes", - "text": "SavedObjectAttributes" - }, - ", unknown>; }>>>" + "label": "TypeOrUndefined", + "description": [], + "signature": [ + "\"query\" | \"eql\" | \"threshold\" | \"machine_learning\" | \"saved_query\" | \"threat_match\" | \"new_terms\" | undefined" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false - }, + } + ], + "objects": [ { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", "id": "def-common.concurrent_searches", @@ -1321,7 +1146,7 @@ "tags": [], "label": "DefaultRiskScoreMappingArray", "description": [ - "\nTypes the DefaultStringArray as:\n - If null or undefined, then a default risk_score_mapping array will be set" + "\nTypes the DefaultStringArray as:\n - If null or undefined, then a default RiskScoreMapping array will be set" ], "signature": [ "Type", @@ -1339,7 +1164,7 @@ "tags": [], "label": "DefaultSeverityMappingArray", "description": [ - "\nTypes the DefaultStringArray as:\n - If null or undefined, then a default severity_mapping array will be set" + "\nTypes the DefaultStringArray as:\n - If null or undefined, then a default SeverityMapping array will be set" ], "signature": [ "Type", @@ -1404,42 +1229,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.from", - "type": "Object", - "tags": [], - "label": "from", - "description": [], - "signature": [ - "Type", - "" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.fromOrUndefined", - "type": "Object", - "tags": [], - "label": "fromOrUndefined", - "description": [], - "signature": [ - "UnionC", - "<[", - "Type", - ", ", - "UndefinedC", - "]>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", "id": "def-common.items_per_search", @@ -1639,191 +1428,404 @@ ], "signature": [ "Type", - "" + "" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RiskScore", + "type": "Object", + "tags": [], + "label": "RiskScore", + "description": [], + "signature": [ + "Type", + "" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RiskScoreMapping", + "type": "Object", + "tags": [], + "label": "RiskScoreMapping", + "description": [], + "signature": [ + "ArrayC", + "<", + "ExactC", + "<", + "TypeC", + "<{ field: ", + "StringC", + "; value: ", + "StringC", + "; operator: ", + "KeyofC", + "<{ equals: null; }>; risk_score: ", + "UnionC", + "<[", + "Type", + ", ", + "UndefinedC", + "]>; }>>>" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RiskScoreMappingItem", + "type": "Object", + "tags": [], + "label": "RiskScoreMappingItem", + "description": [], + "signature": [ + "ExactC", + "<", + "TypeC", + "<{ field: ", + "StringC", + "; value: ", + "StringC", + "; operator: ", + "KeyofC", + "<{ equals: null; }>; risk_score: ", + "UnionC", + "<[", + "Type", + ", ", + "UndefinedC", + "]>; }>>" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RuleAction", + "type": "Object", + "tags": [], + "label": "RuleAction", + "description": [], + "signature": [ + "ExactC", + "<", + "TypeC", + "<{ group: ", + "StringC", + "; id: ", + "StringC", + "; action_type_id: ", + "StringC", + "; params: ", + "Type", + "<", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", unknown>; }>>" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RuleActionArray", + "type": "Object", + "tags": [], + "label": "RuleActionArray", + "description": [], + "signature": [ + "ArrayC", + "<", + "ExactC", + "<", + "TypeC", + "<{ group: ", + "StringC", + "; id: ", + "StringC", + "; action_type_id: ", + "StringC", + "; params: ", + "Type", + "<", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", unknown>; }>>>" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RuleActionArrayCamel", + "type": "Object", + "tags": [], + "label": "RuleActionArrayCamel", + "description": [], + "signature": [ + "ArrayC", + "<", + "ExactC", + "<", + "TypeC", + "<{ group: ", + "StringC", + "; id: ", + "StringC", + "; actionTypeId: ", + "StringC", + "; params: ", + "Type", + "<", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", unknown>; }>>>" + ], + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", + "id": "def-common.RuleActionCamel", + "type": "Object", + "tags": [], + "label": "RuleActionCamel", + "description": [], + "signature": [ + "ExactC", + "<", + "TypeC", + "<{ group: ", + "StringC", + "; id: ", + "StringC", + "; actionTypeId: ", + "StringC", + "; params: ", + "Type", + "<", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", unknown>; }>>" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.risk_score", + "id": "def-common.RuleActionGroup", "type": "Object", "tags": [], - "label": "risk_score", + "label": "RuleActionGroup", "description": [], "signature": [ - "Type", - "" + "StringC" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.risk_score_mapping", + "id": "def-common.RuleActionId", "type": "Object", "tags": [], - "label": "risk_score_mapping", + "label": "RuleActionId", "description": [], "signature": [ - "ArrayC", - "<", - "ExactC", - "<", - "TypeC", - "<{ field: ", - "StringC", - "; value: ", - "StringC", - "; operator: ", - "KeyofC", - "<{ equals: null; }>; risk_score: ", - "UnionC", - "<[", - "Type", - ", ", - "UndefinedC", - "]>; }>>>" + "StringC" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.risk_score_mapping_field", + "id": "def-common.RuleActionParams", "type": "Object", "tags": [], - "label": "risk_score_mapping_field", + "label": "RuleActionParams", "description": [], "signature": [ - "StringC" + "Type", + "<", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", ", + { + "pluginId": "@kbn/securitysolution-io-ts-alerting-types", + "scope": "common", + "docId": "kibKbnSecuritysolutionIoTsAlertingTypesPluginApi", + "section": "def-common.SavedObjectAttributes", + "text": "SavedObjectAttributes" + }, + ", unknown>" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.risk_score_mapping_item", + "id": "def-common.RuleActionThrottle", "type": "Object", "tags": [], - "label": "risk_score_mapping_item", + "label": "RuleActionThrottle", "description": [], "signature": [ - "ExactC", - "<", - "TypeC", - "<{ field: ", - "StringC", - "; value: ", - "StringC", - "; operator: ", - "KeyofC", - "<{ equals: null; }>; risk_score: ", "UnionC", "<[", + "LiteralC", + "<\"no_actions\">, ", + "LiteralC", + "<\"rule\">, ", "Type", - ", ", - "UndefinedC", - "]>; }>>" + "]>" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.risk_score_mapping_value", + "id": "def-common.RuleActionTypeId", "type": "Object", "tags": [], - "label": "risk_score_mapping_value", + "label": "RuleActionTypeId", "description": [], "signature": [ "StringC" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.RiskScore", + "id": "def-common.RuleInterval", "type": "Object", "tags": [], - "label": "RiskScore", - "description": [ - "\nTypes the risk score as:\n - Natural Number (positive integer and not a float),\n - Between the values [0 and 100] inclusive." - ], + "label": "RuleInterval", + "description": [], "signature": [ - "Type", - "" + "StringC" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.riskScoreMappingOrUndefined", + "id": "def-common.RuleIntervalFrom", "type": "Object", "tags": [], - "label": "riskScoreMappingOrUndefined", + "label": "RuleIntervalFrom", "description": [], "signature": [ - "UnionC", - "<[", - "ArrayC", - "<", - "ExactC", - "<", - "TypeC", - "<{ field: ", - "StringC", - "; value: ", - "StringC", - "; operator: ", - "KeyofC", - "<{ equals: null; }>; risk_score: ", - "UnionC", - "<[", "Type", - ", ", - "UndefinedC", - "]>; }>>>, ", - "UndefinedC", - "]>" + "" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.riskScoreOrUndefined", + "id": "def-common.RuleIntervalTo", "type": "Object", "tags": [], - "label": "riskScoreOrUndefined", + "label": "RuleIntervalTo", "description": [], "signature": [ - "UnionC", - "<[", - "Type", - ", ", - "UndefinedC", - "]>" + "StringC" ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts", + "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -1926,10 +1928,10 @@ }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.severity", + "id": "def-common.Severity", "type": "Object", "tags": [], - "label": "severity", + "label": "Severity", "description": [], "signature": [ "KeyofC", @@ -1942,10 +1944,10 @@ }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.severity_mapping", + "id": "def-common.SeverityMapping", "type": "Object", "tags": [], - "label": "severity_mapping", + "label": "SeverityMapping", "description": [], "signature": [ "ArrayC", @@ -1970,25 +1972,10 @@ }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.severity_mapping_field", - "type": "Object", - "tags": [], - "label": "severity_mapping_field", - "description": [], - "signature": [ - "StringC" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.severity_mapping_item", + "id": "def-common.SeverityMappingItem", "type": "Object", "tags": [], - "label": "severity_mapping_item", + "label": "SeverityMappingItem", "description": [], "signature": [ "ExactC", @@ -2009,73 +1996,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.severity_mapping_value", - "type": "Object", - "tags": [], - "label": "severity_mapping_value", - "description": [], - "signature": [ - "StringC" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.severityMappingOrUndefined", - "type": "Object", - "tags": [], - "label": "severityMappingOrUndefined", - "description": [], - "signature": [ - "UnionC", - "<[", - "ArrayC", - "<", - "ExactC", - "<", - "TypeC", - "<{ field: ", - "StringC", - "; operator: ", - "KeyofC", - "<{ equals: null; }>; value: ", - "StringC", - "; severity: ", - "KeyofC", - "<{ low: null; medium: null; high: null; critical: null; }>; }>>>, ", - "UndefinedC", - "]>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.severityOrUndefined", - "type": "Object", - "tags": [], - "label": "severityOrUndefined", - "description": [], - "signature": [ - "UnionC", - "<[", - "KeyofC", - "<{ low: null; medium: null; high: null; critical: null; }>, ", - "UndefinedC", - "]>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", "id": "def-common.threat", @@ -2880,54 +2800,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.throttle", - "type": "Object", - "tags": [], - "label": "throttle", - "description": [], - "signature": [ - "UnionC", - "<[", - "LiteralC", - "<\"no_actions\">, ", - "LiteralC", - "<\"rule\">, ", - "Type", - "]>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", - "id": "def-common.throttleOrNull", - "type": "Object", - "tags": [], - "label": "throttleOrNull", - "description": [], - "signature": [ - "UnionC", - "<[", - "UnionC", - "<[", - "LiteralC", - "<\"no_actions\">, ", - "LiteralC", - "<\"rule\">, ", - "Type", - "]>, ", - "NullC", - "]>" - ], - "path": "packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/securitysolution-io-ts-alerting-types", "id": "def-common.type", diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index c95b9cd11f17e..ad49fe868193b 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 145 | 0 | 127 | 0 | +| 138 | 0 | 119 | 0 | ## Common diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.devdocs.json b/api_docs/kbn_securitysolution_io_ts_list_types.devdocs.json index 6131ceb64878a..02fc5d323345b 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.devdocs.json +++ b/api_docs/kbn_securitysolution_io_ts_list_types.devdocs.json @@ -27,7 +27,7 @@ "label": "updateExceptionListItemValidate", "description": [], "signature": [ - "(schema: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) => string[]" + "(schema: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) => string[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_validation/index.ts", "deprecated": false, @@ -41,7 +41,7 @@ "label": "schema", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_validation/index.ts", "deprecated": false, @@ -60,7 +60,7 @@ "label": "validateComments", "description": [], "signature": [ - "(item: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) => string[]" + "(item: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) => string[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_validation/index.ts", "deprecated": false, @@ -74,7 +74,7 @@ "label": "item", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_validation/index.ts", "deprecated": false, @@ -162,7 +162,7 @@ "label": "listItem", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts", "deprecated": false, @@ -697,7 +697,7 @@ "label": "exceptions", "description": [], "signature": [ - "(({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; })[]" + "(({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; })[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts", "deprecated": false, @@ -1525,7 +1525,7 @@ "label": "exceptions", "description": [], "signature": [ - "(({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; })[]" + "(({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; })[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts", "deprecated": false, @@ -1747,7 +1747,7 @@ "label": "listItem", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts", "deprecated": false, @@ -1845,7 +1845,7 @@ "label": "exceptions", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts", "deprecated": false, @@ -2475,7 +2475,7 @@ "label": "CreateEndpointListItemSchemaDecoded", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; comments: { comment: string; }[] | undefined; item_id: string | undefined; meta: object | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"os_types\"> & { comments: { comment: string; }[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" + "Omit<{ description: string; entries: ({ field: string; operator: \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; comments: { comment: string; }[] | undefined; item_id: string | undefined; meta: object | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"os_types\"> & { comments: { comment: string; }[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.ts", "deprecated": false, @@ -2505,7 +2505,7 @@ "label": "CreateExceptionListItemSchema", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts", "deprecated": false, @@ -2520,7 +2520,7 @@ "label": "CreateExceptionListItemSchemaDecoded", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; comments: { comment: string; }[] | undefined; item_id: string | undefined; meta: object | undefined; namespace_type: \"single\" | \"agnostic\" | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"namespace_type\"> & { comments: { comment: string; }[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" + "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; comments: { comment: string; }[] | undefined; item_id: string | undefined; meta: object | undefined; namespace_type: \"single\" | \"agnostic\" | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"namespace_type\"> & { comments: { comment: string; }[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts", "deprecated": false, @@ -2595,7 +2595,7 @@ "label": "CreateListSchema", "description": [], "signature": [ - "{ description: string; name: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; } & { deserializer?: string | undefined; id?: string | undefined; meta?: object | undefined; serializer?: string | undefined; version?: number | undefined; }" + "{ description: string; name: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; } & { deserializer?: string | undefined; id?: string | undefined; meta?: object | undefined; serializer?: string | undefined; version?: number | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts", "deprecated": false, @@ -2610,7 +2610,7 @@ "label": "CreateListSchemaDecoded", "description": [], "signature": [ - "{ name: string; description: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; id: string | undefined; meta: object | undefined; serializer: string | undefined; deserializer: string | undefined; } & { version: number; }" + "{ name: string; description: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; id: string | undefined; meta: object | undefined; serializer: string | undefined; deserializer: string | undefined; } & { version: number; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts", "deprecated": false, @@ -2625,7 +2625,7 @@ "label": "CreateRuleExceptionListItemSchema", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; list_id?: undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; list_id?: undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts", "deprecated": false, @@ -2640,7 +2640,7 @@ "label": "CreateRuleExceptionListItemSchemaDecoded", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; comments: { comment: string; }[] | undefined; item_id: string | undefined; list_id: undefined; meta: object | undefined; namespace_type: \"single\" | \"agnostic\" | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"namespace_type\"> & { comments: { comment: string; }[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" + "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; comments: { comment: string; }[] | undefined; item_id: string | undefined; list_id: undefined; meta: object | undefined; namespace_type: \"single\" | \"agnostic\" | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"namespace_type\"> & { comments: { comment: string; }[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts", "deprecated": false, @@ -2955,7 +2955,7 @@ "label": "EntriesArray", "description": [], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts", "deprecated": false, @@ -2970,7 +2970,7 @@ "label": "EntriesArrayOrUndefined", "description": [], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[] | undefined" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[] | undefined" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts", "deprecated": false, @@ -2985,7 +2985,7 @@ "label": "Entry", "description": [], "signature": [ - "{ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; }" + "{ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts", "deprecated": false, @@ -3015,7 +3015,7 @@ "label": "EntryList", "description": [], "signature": [ - "{ field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; }" + "{ field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.ts", "deprecated": false, @@ -3105,7 +3105,7 @@ "label": "ExceptionListItemSchema", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.ts", "deprecated": false, @@ -3450,7 +3450,7 @@ "label": "FoundAllListItemsSchema", "description": [], "signature": [ - "{ data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]; total: number; }" + "{ data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]; total: number; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.ts", "deprecated": false, @@ -3465,7 +3465,7 @@ "label": "FoundExceptionListItemSchema", "description": [], "signature": [ - "{ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }" + "{ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.ts", "deprecated": false, @@ -3495,7 +3495,7 @@ "label": "FoundListItemSchema", "description": [], "signature": [ - "{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]; page: number; per_page: number; total: number; }" + "{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]; page: number; per_page: number; total: number; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.ts", "deprecated": false, @@ -3510,7 +3510,7 @@ "label": "FoundListsBySizeSchema", "description": [], "signature": [ - "{ largeLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; smallLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; }" + "{ largeLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; smallLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.ts", "deprecated": false, @@ -3525,7 +3525,7 @@ "label": "FoundListSchema", "description": [], "signature": [ - "{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }" + "{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.ts", "deprecated": false, @@ -3540,7 +3540,7 @@ "label": "GetExceptionFilterSchema", "description": [], "signature": [ - "({ exception_list_ids: { exception_list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; type: \"exception_list_ids\"; } | { exceptions: (({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; })[]; type: \"exception_items\"; }) & { alias?: string | undefined; chunk_size?: number | undefined; exclude_exceptions?: boolean | undefined; }" + "({ exception_list_ids: { exception_list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; type: \"exception_list_ids\"; } | { exceptions: (({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; })[]; type: \"exception_items\"; }) & { alias?: string | undefined; chunk_size?: number | undefined; exclude_exceptions?: boolean | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/get_exception_filter_schema/index.ts", "deprecated": false, @@ -3660,7 +3660,7 @@ "label": "ImportExceptionListItemSchema", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; item_id: string; list_id: string; name: string; type: \"simple\"; } & { id?: string | undefined; comments?: (({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; }) | { comment: string; })[] | undefined; created_at?: string | undefined; updated_at?: string | undefined; created_by?: string | undefined; updated_by?: string | undefined; _version?: string | undefined; tie_breaker_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; item_id: string; list_id: string; name: string; type: \"simple\"; } & { id?: string | undefined; comments?: (({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; }) | { comment: string; })[] | undefined; created_at?: string | undefined; updated_at?: string | undefined; created_by?: string | undefined; updated_by?: string | undefined; _version?: string | undefined; tie_breaker_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts", "deprecated": false, @@ -3675,7 +3675,7 @@ "label": "ImportExceptionListItemSchemaDecoded", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; item_id: string; list_id: string; name: string; type: \"simple\"; } & { id?: string | undefined; comments?: (({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; }) | { comment: string; })[] | undefined; created_at?: string | undefined; updated_at?: string | undefined; created_by?: string | undefined; updated_by?: string | undefined; _version?: string | undefined; tie_breaker_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"namespace_type\"> & { comments: (({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; }) | { comment: string; })[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" + "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; item_id: string; list_id: string; name: string; type: \"simple\"; } & { id?: string | undefined; comments?: (({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; }) | { comment: string; })[] | undefined; created_at?: string | undefined; updated_at?: string | undefined; created_by?: string | undefined; updated_by?: string | undefined; _version?: string | undefined; tie_breaker_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"item_id\" | \"namespace_type\"> & { comments: (({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; }) | { comment: string; })[]; tags: string[]; item_id: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts", "deprecated": false, @@ -3735,7 +3735,7 @@ "label": "ImportListItemQuerySchema", "description": [], "signature": [ - "{ deserializer: string | undefined; list_id: string | undefined; serializer: string | undefined; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\" | undefined; }" + "{ deserializer: string | undefined; list_id: string | undefined; serializer: string | undefined; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\" | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts", "deprecated": false, @@ -3750,7 +3750,7 @@ "label": "ImportListItemQuerySchemaEncoded", "description": [], "signature": [ - "{ deserializer?: string | undefined; list_id?: string | undefined; serializer?: string | undefined; type?: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\" | undefined; }" + "{ deserializer?: string | undefined; list_id?: string | undefined; serializer?: string | undefined; type?: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\" | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts", "deprecated": false, @@ -3900,7 +3900,7 @@ "label": "ListArraySchema", "description": [], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]" + "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts", "deprecated": false, @@ -3945,7 +3945,7 @@ "label": "ListItemArraySchema", "description": [], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]" + "{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts", "deprecated": false, @@ -3975,7 +3975,7 @@ "label": "ListItemSchema", "description": [], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }" + "{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts", "deprecated": false, @@ -4005,7 +4005,7 @@ "label": "ListSchema", "description": [], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }" + "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts", "deprecated": false, @@ -4230,7 +4230,7 @@ "label": "NonEmptyEntriesArray", "description": [], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts", "deprecated": false, @@ -4245,7 +4245,7 @@ "label": "NonEmptyEntriesArrayDecoded", "description": [], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts", "deprecated": false, @@ -4680,7 +4680,7 @@ "label": "SearchListItemArraySchema", "description": [], "signature": [ - "{ items: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]; value: unknown; }[]" + "{ items: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]; value: unknown; }[]" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts", "deprecated": false, @@ -4695,7 +4695,7 @@ "label": "SearchListItemSchema", "description": [], "signature": [ - "{ items: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]; value: unknown; }" + "{ items: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]; value: unknown; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts", "deprecated": false, @@ -4860,7 +4860,7 @@ "label": "Type", "description": [], "signature": [ - "\"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"" + "\"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts", "deprecated": false, @@ -4875,7 +4875,7 @@ "label": "TypeOrUndefined", "description": [], "signature": [ - "\"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\" | undefined" + "\"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\" | undefined" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts", "deprecated": false, @@ -4935,7 +4935,7 @@ "label": "UpdateEndpointListItemSchema", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts", "deprecated": false, @@ -4950,7 +4950,7 @@ "label": "UpdateEndpointListItemSchemaDecoded", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; _version: string | undefined; comments: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id: string | undefined; item_id: string | undefined; meta: object | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\"> & { comments: ({ comment: string; } & { id?: string | undefined; })[]; tags: string[]; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" + "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; _version: string | undefined; comments: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id: string | undefined; item_id: string | undefined; meta: object | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\"> & { comments: ({ comment: string; } & { id?: string | undefined; })[]; tags: string[]; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts", "deprecated": false, @@ -4965,7 +4965,7 @@ "label": "UpdateExceptionListItemSchema", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts", "deprecated": false, @@ -4980,7 +4980,7 @@ "label": "UpdateExceptionListItemSchemaDecoded", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; _version: string | undefined; comments: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id: string | undefined; item_id: string | undefined; meta: object | undefined; namespace_type: \"single\" | \"agnostic\" | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"namespace_type\" | \"os_types\"> & { comments: ({ comment: string; } & { id?: string | undefined; })[]; tags: string[]; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" + "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; _version: string | undefined; comments: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id: string | undefined; item_id: string | undefined; meta: object | undefined; namespace_type: \"single\" | \"agnostic\" | undefined; os_types: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags: string[] | undefined; }, \"tags\" | \"entries\" | \"comments\" | \"namespace_type\" | \"os_types\"> & { comments: ({ comment: string; } & { id?: string | undefined; })[]; tags: string[]; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[]; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; }" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts", "deprecated": false, @@ -5535,7 +5535,7 @@ "StringC", "; entries: ", "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; list_id: ", + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; list_id: ", "Type", "; name: ", "StringC", @@ -5703,7 +5703,7 @@ "StringC", "; entries: ", "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; name: ", + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; name: ", "StringC", "; type: ", "KeyofC", @@ -7110,7 +7110,7 @@ "StringC", "; entries: ", "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; list_id: ", + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; list_id: ", "Type", "; name: ", "StringC", @@ -8319,7 +8319,7 @@ "StringC", "; entries: ", "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; list_id: ", + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; list_id: ", "Type", "; name: ", "StringC", @@ -8606,7 +8606,7 @@ "StringC", "; entries: ", "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; item_id: ", + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; item_id: ", "Type", "; list_id: ", "Type", @@ -9646,7 +9646,7 @@ ], "signature": [ "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>" + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>" ], "path": "packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts", "deprecated": false, @@ -10656,7 +10656,7 @@ "StringC", "; entries: ", "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; name: ", + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; name: ", "StringC", "; type: ", "KeyofC", @@ -10710,7 +10710,7 @@ "StringC", "; entries: ", "Type", - "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; name: ", + "<({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; })[]; field: string; type: \"nested\"; })[], unknown>; name: ", "StringC", "; type: ", "KeyofC", diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 10fe52558bfec..9fef809436887 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: 2022-10-19 +date: 2022-10-23 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 f071273b1067c..07caff5f09fca 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: 2022-10-19 +date: 2022-10-23 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 1ec1ec0084617..d0cbc9f176468 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_securitysolution_list_api.devdocs.json index 19306715a1954..00e1b747be030 100644 --- a/api_docs/kbn_securitysolution_list_api.devdocs.json +++ b/api_docs/kbn_securitysolution_list_api.devdocs.json @@ -64,7 +64,7 @@ "signature": [ "({ http, listItem, signal, }: ", "AddExceptionListItemProps", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "packages/kbn-securitysolution-list-api/src/api/index.ts", "deprecated": false, @@ -216,7 +216,7 @@ "signature": [ "({ http, id, namespaceType, signal, }: ", "ApiCallByIdProps", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "packages/kbn-securitysolution-list-api/src/api/index.ts", "deprecated": false, @@ -257,7 +257,7 @@ "section": "def-common.DeleteListParams", "text": "DeleteListParams" }, - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }>" ], "path": "packages/kbn-securitysolution-list-api/src/list_api/index.ts", "deprecated": false, @@ -419,7 +419,7 @@ "signature": [ "({ http, id, namespaceType, signal, }: ", "ApiCallByIdProps", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "packages/kbn-securitysolution-list-api/src/api/index.ts", "deprecated": false, @@ -454,7 +454,7 @@ "signature": [ "({ filter, http, listIds, namespaceTypes, pagination, search, signal, }: ", "ApiCallByListIdProps", - ") => Promise<{ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }>" + ") => Promise<{ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }>" ], "path": "packages/kbn-securitysolution-list-api/src/api/index.ts", "deprecated": false, @@ -530,7 +530,7 @@ "section": "def-common.FindListsParams", "text": "FindListsParams" }, - ") => Promise<{ largeLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; smallLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; }>" + ") => Promise<{ largeLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; smallLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; }>" ], "path": "packages/kbn-securitysolution-list-api/src/list_api/index.ts", "deprecated": false, @@ -577,7 +577,7 @@ "section": "def-common.FindListsParams", "text": "FindListsParams" }, - ") => Promise<{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }>" + ") => Promise<{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }>" ], "path": "packages/kbn-securitysolution-list-api/src/list_api/index.ts", "deprecated": false, @@ -706,7 +706,7 @@ "section": "def-common.ImportListParams", "text": "ImportListParams" }, - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }>" ], "path": "packages/kbn-securitysolution-list-api/src/list_api/index.ts", "deprecated": false, @@ -910,7 +910,7 @@ "signature": [ "({ http, listItem, signal, }: ", "UpdateExceptionListItemProps", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "packages/kbn-securitysolution-list-api/src/api/index.ts", "deprecated": false, @@ -1291,7 +1291,7 @@ "label": "type", "description": [], "signature": [ - "\"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\" | undefined" + "\"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\" | undefined" ], "path": "packages/kbn-securitysolution-list-api/src/list_api/types.ts", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 0ab9532ea820a..5bf2d289bce03 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: 2022-10-19 +date: 2022-10-23 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 724c6c4b8cd63..7a75f384ae683 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_securitysolution_list_hooks.devdocs.json index 442efdd46470e..0584759561cde 100644 --- a/api_docs/kbn_securitysolution_list_hooks.devdocs.json +++ b/api_docs/kbn_securitysolution_list_hooks.devdocs.json @@ -29,7 +29,7 @@ "\nThis adds an id to the incoming exception item entries as ReactJS prefers to have\nan id added to them for use as a stable id. Later if we decide to change the data\nmodel to have id's within the array then this code should be removed. If not, then\nthis code should stay as an adapter for ReactJS.\n\nThis does break the type system slightly as we are lying a bit to the type system as we return\nthe same exceptionItem as we have previously but are augmenting the arrays with an id which TypeScript\ndoesn't mind us doing here. However, downstream you will notice that you have an id when the type\ndoes not indicate it. In that case use (ExceptionItem & { id: string }) temporarily if you're using the id. If you're not,\nyou can ignore the id and just use the normal TypeScript with ReactJS.\n" ], "signature": [ - "(exceptionItem: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "(exceptionItem: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -45,7 +45,7 @@ "The exceptionItem to add an id to the threat matches." ], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -68,7 +68,7 @@ "\nThis removes an id from the exceptionItem entries as ReactJS prefers to have\nan id added to them for use as a stable id. Later if we decide to change the data\nmodel to have id's within the array then this code should be removed. If not, then\nthis code should stay as an adapter for ReactJS.\n" ], "signature": [ - "(exceptionItem: T) => T" + "(exceptionItem: T) => T" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -107,7 +107,7 @@ "\nTransforms the output of rules to compensate for technical debt or UI concerns such as\nReactJS preferences for having ids within arrays if the data is not modeled that way.\n\nIf you add a new transform of the input called \"myNewTransform\" do it\nin the form of:\nflow(addIdToExceptionItemEntries, myNewTransform)(exceptionItem)\n" ], "signature": [ - "(exceptionItem: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "(exceptionItem: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -123,7 +123,7 @@ "The exceptionItem to transform the output of" ], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -144,7 +144,7 @@ "label": "transformNewItemOutput", "description": [], "signature": [ - "(exceptionItem: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) => { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "(exceptionItem: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) => { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -158,7 +158,7 @@ "label": "exceptionItem", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -179,7 +179,7 @@ "\nTransforms the output of exception items to compensate for technical debt or UI concerns such as\nReactJS preferences for having ids within arrays if the data is not modeled that way.\n\nIf you add a new transform of the output called \"myNewTransform\" do it\nin the form of:\nflow(removeIdFromExceptionItemsEntries, myNewTransform)(exceptionItem)\n" ], "signature": [ - "(exceptionItem: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })) => { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" + "(exceptionItem: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })) => { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -195,7 +195,7 @@ "The exceptionItem to transform the output of" ], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" ], "path": "packages/kbn-securitysolution-list-hooks/src/transforms/index.ts", "deprecated": false, @@ -332,7 +332,7 @@ "OptionalSignalArgs", "<", "DeleteListParams", - ">], { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" + ">], { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }>" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.ts", "deprecated": false, @@ -422,7 +422,7 @@ "OptionalSignalArgs", "<", "FindListsParams", - ">], { cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }>" + ">], { cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }>" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.ts", "deprecated": false, @@ -445,7 +445,7 @@ "OptionalSignalArgs", "<", "FindListsParams", - ">], { largeLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; smallLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; }>" + ">], { largeLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; smallLists: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; }>" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_find_lists_by_size/index.ts", "deprecated": false, @@ -468,7 +468,7 @@ "OptionalSignalArgs", "<", "ImportListParams", - ">], { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" + ">], { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }>" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts", "deprecated": false, @@ -632,7 +632,7 @@ "label": "addExceptionListItem", "description": [], "signature": [ - "(arg: { listItem: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }; }) => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + "(arg: { listItem: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }; }) => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_api/index.ts", "deprecated": false, @@ -657,7 +657,7 @@ "label": "listItem", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_api/index.ts", "deprecated": false, @@ -676,7 +676,7 @@ "label": "updateExceptionListItem", "description": [], "signature": [ - "(arg: { listItem: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }; }) => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + "(arg: { listItem: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }; }) => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_api/index.ts", "deprecated": false, @@ -701,7 +701,7 @@ "label": "listItem", "description": [], "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" + "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_api/index.ts", "deprecated": false, @@ -790,7 +790,7 @@ "signature": [ "(arg: ", "ApiCallMemoProps", - " & { onSuccess: (arg: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => void; }) => Promise" + " & { onSuccess: (arg: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => void; }) => Promise" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_api/index.ts", "deprecated": false, @@ -805,7 +805,7 @@ "description": [], "signature": [ "ApiCallMemoProps", - " & { onSuccess: (arg: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => void; }" + " & { onSuccess: (arg: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }) => void; }" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_api/index.ts", "deprecated": false, @@ -1080,7 +1080,7 @@ "label": "ReturnPersistExceptionItem", "description": [], "signature": [ - "[PersistReturnExceptionItem, React.Dispatch<({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | null>]" + "[PersistReturnExceptionItem, React.Dispatch<({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | null>]" ], "path": "packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.ts", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index b9b4d7e437a36..b28c9ecc0ff96 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: 2022-10-19 +date: 2022-10-23 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.devdocs.json b/api_docs/kbn_securitysolution_list_utils.devdocs.json index 39f11e812f589..becdd346daef2 100644 --- a/api_docs/kbn_securitysolution_list_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_list_utils.devdocs.json @@ -27,7 +27,7 @@ "label": "addIdToEntries", "description": [], "signature": [ - "(entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]) => ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" + "(entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]) => ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" ], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -41,7 +41,7 @@ "label": "entries", "description": [], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" ], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -116,7 +116,15 @@ "section": "def-common.ExceptionsBuilderExceptionItem", "text": "ExceptionsBuilderExceptionItem" }, - "[]) => ({ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }))[]" + "[]) => ", + { + "pluginId": "@kbn/securitysolution-list-utils", + "scope": "common", + "docId": "kibKbnSecuritysolutionListUtilsPluginApi", + "section": "def-common.ExceptionsBuilderReturnExceptionItem", + "text": "ExceptionsBuilderReturnExceptionItem" + }, + "[]" ], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -288,7 +296,7 @@ "section": "def-common.FormattedBuilderEntry", "text": "FormattedBuilderEntry" }, - ") => ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; }) & { id?: string | undefined; }" + ") => ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; }) & { id?: string | undefined; }" ], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -436,7 +444,7 @@ "section": "def-common.FormattedBuilderEntry", "text": "FormattedBuilderEntry" }, - ", newField: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }) => { index: number; updatedEntry: ", + ", newField: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }) => { index: number; updatedEntry: ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -483,7 +491,7 @@ "- newly selected list" ], "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }" + "{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }" ], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -1154,7 +1162,7 @@ "section": "def-common.BuilderEntry", "text": "BuilderEntry" }, - "[], parent?: { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | undefined, parentIndex?: number | undefined) => ", + "[], allowCustomFieldOptions: boolean, parent?: { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | undefined, parentIndex?: number | undefined) => ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -1210,6 +1218,23 @@ { "parentPluginId": "@kbn/securitysolution-list-utils", "id": "def-common.getFormattedBuilderEntries.$3", + "type": "boolean", + "tags": [], + "label": "allowCustomFieldOptions", + "description": [ + "determines if field must be found to match in indexPattern or not" + ], + "signature": [ + "boolean" + ], + "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/securitysolution-list-utils", + "id": "def-common.getFormattedBuilderEntries.$4", "type": "Object", "tags": [], "label": "parent", @@ -1226,7 +1251,7 @@ }, { "parentPluginId": "@kbn/securitysolution-list-utils", - "id": "def-common.getFormattedBuilderEntries.$4", + "id": "def-common.getFormattedBuilderEntries.$5", "type": "number", "tags": [], "label": "parentIndex", @@ -1265,7 +1290,7 @@ "section": "def-common.BuilderEntry", "text": "BuilderEntry" }, - ", itemIndex: number, parent: { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | undefined, parentIndex: number | undefined) => ", + ", itemIndex: number, parent: { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | undefined, parentIndex: number | undefined, allowCustomFieldOptions: boolean) => ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -1366,6 +1391,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "@kbn/securitysolution-list-utils", + "id": "def-common.getFormattedBuilderEntry.$6", + "type": "boolean", + "tags": [], + "label": "allowCustomFieldOptions", + "description": [ + "determines if field must be found to match in indexPattern or not" + ], + "signature": [ + "boolean" + ], + "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [], @@ -1514,7 +1556,7 @@ "label": "getNewExceptionItem", "description": [], "signature": [ - "({ listId, namespaceType, ruleName, }: { listId: string | undefined; namespaceType: \"single\" | \"agnostic\" | undefined; ruleName: string; }) => ", + "({ listId, namespaceType, name, }: { listId: string | undefined; namespaceType: \"single\" | \"agnostic\" | undefined; name: string; }) => ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -1532,7 +1574,7 @@ "id": "def-common.getNewExceptionItem.$1", "type": "Object", "tags": [], - "label": "{\n listId,\n namespaceType,\n ruleName,\n}", + "label": "{\n listId,\n namespaceType,\n name,\n}", "description": [], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -1568,10 +1610,10 @@ }, { "parentPluginId": "@kbn/securitysolution-list-utils", - "id": "def-common.getNewExceptionItem.$1.ruleName", + "id": "def-common.getNewExceptionItem.$1.name", "type": "string", "tags": [], - "label": "ruleName", + "label": "name", "description": [], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -1940,7 +1982,7 @@ "label": "hasLargeValueList", "description": [], "signature": [ - "(entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]) => boolean" + "(entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]) => boolean" ], "path": "packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts", "deprecated": false, @@ -1954,7 +1996,7 @@ "label": "entries", "description": [], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" ], "path": "packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts", "deprecated": false, @@ -2539,7 +2581,7 @@ "label": "BuilderEntry", "description": [], "signature": [ - "(({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; }) & { id?: string | undefined; }) | ", + "(({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; }) & { id?: string | undefined; }) | ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -2600,7 +2642,7 @@ "label": "CreateExceptionListItemBuilderSchema", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }, \"meta\" | \"entries\" | \"list_id\" | \"namespace_type\"> & { meta: { temporaryUuid: string; }; entries: ", + "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }, \"meta\" | \"entries\" | \"list_id\" | \"namespace_type\"> & { meta: { temporaryUuid: string; }; entries: ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -2726,7 +2768,7 @@ "label": "ExceptionListItemBuilderSchema", "description": [], "signature": [ - "Omit<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }, \"entries\"> & { entries: ", + "Omit<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }, \"entries\"> & { entries: ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -2793,7 +2835,7 @@ "label": "ExceptionsBuilderReturnExceptionItem", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; list_id?: undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; list_id?: undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" ], "path": "packages/kbn-securitysolution-list-utils/src/types/index.ts", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index a57b7c36ad6ce..aa6a97dd4a0d9 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 192 | 0 | 150 | 0 | +| 194 | 0 | 150 | 0 | ## Common diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 8605e596eedac..509c5178a97f1 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: 2022-10-19 +date: 2022-10-23 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 590ef8eaa6c5a..1da7a50409e32 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: 2022-10-19 +date: 2022-10-23 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 800b9e4af40df..dfd9c1004e558 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: 2022-10-19 +date: 2022-10-23 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 4227acb023d34..9a6916f6ba7ab 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: 2022-10-19 +date: 2022-10-23 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 14da580302760..84cf1e855f1b5 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 7a8502d00a6b5..17483cbad04cc 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: 2022-10-19 +date: 2022-10-23 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_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index bb56ff5226aa0..62e1ef28dd737 100644 --- a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx +++ b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-user-profile-components title: "@kbn/shared-ux-avatar-user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-user-profile-components plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-user-profile-components'] --- import kbnSharedUxAvatarUserProfileComponentsObj from './kbn_shared_ux_avatar_user_profile_components.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 6736eea0420cb..92dabd804b235 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: 2022-10-19 +date: 2022-10-23 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 5062f90955cdf..144b6954b7224 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: 2022-10-19 +date: 2022-10-23 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 4e681c4ceb59a..e3b5081c9d805 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: 2022-10-19 +date: 2022-10-23 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 d1a43cc86f335..aebe27afe102c 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: 2022-10-19 +date: 2022-10-23 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_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 4eb5df3025dce..6c8fbfad07d37 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: 2022-10-19 +date: 2022-10-23 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 71eb503b0ae27..94c32cd2dcaab 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: 2022-10-19 +date: 2022-10-23 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 a46a79f7055fa..478fb9bb023ba 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: 2022-10-19 +date: 2022-10-23 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 cfcdb0598569c..0c1d65d3cb73b 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: 2022-10-19 +date: 2022-10-23 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 843ffd7a43c71..75bed31d05424 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: 2022-10-19 +date: 2022-10-23 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 51a8cb1d10a7e..4ec8c1628584d 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: 2022-10-19 +date: 2022-10-23 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 8fe8a8ee12999..50dab94af30ac 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: 2022-10-19 +date: 2022-10-23 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 7473d908e28fe..e7a8ac56275ee 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: 2022-10-19 +date: 2022-10-23 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 ac549a8681ade..87f18a0991826 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: 2022-10-19 +date: 2022-10-23 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 6604c3f0e6175..570eb559ddd44 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: 2022-10-19 +date: 2022-10-23 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 835a459d9cd9f..b1eff12598b8f 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: 2022-10-19 +date: 2022-10-23 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 2795821d7c692..16e6414a082ed 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: 2022-10-19 +date: 2022-10-23 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 5d8d4a619c500..3e175a7d75baf 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: 2022-10-19 +date: 2022-10-23 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 3a02573011e3d..11cbf8bb8f6c8 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: 2022-10-19 +date: 2022-10-23 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 504d85c3793a6..8c017d80a3cb3 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: 2022-10-19 +date: 2022-10-23 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 f6623d0ef40c3..7fb342fee5ebf 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: 2022-10-19 +date: 2022-10-23 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_router.mdx b/api_docs/kbn_shared_ux_router.mdx index c0bc26f48dce4..4815bcf101f2d 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: 2022-10-19 +date: 2022-10-23 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 54988f3c8f70a..f8982ed0d7012 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: 2022-10-19 +date: 2022-10-23 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 81bce42ddc563..3bb3041db9c56 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: 2022-10-19 +date: 2022-10-23 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 6cc2ffb9b6fee..d226bf5552453 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: 2022-10-19 +date: 2022-10-23 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 92736ba656203..0122d2fd36da1 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 7a0e18bbbb45c..4861591d4df37 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index cc48c4dd70526..ff0c054cb5d95 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-package-json plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] --- import kbnSortPackageJsonObj from './kbn_sort_package_json.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 24a0703ce14f6..3d8b290bb8d36 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: 2022-10-19 +date: 2022-10-23 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 30c8c381c0011..f844436143f81 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: 2022-10-19 +date: 2022-10-23 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 aa57f4e3ecc4e..647f5a345cc44 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index c593141c7552a..eb3c04653cb5f 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: 2022-10-19 +date: 2022-10-23 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 3c549354a2843..5e170972157db 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: 2022-10-19 +date: 2022-10-23 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 fd36b980ad29b..83e70d19f4a25 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: 2022-10-19 +date: 2022-10-23 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 fb47d96c8bc0b..701855170084c 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index fc9bf037bd5e5..46bb805891a19 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index ab7cd3cc4bd13..5cd3e0c62c618 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] --- import kbnTypeSummarizerObj from './kbn_type_summarizer.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer_core.mdx b/api_docs/kbn_type_summarizer_core.mdx index 26a51ad359692..86596d6920dd3 100644 --- a/api_docs/kbn_type_summarizer_core.mdx +++ b/api_docs/kbn_type_summarizer_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer-core title: "@kbn/type-summarizer-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer-core plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer-core'] --- import kbnTypeSummarizerCoreObj from './kbn_type_summarizer_core.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 8249c746de860..6eb7e508f7402 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: 2022-10-19 +date: 2022-10-23 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_theme.mdx b/api_docs/kbn_ui_theme.mdx index 8f254d50010cd..77bf8c74e4e32 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 993f38a1d662b..08f28ad7397a8 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: 2022-10-19 +date: 2022-10-23 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 c5f3735d6cd0f..2c851f8c21def 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: 2022-10-19 +date: 2022-10-23 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 7bc9101406d46..abfc1603574f1 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: 2022-10-19 +date: 2022-10-23 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 9345c4dd01a8e..ae6919df02199 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index c97ceed036db9..558f4d554b6bd 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index f63c34127ff68..2a01e6fe28b1b 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: 2022-10-19 +date: 2022-10-23 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 a53bcae3e76e9..adcc3c1b68859 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: 2022-10-19 +date: 2022-10-23 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 b5f6e16e9dced..55bf1e431e9cb 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: 2022-10-19 +date: 2022-10-23 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 2425fc77afd1a..408c4a73d1b34 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: 2022-10-19 +date: 2022-10-23 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 4e1fcb3522b70..a47de550fe7da 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: 2022-10-19 +date: 2022-10-23 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 fb0ec27276102..863a36d861e4d 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: 2022-10-19 +date: 2022-10-23 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 960de45eabbe3..7c8083328859d 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.devdocs.json b/api_docs/licensing.devdocs.json index 6b2d792de9c75..df3ae7c6518ff 100644 --- a/api_docs/licensing.devdocs.json +++ b/api_docs/licensing.devdocs.json @@ -598,6 +598,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts" @@ -1871,6 +1875,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts" diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 62f2758c6431a..28e869af4d0a3 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.devdocs.json b/api_docs/lists.devdocs.json index 5270d0f1418e9..6410ac3562395 100644 --- a/api_docs/lists.devdocs.json +++ b/api_docs/lists.devdocs.json @@ -303,7 +303,7 @@ "label": "exceptionsToDelete", "description": [], "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]" + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]" ], "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", "deprecated": false, @@ -580,7 +580,7 @@ "signature": [ "({ itemId, id, namespaceType, }: ", "GetExceptionListItemOptions", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -658,7 +658,7 @@ "signature": [ "({ comments, description, entries, itemId, meta, name, osTypes, tags, type, }: ", "CreateEndpointListItemOptions", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -696,7 +696,7 @@ "signature": [ "({ _version, comments, description, entries, id, itemId, meta, name, osTypes, tags, type, }: ", "UpdateEndpointListItemOptions", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -734,7 +734,7 @@ "signature": [ "({ itemId, id, }: ", "GetEndpointListItemOptions", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -892,7 +892,7 @@ "section": "def-server.CreateExceptionListItemOptions", "text": "CreateExceptionListItemOptions" }, - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -942,7 +942,7 @@ "section": "def-server.UpdateExceptionListItemOptions", "text": "UpdateExceptionListItemOptions" }, - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -986,7 +986,7 @@ "signature": [ "({ id, itemId, namespaceType, }: ", "DeleteExceptionListItemOptions", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -1060,7 +1060,7 @@ "signature": [ "({ id, itemId, }: ", "DeleteEndpointListItemOptions", - ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" + ") => Promise<{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -1096,7 +1096,7 @@ "signature": [ "({ listId, filter, perPage, pit, page, search, searchAfter, sortField, sortOrder, namespaceType, }: ", "FindExceptionListItemOptions", - ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" + ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -1134,7 +1134,7 @@ "signature": [ "({ listId, filter, perPage, pit, page, search, searchAfter, sortField, sortOrder, namespaceType, }: ", "FindExceptionListsItemOptions", - ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" + ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -1172,7 +1172,7 @@ "signature": [ "({ perPage, pit, page, searchAfter, sortField, sortOrder, valueListId, }: ", "FindValueListExceptionListsItems", - ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" + ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -1248,7 +1248,7 @@ "signature": [ "({ filter, perPage, page, pit, search, searchAfter, sortField, sortOrder, }: ", "FindEndpointListItemOptions", - ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" + ") => Promise<({ data: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]; page: number; per_page: number; total: number; } & { pit?: string | undefined; }) | null>" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", "deprecated": false, @@ -1722,7 +1722,7 @@ "signature": [ "({ id }: ", "GetListOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -1760,7 +1760,7 @@ "signature": [ "({ id, deserializer, immutable, serializer, name, description, type, meta, version, }: ", "CreateListOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -1798,7 +1798,7 @@ "signature": [ "({ id, deserializer, serializer, name, description, immutable, type, meta, version, }: ", "CreateListIfItDoesNotExistOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2316,7 +2316,7 @@ "signature": [ "({ id }: ", "DeleteListItemOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2354,7 +2354,7 @@ "signature": [ "({ listId, value, type, }: ", "DeleteListItemByValueOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2392,7 +2392,7 @@ "signature": [ "({ id }: ", "DeleteListOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2466,7 +2466,7 @@ "signature": [ "({ deserializer, serializer, type, listId, stream, meta, version, }: ", "ImportListItemsToStreamOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2502,7 +2502,7 @@ "signature": [ "({ listId, value, type, }: ", "GetListItemByValueOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2540,7 +2540,7 @@ "signature": [ "({ id, deserializer, serializer, listId, value, type, meta, }: ", "CreateListItemOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2576,7 +2576,7 @@ "signature": [ "({ _version, id, value, meta, }: ", "UpdateListItemOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2612,7 +2612,7 @@ "signature": [ "({ _version, id, name, description, meta, version, }: ", "UpdateListOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2648,7 +2648,7 @@ "signature": [ "({ id }: ", "GetListItemOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; } | null>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2686,7 +2686,7 @@ "signature": [ "({ type, listId, value, }: ", "GetListItemsByValueOptions", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]>" + ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2724,7 +2724,7 @@ "signature": [ "({ type, listId, value, }: ", "SearchListItemByValuesOptions", - ") => Promise<{ items: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]; value: unknown; }[]>" + ") => Promise<{ items: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]; value: unknown; }[]>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2762,7 +2762,7 @@ "signature": [ "({ filter, currentIndexPosition, perPage, page, sortField, sortOrder, searchAfter, runtimeMappings, }: ", "FindListOptions", - ") => Promise<{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }>" + ") => Promise<{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2800,7 +2800,7 @@ "signature": [ "({ listId, filter, currentIndexPosition, perPage, page, runtimeMappings, sortField, sortOrder, searchAfter, }: ", "FindListItemOptions", - ") => Promise<{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]; page: number; per_page: number; total: number; } | null>" + ") => Promise<{ cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]; page: number; per_page: number; total: number; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2836,7 +2836,7 @@ "signature": [ "({ listId, filter, sortField, sortOrder, }: ", "FindAllListItemsOptions", - ") => Promise<{ data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; updated_at: string; updated_by: string; value: string; }[]; total: number; } | null>" + ") => Promise<{ data: { _version: string | undefined; created_at: string; created_by: string; deserializer: string | undefined; id: string; list_id: string; meta: object | undefined; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; updated_at: string; updated_by: string; value: string; }[]; total: number; } | null>" ], "path": "x-pack/plugins/lists/server/services/lists/list_client.ts", "deprecated": false, @@ -2905,7 +2905,7 @@ "an array with the exception list item entries" ], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", "deprecated": false, @@ -3217,7 +3217,7 @@ "item exception entries logic" ], "signature": [ - "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" + "({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"byte\" | \"float\" | \"half_float\" | \"integer\" | \"double_range\" | \"float_range\" | \"integer_range\" | \"long_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]" ], "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts", "deprecated": false, @@ -4065,7 +4065,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -4073,8 +4073,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 54b954ea9229e..9c8b88b2b0493 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 906eabdcdd897..d953c84f35b5a 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: 2022-10-19 +date: 2022-10-23 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 2d8e9e32cab10..ee67d386557aa 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: 2022-10-19 +date: 2022-10-23 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 4b171399aed6f..0cabfca43e265 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.devdocs.json b/api_docs/ml.devdocs.json index 8e0baf14b5893..792bc38f914f3 100644 --- a/api_docs/ml.devdocs.json +++ b/api_docs/ml.devdocs.json @@ -1596,7 +1596,7 @@ "label": "ML_PAGES", "description": [], "signature": [ - "{ readonly ANOMALY_DETECTION_JOBS_MANAGE: \"jobs\"; readonly ANOMALY_EXPLORER: \"explorer\"; readonly SINGLE_METRIC_VIEWER: \"timeseriesexplorer\"; readonly DATA_FRAME_ANALYTICS_JOBS_MANAGE: \"data_frame_analytics\"; readonly DATA_FRAME_ANALYTICS_SOURCE_SELECTION: \"data_frame_analytics/source_selection\"; readonly DATA_FRAME_ANALYTICS_CREATE_JOB: \"data_frame_analytics/new_job\"; readonly TRAINED_MODELS_MANAGE: \"trained_models\"; readonly TRAINED_MODELS_NODES: \"trained_models/nodes\"; readonly DATA_FRAME_ANALYTICS_EXPLORATION: \"data_frame_analytics/exploration\"; readonly DATA_FRAME_ANALYTICS_MAP: \"data_frame_analytics/map\"; readonly DATA_VISUALIZER: \"datavisualizer\"; readonly DATA_VISUALIZER_INDEX_SELECT: \"datavisualizer_index_select\"; readonly DATA_VISUALIZER_FILE: \"filedatavisualizer\"; readonly DATA_VISUALIZER_INDEX_VIEWER: \"jobs/new_job/datavisualizer\"; readonly ANOMALY_DETECTION_CREATE_JOB: \"jobs/new_job\"; readonly ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER: \"jobs/new_job/recognize\"; readonly ANOMALY_DETECTION_CREATE_JOB_ADVANCED: \"jobs/new_job/advanced\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE: \"jobs/new_job/step/job_type\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX: \"jobs/new_job/step/index_or_search\"; readonly ANOMALY_DETECTION_CREATE_JOB_FROM_LENS: \"jobs/new_job/from_lens\"; readonly SETTINGS: \"settings\"; readonly CALENDARS_MANAGE: \"settings/calendars_list\"; readonly CALENDARS_NEW: \"settings/calendars_list/new_calendar\"; readonly CALENDARS_EDIT: \"settings/calendars_list/edit_calendar\"; readonly FILTER_LISTS_MANAGE: \"settings/filter_lists\"; readonly FILTER_LISTS_NEW: \"settings/filter_lists/new_filter_list\"; readonly FILTER_LISTS_EDIT: \"settings/filter_lists/edit_filter_list\"; readonly ACCESS_DENIED: \"access-denied\"; readonly OVERVIEW: \"overview\"; readonly NOTIFICATIONS: \"notifications\"; readonly AIOPS: \"aiops\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES: \"aiops/explain_log_rate_spikes\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT: \"aiops/explain_log_rate_spikes_index_select\"; readonly AIOPS_LOG_CATEGORIZATION: \"aiops/log_categorization\"; readonly AIOPS_LOG_CATEGORIZATION_INDEX_SELECT: \"aiops/log_categorization_index_select\"; }" + "{ readonly ANOMALY_DETECTION_JOBS_MANAGE: \"jobs\"; readonly ANOMALY_EXPLORER: \"explorer\"; readonly SINGLE_METRIC_VIEWER: \"timeseriesexplorer\"; readonly DATA_FRAME_ANALYTICS_JOBS_MANAGE: \"data_frame_analytics\"; readonly DATA_FRAME_ANALYTICS_SOURCE_SELECTION: \"data_frame_analytics/source_selection\"; readonly DATA_FRAME_ANALYTICS_CREATE_JOB: \"data_frame_analytics/new_job\"; readonly TRAINED_MODELS_MANAGE: \"trained_models\"; readonly TRAINED_MODELS_NODES: \"trained_models/nodes\"; readonly DATA_FRAME_ANALYTICS_EXPLORATION: \"data_frame_analytics/exploration\"; readonly DATA_FRAME_ANALYTICS_MAP: \"data_frame_analytics/map\"; readonly DATA_VISUALIZER: \"datavisualizer\"; readonly DATA_VISUALIZER_INDEX_SELECT: \"datavisualizer_index_select\"; readonly DATA_VISUALIZER_FILE: \"filedatavisualizer\"; readonly DATA_VISUALIZER_INDEX_VIEWER: \"jobs/new_job/datavisualizer\"; readonly ANOMALY_DETECTION_CREATE_JOB: \"jobs/new_job\"; readonly ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER: \"jobs/new_job/recognize\"; readonly ANOMALY_DETECTION_CREATE_JOB_SINGLE_METRIC: \"jobs/new_job/single_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_MULTI_METRIC: \"jobs/new_job/multi_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_CONVERT_TO_MULTI_METRIC: \"jobs/new_job/convert_to_multi_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_ADVANCED: \"jobs/new_job/advanced\"; readonly ANOMALY_DETECTION_CREATE_JOB_CONVERT_TO_ADVANCED: \"jobs/new_job/convert_to_advanced\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE: \"jobs/new_job/step/job_type\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX: \"jobs/new_job/step/index_or_search\"; readonly ANOMALY_DETECTION_CREATE_JOB_FROM_LENS: \"jobs/new_job/from_lens\"; readonly SETTINGS: \"settings\"; readonly CALENDARS_MANAGE: \"settings/calendars_list\"; readonly CALENDARS_NEW: \"settings/calendars_list/new_calendar\"; readonly CALENDARS_EDIT: \"settings/calendars_list/edit_calendar\"; readonly FILTER_LISTS_MANAGE: \"settings/filter_lists\"; readonly FILTER_LISTS_NEW: \"settings/filter_lists/new_filter_list\"; readonly FILTER_LISTS_EDIT: \"settings/filter_lists/edit_filter_list\"; readonly ACCESS_DENIED: \"access-denied\"; readonly OVERVIEW: \"overview\"; readonly NOTIFICATIONS: \"notifications\"; readonly AIOPS: \"aiops\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES: \"aiops/explain_log_rate_spikes\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT: \"aiops/explain_log_rate_spikes_index_select\"; readonly AIOPS_LOG_CATEGORIZATION: \"aiops/log_categorization\"; readonly AIOPS_LOG_CATEGORIZATION_INDEX_SELECT: \"aiops/log_categorization_index_select\"; }" ], "path": "x-pack/plugins/ml/common/constants/locator.ts", "deprecated": false, diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 4f64963ea6dae..87f9ddce7e770 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: 2022-10-19 +date: 2022-10-23 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 873ba69fc80ef..606db336574ab 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: 2022-10-19 +date: 2022-10-23 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 27ff5fe862bf8..18b18fd995f34 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: 2022-10-19 +date: 2022-10-23 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 f7a7d87fc8ff5..f06c62f742e60 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: 2022-10-19 +date: 2022-10-23 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 7ea70d18ebe4f..a91c2ecbba647 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index c1968f7c02049..2c64c1c5b973a 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -3752,6 +3752,26 @@ "path": "x-pack/plugins/observability/public/plugin.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-public.ObservabilityPublicPluginsStart.guidedOnboarding", + "type": "Object", + "tags": [], + "label": "guidedOnboarding", + "description": [], + "signature": [ + { + "pluginId": "guidedOnboarding", + "scope": "public", + "docId": "kibGuidedOnboardingPluginApi", + "section": "def-public.GuidedOnboardingPluginStart", + "text": "GuidedOnboardingPluginStart" + } + ], + "path": "x-pack/plugins/observability/public/plugin.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -6055,7 +6075,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -6063,8 +6083,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -7762,7 +7780,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; summary: { sli_value: number; error_budget: { initial: number; consumed: number; remaining: number; }; }; revision: number; created_at: Date; updated_at: Date; }, ", + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: string; objective: { target: number; } & { timeslice_target?: number | undefined; timeslice_window?: string | undefined; }; summary: { sli_value: number; error_budget: { initial: number; consumed: number; remaining: number; }; }; revision: number; created_at: string; updated_at: string; }, ", { "pluginId": "observability", "scope": "server", @@ -7865,18 +7883,46 @@ "<\"4xx\">, ", "LiteralC", "<\"5xx\">]>>; }>]>; }>]>; time_window: ", + "UnionC", + "<[", "TypeC", "<{ duration: ", - "StringC", - "; is_rolling: ", + "Type", + "<", + "Duration", + ", string, unknown>; is_rolling: ", + "LiteralC", + "; }>, ", + "TypeC", + "<{ duration: ", + "Type", + "<", + "Duration", + ", string, unknown>; calendar: ", + "TypeC", + "<{ start_time: ", + "Type", + "; }>; }>]>; budgeting_method: ", + "UnionC", + "<[", "LiteralC", - "; }>; budgeting_method: ", + ", ", "LiteralC", - "<\"occurrences\">; objective: ", + "]>; objective: ", + "IntersectionC", + "<[", "TypeC", "<{ target: ", "NumberC", - "; }>; }>; }>, ", + "; }>, ", + "PartialC", + "<{ timeslice_target: ", + "NumberC", + "; timeslice_window: ", + "Type", + "<", + "Duration", + ", string, unknown>; }>]>; }>; }>, ", { "pluginId": "observability", "scope": "server", @@ -7884,7 +7930,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; created_at: Date; updated_at: Date; }, ", + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: string; objective: { target: number; } & { timeslice_target?: number | undefined; timeslice_window?: string | undefined; }; created_at: string; updated_at: string; }, ", { "pluginId": "observability", "scope": "server", @@ -7983,18 +8029,46 @@ "<\"4xx\">, ", "LiteralC", "<\"5xx\">]>>; }>]>; }>]>; time_window: ", + "UnionC", + "<[", "TypeC", "<{ duration: ", - "StringC", - "; is_rolling: ", + "Type", + "<", + "Duration", + ", string, unknown>; is_rolling: ", "LiteralC", - "; }>; budgeting_method: ", + "; }>, ", + "TypeC", + "<{ duration: ", + "Type", + "<", + "Duration", + ", string, unknown>; calendar: ", + "TypeC", + "<{ start_time: ", + "Type", + "; }>; }>]>; budgeting_method: ", + "UnionC", + "<[", + "LiteralC", + ", ", "LiteralC", - "<\"occurrences\">; objective: ", + "]>; objective: ", + "IntersectionC", + "<[", "TypeC", "<{ target: ", "NumberC", - "; }>; }>; }>, ", + "; }>, ", + "PartialC", + "<{ timeslice_target: ", + "NumberC", + "; timeslice_window: ", + "Type", + "<", + "Duration", + ", string, unknown>; }>]>; }>; }>, ", { "pluginId": "observability", "scope": "server", @@ -8112,7 +8186,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; summary: { sli_value: number; error_budget: { initial: number; consumed: number; remaining: number; }; }; revision: number; created_at: Date; updated_at: Date; }, ", + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: string; objective: { target: number; } & { timeslice_target?: number | undefined; timeslice_window?: string | undefined; }; summary: { sli_value: number; error_budget: { initial: number; consumed: number; remaining: number; }; }; revision: number; created_at: string; updated_at: string; }, ", { "pluginId": "observability", "scope": "server", @@ -8215,18 +8289,46 @@ "<\"4xx\">, ", "LiteralC", "<\"5xx\">]>>; }>]>; }>]>; time_window: ", + "UnionC", + "<[", "TypeC", "<{ duration: ", - "StringC", - "; is_rolling: ", + "Type", + "<", + "Duration", + ", string, unknown>; is_rolling: ", + "LiteralC", + "; }>, ", + "TypeC", + "<{ duration: ", + "Type", + "<", + "Duration", + ", string, unknown>; calendar: ", + "TypeC", + "<{ start_time: ", + "Type", + "; }>; }>]>; budgeting_method: ", + "UnionC", + "<[", "LiteralC", - "; }>; budgeting_method: ", + ", ", "LiteralC", - "<\"occurrences\">; objective: ", + "]>; objective: ", + "IntersectionC", + "<[", "TypeC", "<{ target: ", "NumberC", - "; }>; }>; }>, ", + "; }>, ", + "PartialC", + "<{ timeslice_target: ", + "NumberC", + "; timeslice_window: ", + "Type", + "<", + "Duration", + ", string, unknown>; }>]>; }>; }>, ", { "pluginId": "observability", "scope": "server", @@ -8234,7 +8336,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; created_at: Date; updated_at: Date; }, ", + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: string; objective: { target: number; } & { timeslice_target?: number | undefined; timeslice_window?: string | undefined; }; created_at: string; updated_at: string; }, ", { "pluginId": "observability", "scope": "server", @@ -8333,18 +8435,46 @@ "<\"4xx\">, ", "LiteralC", "<\"5xx\">]>>; }>]>; }>]>; time_window: ", + "UnionC", + "<[", "TypeC", "<{ duration: ", - "StringC", - "; is_rolling: ", + "Type", + "<", + "Duration", + ", string, unknown>; is_rolling: ", "LiteralC", - "; }>; budgeting_method: ", + "; }>, ", + "TypeC", + "<{ duration: ", + "Type", + "<", + "Duration", + ", string, unknown>; calendar: ", + "TypeC", + "<{ start_time: ", + "Type", + "; }>; }>]>; budgeting_method: ", + "UnionC", + "<[", "LiteralC", - "<\"occurrences\">; objective: ", + ", ", + "LiteralC", + "]>; objective: ", + "IntersectionC", + "<[", "TypeC", "<{ target: ", "NumberC", - "; }>; }>; }>, ", + "; }>, ", + "PartialC", + "<{ timeslice_target: ", + "NumberC", + "; timeslice_window: ", + "Type", + "<", + "Duration", + ", string, unknown>; }>]>; }>; }>, ", { "pluginId": "observability", "scope": "server", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 01b55c0e99a52..e3ea81176c424 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Observability UI](https://github.com/orgs/elastic/teams/observability-u | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 539 | 2 | 535 | 30 | +| 540 | 2 | 536 | 31 | ## Client diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 0f58e1cef0937..a7901d5726b45 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 2b102646af5b3..3c9ede3d2d276 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: 2022-10-19 +date: 2022-10-23 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 | |--------------|----------|------------------------| -| 493 | 409 | 38 | +| 497 | 412 | 38 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 32549 | 179 | 21883 | 1029 | +| 32648 | 179 | 21947 | 1032 | ## Plugin Directory @@ -31,7 +31,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 1 | 32 | 2 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 9 | 0 | 0 | 2 | | | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 382 | 0 | 373 | 24 | -| | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 38 | 0 | 38 | 52 | +| | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 38 | 0 | 38 | 53 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 9 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 81 | 1 | 72 | 2 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | @@ -41,20 +41,21 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 1 | 0 | 0 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/@elastic/kibana-core) | Provides the necessary APIs to implement A/B testing scenarios, fetching the variations in configuration and reporting back metrics to track conversion rates of the experiments. | 12 | 0 | 0 | 0 | | cloudFullStory | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | When Kibana runs on Elastic Cloud, this plugin registers FullStory as a shipper for telemetry. | 0 | 0 | 0 | 0 | +| cloudGainsight | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | When Kibana runs on Elastic Cloud, this plugin registers Gainsight as a shipper for telemetry. | 0 | 0 | 0 | 0 | | cloudLinks | [Kibana Core](https://github.com/orgs/elastic/teams/@kibana-core) | Adds the links to the Elastic Cloud console | 0 | 0 | 0 | 0 | | | [Cloud Security Posture](https://github.com/orgs/elastic/teams/cloud-posture-security) | The cloud security posture plugin | 18 | 0 | 2 | 3 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 13 | 0 | 13 | 1 | -| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 213 | 0 | 205 | 7 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2691 | 0 | 23 | 0 | +| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 229 | 0 | 220 | 7 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2697 | 0 | 23 | 0 | | crossClusterReplication | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 107 | 0 | 88 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 121 | 0 | 114 | 3 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 52 | 0 | 51 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | 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. | 3242 | 33 | 2516 | 24 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | 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. | 3245 | 33 | 2517 | 24 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 16 | 0 | 7 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Reusable data view field editor across Kibana | 60 | 0 | 30 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data view management app | 2 | 0 | 2 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | 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. | 1020 | 0 | 229 | 2 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | 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. | 1021 | 0 | 229 | 2 | | | [Machine Learning 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. | 28 | 3 | 24 | 1 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 10 | 0 | 8 | 2 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 97 | 0 | 80 | 4 | @@ -90,7 +91,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | globalSearchProviders | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | graph | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 0 | 0 | 0 | 0 | | grokdebugger | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | Guided onboarding framework | 19 | 0 | 19 | 3 | +| | [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | Guided onboarding framework | 36 | 0 | 36 | 1 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 143 | 0 | 104 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 4 | 0 | 4 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 177 | 0 | 172 | 3 | @@ -118,7 +119,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Stack Monitoring](https://github.com/orgs/elastic/teams/stack-monitoring-ui) | - | 9 | 0 | 9 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 34 | 0 | 34 | 2 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | -| | [Observability UI](https://github.com/orgs/elastic/teams/observability-ui) | - | 539 | 2 | 535 | 30 | +| | [Observability UI](https://github.com/orgs/elastic/teams/observability-ui) | - | 540 | 2 | 536 | 31 | | | [Security asset management](https://github.com/orgs/elastic/teams/security-asset-management) | - | 21 | 0 | 21 | 3 | | painlessLab | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [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). | 243 | 2 | 187 | 12 | @@ -137,7 +138,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 32 | 0 | 13 | 0 | | | [Kibana Reporting Services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 27 | 0 | 8 | 4 | | searchprofiler | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 249 | 0 | 90 | 0 | +| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 250 | 0 | 90 | 0 | | | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 112 | 0 | 75 | 26 | | | [Security Team](https://github.com/orgs/elastic/teams/security-team) | - | 7 | 0 | 7 | 1 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds URL Service and sharing capabilities to Kibana | 115 | 0 | 56 | 10 | @@ -160,7 +161,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Extends UI Actions plugin with more functionality | 206 | 0 | 142 | 9 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list which can be integrated into apps | 122 | 0 | 117 | 2 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 56 | 0 | 29 | 0 | -| | [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-services) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 131 | 2 | 104 | 17 | +| | [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-services) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 131 | 2 | 104 | 18 | | upgradeAssistant | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | urlDrilldown | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds drilldown implementations to Kibana | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 12 | 0 | 12 | 0 | @@ -196,6 +197,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 23 | 0 | 0 | 0 | | | Kibana Core | - | 18 | 0 | 0 | 0 | | | Kibana Core | - | 20 | 0 | 0 | 0 | +| | Kibana Core | - | 17 | 0 | 2 | 0 | | | [Owner missing] | - | 16 | 0 | 16 | 0 | | | [Owner missing] | Elastic APM trace data generator | 74 | 0 | 74 | 13 | | | [Owner missing] | - | 11 | 0 | 11 | 0 | @@ -267,7 +269,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 4 | 0 | 0 | 0 | | | Kibana Core | - | 10 | 1 | 10 | 0 | | | Kibana Core | - | 14 | 0 | 11 | 0 | -| | [Owner missing] | - | 20 | 0 | 6 | 0 | +| | [Owner missing] | - | 22 | 0 | 7 | 0 | | | [Owner missing] | - | 9 | 0 | 9 | 3 | | | Kibana Core | - | 7 | 0 | 7 | 0 | | | Kibana Core | - | 25 | 5 | 25 | 1 | @@ -311,7 +313,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 2 | 0 | 2 | 0 | | | Kibana Core | - | 2 | 0 | 2 | 0 | | | Kibana Core | - | 4 | 0 | 4 | 1 | -| | Kibana Core | - | 106 | 1 | 75 | 0 | +| | Kibana Core | - | 107 | 1 | 76 | 0 | | | Kibana Core | - | 310 | 1 | 137 | 0 | | | Kibana Core | - | 71 | 0 | 51 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | @@ -320,12 +322,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 2 | 0 | 1 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | | | Kibana Core | - | 7 | 0 | 7 | 0 | -| | Kibana Core | - | 82 | 0 | 41 | 0 | +| | Kibana Core | - | 83 | 0 | 41 | 0 | | | Kibana Core | - | 25 | 0 | 23 | 0 | | | Kibana Core | - | 4 | 0 | 4 | 0 | | | Kibana Core | - | 100 | 0 | 74 | 43 | | | Kibana Core | - | 12 | 0 | 12 | 0 | -| | Kibana Core | - | 225 | 0 | 82 | 0 | +| | Kibana Core | - | 226 | 0 | 83 | 0 | | | Kibana Core | - | 69 | 0 | 69 | 4 | | | Kibana Core | - | 14 | 0 | 13 | 0 | | | Kibana Core | - | 99 | 1 | 86 | 0 | @@ -371,6 +373,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | - | 28 | 0 | 28 | 2 | | | [Owner missing] | - | 1 | 0 | 0 | 0 | | | [Owner missing] | - | 3 | 0 | 0 | 0 | +| | [Owner missing] | - | 17 | 0 | 17 | 2 | | | [Owner missing] | - | 6 | 0 | 0 | 0 | | | [Owner missing] | - | 3 | 0 | 3 | 0 | | | [Owner missing] | - | 32 | 0 | 22 | 0 | @@ -382,6 +385,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | - | 13 | 0 | 13 | 0 | | | [Owner missing] | - | 64 | 0 | 59 | 5 | | | [Owner missing] | - | 96 | 0 | 95 | 0 | +| | [Owner missing] | - | 7 | 0 | 5 | 0 | | | Kibana Core | - | 30 | 0 | 5 | 37 | | | Kibana Core | - | 8 | 0 | 8 | 0 | | | [Owner missing] | - | 6 | 0 | 1 | 1 | @@ -401,16 +405,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | - | 75 | 0 | 72 | 0 | | | [Owner missing] | Security Solution auto complete | 56 | 1 | 41 | 1 | | | [Owner missing] | security solution elastic search utilities to use across plugins such lists, security_solution, cases, etc... | 67 | 0 | 61 | 1 | -| | [Owner missing] | - | 76 | 0 | 67 | 1 | +| | [Owner missing] | - | 89 | 0 | 78 | 1 | | | [Owner missing] | Security Solution utilities for React hooks | 15 | 0 | 7 | 0 | -| | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 145 | 0 | 127 | 0 | +| | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 138 | 0 | 119 | 0 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 505 | 1 | 492 | 0 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 65 | 0 | 36 | 0 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 28 | 0 | 21 | 0 | | | [Owner missing] | security solution list REST API | 67 | 0 | 64 | 0 | | | [Owner missing] | security solution list constants to use across plugins such lists, security_solution, cases, etc... | 33 | 0 | 17 | 0 | | | [Owner missing] | Security solution list ReactJS hooks | 58 | 0 | 47 | 0 | -| | [Owner missing] | security solution list utilities | 192 | 0 | 150 | 0 | +| | [Owner missing] | security solution list utilities | 194 | 0 | 150 | 0 | | | [Owner missing] | security solution rule utilities to use across plugins | 26 | 0 | 23 | 0 | | | [Owner missing] | security solution t-grid packages will allow sharing components between timelines and security_solution plugin until we transfer all functionality to timelines plugin | 120 | 0 | 116 | 0 | | | [Owner missing] | security solution utilities to use across plugins such lists, security_solution, cases, etc... | 31 | 0 | 29 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index dd2707a4c4da8..2817584cfc308 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: 2022-10-19 +date: 2022-10-23 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 3e14b95943290..2d942603a131c 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index e5af21cb90573..f077ea710b8a4 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: 2022-10-19 +date: 2022-10-23 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 8af0fd0474771..fc06e20e3997f 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: 2022-10-19 +date: 2022-10-23 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 5c003c78b1d3d..3950fb8b362e6 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.devdocs.json b/api_docs/rule_registry.devdocs.json index 942341236243f..868760ba33262 100644 --- a/api_docs/rule_registry.devdocs.json +++ b/api_docs/rule_registry.devdocs.json @@ -203,7 +203,9 @@ "SortOptions", "[] | undefined; search_after?: (string | number)[] | undefined; }) => Promise<", "SearchResponse", - ">, unknown>>" + ">, Record>>" ], "path": "x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts", "deprecated": false, @@ -1864,7 +1866,7 @@ { "parentPluginId": "ruleRegistry", "id": "def-server.ComponentTemplateOptions.settings", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "settings", "description": [], @@ -3374,7 +3376,9 @@ "signature": [ "{ phases: ", "IlmPhases", - "; }" + "; _meta?: ", + "Metadata", + " | undefined; }" ], "path": "x-pack/plugins/rule_registry/server/rule_data_plugin_service/index_options.ts", "deprecated": false, @@ -3705,7 +3709,8 @@ "label": "Settings", "description": [], "signature": [ - "IndicesIndexSettings" + "IndicesIndexSettingsKeys", + " & { [property: string]: any; }" ], "path": "x-pack/plugins/rule_registry/server/rule_data_plugin_service/index_options.ts", "deprecated": false, diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 673945319f913..f854d8c8b6329 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: 2022-10-19 +date: 2022-10-23 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 19ea40efd2ac3..87433aa6119c4 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: 2022-10-19 +date: 2022-10-23 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 32fb3d347301d..bc85c9f029ac1 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: 2022-10-19 +date: 2022-10-23 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 d0c7c83f8a0eb..cca8826598ad7 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: 2022-10-19 +date: 2022-10-23 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 86639506ff508..b8bef8c983ca4 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: 2022-10-19 +date: 2022-10-23 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 8a4f8cdb17e62..f4a09ff9fd32e 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: 2022-10-19 +date: 2022-10-23 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 59124cb48080f..e264346fc0866 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: 2022-10-19 +date: 2022-10-23 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 25476116ca262..ac2a4930e8d7e 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: 2022-10-19 +date: 2022-10-23 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 f3866a7560795..f3328ffbc7e76 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: 2022-10-19 +date: 2022-10-23 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 bca4567429078..dcc2c3005cc9c 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index b913d81e4e55a..331e2d40aeb93 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -2366,6 +2366,25 @@ "description": [ "\nQuery string used to match name-related fields in user profiles. The following fields are treated as\nname-related: username, full_name and email." ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.UserProfileSuggestParams.hint", + "type": "Object", + "tags": [], + "label": "hint", + "description": [ + "\nExtra search criteria to improve relevance of the suggestion result. A profile matching the\nspecified hint is ranked higher in the response. But not-matching the hint does not exclude a\nprofile from the response as long as it matches the `name` field query." + ], + "signature": [ + "{ uids: string[]; } | undefined" + ], "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false @@ -2565,6 +2584,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/request_context_factory.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts" @@ -2581,10 +2604,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts" - }, { "plugin": "cloudChat", "path": "x-pack/plugins/cloud_integrations/cloud_chat/server/routes/chat.ts" diff --git a/api_docs/security.mdx b/api_docs/security.mdx index cd715de566055..9dd0045076513 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Platform Security](https://github.com/orgs/elastic/teams/kibana-securit | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 249 | 0 | 90 | 0 | +| 250 | 0 | 90 | 0 | ## Client diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index f59a44e9b79e4..c362de021f944 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 72cb87eed8544..e052a43c45be5 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: 2022-10-19 +date: 2022-10-23 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 b33e5cc0f9ce1..ea5d26d27f557 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: 2022-10-19 +date: 2022-10-23 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 a9d81fcde7492..fed0ab667bedf 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: 2022-10-19 +date: 2022-10-23 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 dbf8180ecffa7..3795e884590c5 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: 2022-10-19 +date: 2022-10-23 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 8948d8bc632ea..e2538aaa3ebe6 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: 2022-10-19 +date: 2022-10-23 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 e04491a1932ac..de74adf08ce25 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: 2022-10-19 +date: 2022-10-23 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 a2b1be5425a76..7a1dfa0700cf8 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: 2022-10-19 +date: 2022-10-23 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 22f35ef376951..f2a5ff0b81e79 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.devdocs.json b/api_docs/telemetry_collection_manager.devdocs.json index efd0378614ce7..b54d4ad1f0e44 100644 --- a/api_docs/telemetry_collection_manager.devdocs.json +++ b/api_docs/telemetry_collection_manager.devdocs.json @@ -248,7 +248,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -256,8 +256,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index ee1621378d88a..a11b2b52db7c4 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: 2022-10-19 +date: 2022-10-23 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 257805f17246c..2097a1c3e8ba0 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: 2022-10-19 +date: 2022-10-23 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 ae6d176000ede..32e1342c90926 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index dfa258fbd99fa..24ff291a86d8b 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.devdocs.json b/api_docs/timelines.devdocs.json index 8bc17ee8d463f..5d590998cb26b 100644 --- a/api_docs/timelines.devdocs.json +++ b/api_docs/timelines.devdocs.json @@ -2490,7 +2490,7 @@ "label": "useBulkActionItems", "description": [], "signature": [ - "({ eventIds, currentStatus, query, indexName, setEventsLoading, showAlertStatusActions, setEventsDeleted, onUpdateSuccess, onUpdateFailure, customBulkActions, scopeId, }: ", + "({ eventIds, currentStatus, query, indexName, setEventsLoading, showAlertStatusActions, setEventsDeleted, onUpdateSuccess, onUpdateFailure, customBulkActions, }: ", "BulkActionsProps", ") => JSX.Element[]" ], @@ -2503,7 +2503,7 @@ "id": "def-public.useBulkActionItems.$1", "type": "Object", "tags": [], - "label": "{\n eventIds,\n currentStatus,\n query,\n indexName,\n setEventsLoading,\n showAlertStatusActions = true,\n setEventsDeleted,\n onUpdateSuccess,\n onUpdateFailure,\n customBulkActions,\n scopeId,\n}", + "label": "{\n eventIds,\n currentStatus,\n query,\n indexName,\n setEventsLoading,\n showAlertStatusActions = true,\n setEventsDeleted,\n onUpdateSuccess,\n onUpdateFailure,\n customBulkActions,\n}", "description": [], "signature": [ "BulkActionsProps" @@ -3222,7 +3222,7 @@ }, "; description?: string | null | undefined; esTypes?: string[] | undefined; example?: string | number | null | undefined; format?: string | undefined; linkField?: string | undefined; placeholder?: string | undefined; subType?: ", "IFieldSubType", - " | undefined; type?: string | undefined; })[]; readonly filters?: ", + " | undefined; type?: string | undefined; })[]; readonly title?: string | undefined; readonly filters?: ", "Filter", "[] | undefined; readonly dataViewId: string | null; readonly sort: ", "SortColumnTable", @@ -3269,7 +3269,7 @@ "label": "TGridType", "description": [], "signature": [ - "\"standalone\" | \"embedded\"" + "\"embedded\"" ], "path": "x-pack/plugins/timelines/public/types.ts", "deprecated": false, @@ -3347,15 +3347,7 @@ "label": "getTGrid", "description": [], "signature": [ - "(props: ", + "(props: ", "GetTGridProps", ") => React.ReactElement<", "GetTGridProps", diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 4f0f054fc8703..c6ba557ad75b4 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: 2022-10-19 +date: 2022-10-23 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 4247cd40eb244..6a62bd2dbb1e7 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: 2022-10-19 +date: 2022-10-23 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 5c6bfd7a463ab..fe3de3ca51588 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: 2022-10-19 +date: 2022-10-23 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 9427ece2e770f..1d5707bb9c94e 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: 2022-10-19 +date: 2022-10-23 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 9718c1fb28cd0..6e615773f1bb7 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_field_list.mdx b/api_docs/unified_field_list.mdx index 894199f5f0a7f..1ce9db4fb9b08 100644 --- a/api_docs/unified_field_list.mdx +++ b/api_docs/unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedFieldList title: "unifiedFieldList" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedFieldList plugin -date: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedFieldList'] --- import unifiedFieldListObj from './unified_field_list.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index a19de855e0886..c78a91a57cf14 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.devdocs.json b/api_docs/unified_search.devdocs.json index 436b928a40233..8f42fc8d88284 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -1229,6 +1229,8 @@ "section": "def-common.DataView", "text": "DataView" }, + " | ", + "DataViewByIdOrTitle", ")[]" ], "path": "src/plugins/unified_search/public/query_string_input/query_string_input.tsx", diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index b0e81791f1a18..a438a666d72df 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-servic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 131 | 2 | 104 | 17 | +| 131 | 2 | 104 | 18 | ## Client diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 1b47fd24f38b9..fcb180359ef3e 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-servic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 131 | 2 | 104 | 17 | +| 131 | 2 | 104 | 18 | ## Client diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index d1603742c74a6..f10cace8b0110 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.devdocs.json b/api_docs/usage_collection.devdocs.json index 046c83b0d64c7..c7453333a13fd 100644 --- a/api_docs/usage_collection.devdocs.json +++ b/api_docs/usage_collection.devdocs.json @@ -517,7 +517,7 @@ "UpdateResponse", ">; }; asyncSearch: ", "default", - "; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; helpers: ", "default", @@ -525,8 +525,6 @@ "ClientOptions", ") => ", "default", - "; Internal: ", - "default", "; autoscaling: ", "default", "; bulk: { (this: That, params: ", @@ -1894,7 +1892,7 @@ "\nPossible type values in the schema" ], "signature": [ - "\"boolean\" | \"date\" | \"keyword\" | \"text\" | \"long\" | \"double\" | \"short\" | \"float\" | \"integer\" | \"byte\"" + "\"boolean\" | \"date\" | \"keyword\" | \"text\" | \"long\" | \"double\" | \"short\" | \"byte\" | \"float\" | \"integer\"" ], "path": "node_modules/@types/kbn__analytics-client/index.d.ts", "deprecated": false, diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 304c8df372a37..1f461323c6e0e 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: 2022-10-19 +date: 2022-10-23 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 f72276d0b9bcb..d6a3e6264fe61 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: 2022-10-19 +date: 2022-10-23 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 bbcb7f83f2523..86f551c91b11f 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: 2022-10-19 +date: 2022-10-23 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 b76401399cd01..f0d8ee3d77bf7 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: 2022-10-19 +date: 2022-10-23 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 6d01800894fc9..01211b0da185b 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: 2022-10-19 +date: 2022-10-23 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 17b4d766a9b8d..bb7dada491fae 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: 2022-10-19 +date: 2022-10-23 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 0f1eb9bfb9329..e5deb4cbcb921 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: 2022-10-19 +date: 2022-10-23 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 2038e0c5dae77..4572b32761992 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: 2022-10-19 +date: 2022-10-23 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 36aa6d663066e..43ab58bdba7d9 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: 2022-10-19 +date: 2022-10-23 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 f79a60f99086a..2c41bfcf34e90 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: 2022-10-19 +date: 2022-10-23 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 cf1eab7eb1c06..49c539c82f1c4 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: 2022-10-19 +date: 2022-10-23 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 2c325393e5bc5..18852cdbe3436 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: 2022-10-19 +date: 2022-10-23 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 447aef1cace5f..bdde2f476bfcf 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: 2022-10-19 +date: 2022-10-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/docs/api-generated/cases/case-apis-passthru.asciidoc b/docs/api-generated/cases/case-apis-passthru.asciidoc index d10933c5b0a9c..2ccee8484b882 100644 --- a/docs/api-generated/cases/case-apis-passthru.asciidoc +++ b/docs/api-generated/cases/case-apis-passthru.asciidoc @@ -87,6 +87,11 @@ Any modifications made to this file will be overwritten. "totalAlerts" : 0, "closed_at" : "2000-01-23T04:56:07.000+00:00", "comments" : [ null, null ], + "assignees" : [ { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + }, { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } ], "created_at" : "2022-05-13T09:16:17.416Z", "description" : "A case description.", "title" : "Case title 1", @@ -199,6 +204,11 @@ Any modifications made to this file will be overwritten. "totalAlerts" : 0, "closed_at" : "2000-01-23T04:56:07.000+00:00", "comments" : [ null, null ], + "assignees" : [ { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + }, { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } ], "created_at" : "2022-05-13T09:16:17.416Z", "description" : "A case description.", "title" : "Case title 1", @@ -376,6 +386,11 @@ Any modifications made to this file will be overwritten. "totalAlerts" : 0, "closed_at" : "2000-01-23T04:56:07.000+00:00", "comments" : [ null, null ], + "assignees" : [ { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + }, { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } ], "created_at" : "2022-05-13T09:16:17.416Z", "description" : "A case description.", "title" : "Case title 1", @@ -488,6 +503,11 @@ Any modifications made to this file will be overwritten. "totalAlerts" : 0, "closed_at" : "2000-01-23T04:56:07.000+00:00", "comments" : [ null, null ], + "assignees" : [ { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + }, { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } ], "created_at" : "2022-05-13T09:16:17.416Z", "description" : "A case description.", "title" : "Case title 1", @@ -602,6 +622,11 @@ Any modifications made to this file will be overwritten. "totalAlerts" : 0, "closed_at" : "2000-01-23T04:56:07.000+00:00", "comments" : [ null, null ], + "assignees" : [ { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + }, { + "uid" : "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } ], "created_at" : "2022-05-13T09:16:17.416Z", "description" : "A case description.", "title" : "Case title 1", @@ -677,6 +702,7 @@ Any modifications made to this file will be overwritten.
  • case_response_closed_by_properties - Case response properties for closed_by
  • case_response_created_by_properties - Case response properties for created_by
  • case_response_properties - Case response properties
  • +
  • case_response_properties_assignees_inner -
  • case_response_pushed_by_properties - Case response properties for pushed_by
  • case_response_updated_by_properties - Case response properties for updated_by
  • connector_properties_cases_webhook - Create or upate case request properties for Cases Webhook connector
  • @@ -692,6 +718,7 @@ Any modifications made to this file will be overwritten.
  • connector_properties_swimlane - Create case request properties for a Swimlane connector
  • connector_properties_swimlane_fields -
  • create_case_request - Create case request
  • +
  • create_case_request_assignees_inner -
  • create_case_request_connector -
  • external_service -
  • owners -
  • @@ -864,7 +891,8 @@ Any modifications made to this file will be overwritten.

    case_response_properties - Case response properties Up

    -
    closed_at
    Date format: date-time
    +
    assignees (optional)
    array[case_response_properties_assignees_inner] An array containing users that are assigned to the case.
    +
    closed_at
    Date format: date-time
    closed_by
    comments
    array[Case_response_properties_for_comments_inner] An array of comment objects for the case.
    connector
    @@ -887,6 +915,13 @@ Any modifications made to this file will be overwritten.
    version
    +
    +

    case_response_properties_assignees_inner - Up

    +
    +
    +
    uid
    String A unique identifier for the user profile. You can use the get user profile API to retrieve more details.
    +
    +

    case_response_pushed_by_properties - Case response properties for pushed_by Up

    @@ -1043,7 +1078,8 @@ Any modifications made to this file will be overwritten.

    create_case_request - Create case request Up

    The create case API request body varies depending on the type of connector.
    -
    connector
    +
    assignees (optional)
    array[create_case_request_assignees_inner] An array containing users that are assigned to the case.
    +
    connector
    description
    String The description for the case.
    owner
    settings
    @@ -1052,6 +1088,13 @@ Any modifications made to this file will be overwritten.
    title
    String A title for the case.
    +
    +

    create_case_request_assignees_inner - Up

    +
    +
    +
    uid
    String A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API.
    +
    +

    create_case_request_connector - Up

    @@ -1152,7 +1195,8 @@ Any modifications made to this file will be overwritten.

    update_case_request_cases_inner - Up

    -
    connector (optional)
    +
    assignees (optional)
    array[create_case_request_assignees_inner] An array containing users that are assigned to the case.
    +
    connector (optional)
    description (optional)
    String An updated description for the case.
    id
    String The identifier for the case.
    settings (optional)
    diff --git a/docs/api/cases/cases-api-create.asciidoc b/docs/api/cases/cases-api-create.asciidoc index 5eec612d8bfca..f124d3500228c 100644 --- a/docs/api/cases/cases-api-create.asciidoc +++ b/docs/api/cases/cases-api-create.asciidoc @@ -34,6 +34,18 @@ default space is used. [role="child_attributes"] === {api-request-body-title} +`assignees`:: +(Optional, array of objects) Array containing users that are assigned to the case. ++ +.Properties of assignee objects +[%collapsible%open] +===== +`uid`:: +(Required, string) A unique identifier for the user profile. These identifiers +can be found by using the +{ref}/security-api-suggest-user-profile.html[suggest user profile API]. +===== + `connector`:: (Required, object) An object that contains the connector configuration. + @@ -207,6 +219,7 @@ the case identifier, version, and creation time. For example: "totalAlerts": 0, "title": "Case title 1", "tags": [ "tag 1" ], + "assignees": [], "settings": { "syncAlerts": true }, diff --git a/docs/api/cases/cases-api-find-cases.asciidoc b/docs/api/cases/cases-api-find-cases.asciidoc index d7ae5fed35b0f..770e1d30ee594 100644 --- a/docs/api/cases/cases-api-find-cases.asciidoc +++ b/docs/api/cases/cases-api-find-cases.asciidoc @@ -141,6 +141,7 @@ The API returns a JSON object listing the retrieved cases. For example: "full_name": "Joe Smith", "username": "jsmith" }, + "assignees": [], "connector": { "id": "none", "name": "none", diff --git a/docs/api/cases/cases-api-get-case.asciidoc b/docs/api/cases/cases-api-get-case.asciidoc index d7bc316a7346d..9d43afb695a79 100644 --- a/docs/api/cases/cases-api-get-case.asciidoc +++ b/docs/api/cases/cases-api-get-case.asciidoc @@ -86,6 +86,7 @@ The API returns a JSON object with the retrieved case. For example: "status":"open", "updated_at":"2022-07-13T15:40:32.335Z", "updated_by":{"full_name":null,"email":null,"username":"elastic"}, + "assignees":[{"uid":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"}], "connector":{"id":"none","name":"none","type":".none","fields":null}, "external_service":null } diff --git a/docs/api/cases/cases-api-update.asciidoc b/docs/api/cases/cases-api-update.asciidoc index 30c482da4282c..ca75e34597afc 100644 --- a/docs/api/cases/cases-api-update.asciidoc +++ b/docs/api/cases/cases-api-update.asciidoc @@ -40,6 +40,19 @@ default space is used. .Properties of `cases` objects [%collapsible%open] ==== + +`assignees`:: +(Optional, array of objects) Array containing users that are assigned to the case. ++ +.Properties of assignee objects +[%collapsible%open] +===== +`uid`:: +(Required, string) A unique identifier for the user profile. These identifiers +can be found by using the +{ref}/security-api-suggest-user-profile.html[suggest user profile API]. +===== + `connector`:: (Optional, object) An object that contains the connector configuration. + @@ -203,6 +216,7 @@ PATCH api/cases }, "description": "A new description.", "tags": [ "tag-1", "tag-2" ], + "assignees": [], "settings": { "syncAlerts": true } diff --git a/docs/settings/reporting-settings.asciidoc b/docs/settings/reporting-settings.asciidoc index afdfbdfd02eb0..90ea49fd281fe 100644 --- a/docs/settings/reporting-settings.asciidoc +++ b/docs/settings/reporting-settings.asciidoc @@ -83,7 +83,9 @@ security is enabled, < { error: SavedObjectType['error']; references: SavedObjectType['references']; updatedAt: SavedObjectType['updated_at']; + createdAt: SavedObjectType['created_at']; /** * Space(s) that this saved object exists in. This attribute is not used for "global" saved object types which are registered with * `namespaceType: 'agnostic'`. diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.test.ts index 51c431b1c6b3b..279b73aced837 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.test.ts @@ -20,6 +20,7 @@ describe('getRootFields', () => { "migrationVersion", "coreMigrationVersion", "updated_at", + "created_at", "originId", ] `); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.ts index 9613d8f6a4a41..55e68c84da512 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/included_fields.ts @@ -18,6 +18,7 @@ const ROOT_FIELDS = [ 'migrationVersion', 'coreMigrationVersion', 'updated_at', + 'created_at', 'originId', ]; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/internal_utils.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/internal_utils.ts index cbe209012ff1a..73134f4855a37 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/internal_utils.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/internal_utils.ts @@ -131,7 +131,7 @@ export function getSavedObjectFromSource( id: string, doc: { _seq_no?: number; _primary_term?: number; _source: SavedObjectsRawDocSource } ): SavedObject { - const { originId, updated_at: updatedAt } = doc._source; + const { originId, updated_at: updatedAt, created_at: createdAt } = doc._source; let namespaces: string[] = []; if (!registry.isNamespaceAgnostic(type)) { @@ -146,6 +146,7 @@ export function getSavedObjectFromSource( namespaces, ...(originId && { originId }), ...(updatedAt && { updated_at: updatedAt }), + ...(createdAt && { created_at: createdAt }), version: encodeHitVersion(doc), attributes: doc._source[type], references: doc._source.references || [], diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts index d5b2ed6874338..8c0690bfdf4fd 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts @@ -112,6 +112,7 @@ describe('SavedObjectsRepository', () => { const mockTimestamp = '2017-08-14T15:49:14.886Z'; const mockTimestampFields = { updated_at: mockTimestamp }; + const mockTimestampFieldsWithCreated = { updated_at: mockTimestamp, created_at: mockTimestamp }; const mockVersionProps = { _seq_no: 1, _primary_term: 1 }; const mockVersion = encodeHitVersion(mockVersionProps); @@ -454,7 +455,7 @@ describe('SavedObjectsRepository', () => { namespace, ...(originId && { originId }), references, - ...mockTimestampFields, + ...mockTimestampFieldsWithCreated, migrationVersion: migrationVersion || { [type]: '1.1.1' }, }, ...mockVersionProps, @@ -528,7 +529,7 @@ describe('SavedObjectsRepository', () => { coreMigrationVersion: KIBANA_VERSION, version: mockVersion, namespaces: obj.namespaces ?? [obj.namespace ?? 'default'], - ...mockTimestampFields, + ...mockTimestampFieldsWithCreated, }); describe('client calls', () => { @@ -1089,7 +1090,7 @@ describe('SavedObjectsRepository', () => { migrator.migrateDocument.mockImplementation(mockMigrateDocument); const modifiedObj1 = { ...obj1, coreMigrationVersion: '8.0.0' }; await bulkCreateSuccess([modifiedObj1, obj2]); - const docs = [modifiedObj1, obj2].map((x) => ({ ...x, ...mockTimestampFields })); + const docs = [modifiedObj1, obj2].map((x) => ({ ...x, ...mockTimestampFieldsWithCreated })); expectMigrationArgs(docs[0], true, 1); expectMigrationArgs(docs[1], true, 2); @@ -1440,6 +1441,7 @@ describe('SavedObjectsRepository', () => { namespaces: doc._source!.namespaces ?? ['default'], ...(doc._source!.originId && { originId: doc._source!.originId }), ...(doc._source!.updated_at && { updated_at: doc._source!.updated_at }), + ...(doc._source!.created_at && { created_at: doc._source!.created_at }), version: encodeHitVersion(doc), attributes: doc._source![type], references: doc._source!.references || [], @@ -3233,7 +3235,7 @@ describe('SavedObjectsRepository', () => { references, migrationVersion, coreMigrationVersion, - ...mockTimestampFields, + ...mockTimestampFieldsWithCreated, }; expectMigrationArgs(doc); @@ -3290,7 +3292,7 @@ describe('SavedObjectsRepository', () => { expect(result).toEqual({ type: MULTI_NAMESPACE_TYPE, id, - ...mockTimestampFields, + ...mockTimestampFieldsWithCreated, version: mockVersion, attributes, references, @@ -3969,6 +3971,7 @@ describe('SavedObjectsRepository', () => { 'migrationVersion', 'coreMigrationVersion', 'updated_at', + 'created_at', 'originId', 'title', ], diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts index f48e031bd23c4..5bf3403742623 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts @@ -337,6 +337,7 @@ export class SavedObjectsRepository implements ISavedObjectsRepository { attributes, migrationVersion, coreMigrationVersion, + created_at: time, updated_at: time, ...(Array.isArray(references) && { references }), }); @@ -516,6 +517,7 @@ export class SavedObjectsRepository implements ISavedObjectsRepository { ...(savedObjectNamespace && { namespace: savedObjectNamespace }), ...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }), updated_at: time, + created_at: time, references: object.references || [], originId, }) as SavedObjectSanitizedDoc; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.test.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.test.ts index 230993bd06d29..dae97802578ca 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.test.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.test.ts @@ -230,6 +230,18 @@ describe('#rawToSavedObject', () => { expect(actual).toHaveProperty('updated_at', now); }); + test('if specified it copies the _source.created_at property to created_at', () => { + const now = Date(); + const actual = singleNamespaceSerializer.rawToSavedObject({ + _id: 'foo:bar', + _source: { + type: 'foo', + created_at: now, + }, + }); + expect(actual).toHaveProperty('created_at', now); + }); + test(`if _source.updated_at is unspecified it doesn't set updated_at`, () => { const actual = singleNamespaceSerializer.rawToSavedObject({ _id: 'foo:bar', @@ -240,6 +252,16 @@ describe('#rawToSavedObject', () => { expect(actual).not.toHaveProperty('updated_at'); }); + test(`if _source.created_at is unspecified it doesn't set created_at`, () => { + const actual = singleNamespaceSerializer.rawToSavedObject({ + _id: 'foo:bar', + _source: { + type: 'foo', + }, + }); + expect(actual).not.toHaveProperty('created_at'); + }); + test('if specified it copies the _source.originId property to originId', () => { const originId = 'baz'; const actual = singleNamespaceSerializer.rawToSavedObject({ @@ -584,6 +606,26 @@ describe('#savedObjectToRaw', () => { ]); }); + test('if specified it copies the created_at property to _source.created_at', () => { + const now = new Date(); + const actual = singleNamespaceSerializer.savedObjectToRaw({ + type: '', + attributes: {}, + created_at: now, + } as any); + + expect(actual._source).toHaveProperty('created_at', now); + }); + + test(`if unspecified it doesn't add created_at property to _source`, () => { + const actual = singleNamespaceSerializer.savedObjectToRaw({ + type: '', + attributes: {}, + } as any); + + expect(actual._source).not.toHaveProperty('created_at'); + }); + test('if specified it copies the updated_at property to _source.updated_at', () => { const now = new Date(); const actual = singleNamespaceSerializer.savedObjectToRaw({ diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts index 340926abd0bce..f1e713b8741b5 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts @@ -110,6 +110,7 @@ export class SavedObjectsSerializer implements ISavedObjectsSerializer { ...(migrationVersion && { migrationVersion }), ...(coreMigrationVersion && { coreMigrationVersion }), ...(_source.updated_at && { updated_at: _source.updated_at }), + ...(_source.created_at && { created_at: _source.created_at }), ...(version && { version }), }; } @@ -130,6 +131,7 @@ export class SavedObjectsSerializer implements ISavedObjectsSerializer { migrationVersion, // eslint-disable-next-line @typescript-eslint/naming-convention updated_at, + created_at: createdAt, version, references, coreMigrationVersion, @@ -144,6 +146,7 @@ export class SavedObjectsSerializer implements ISavedObjectsSerializer { ...(migrationVersion && { migrationVersion }), ...(coreMigrationVersion && { coreMigrationVersion }), ...(updated_at && { updated_at }), + ...(createdAt && { created_at: createdAt }), }; return { diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/validation/schema.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/validation/schema.ts index 221f21b5aa992..8b745caae85de 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/validation/schema.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/validation/schema.ts @@ -43,6 +43,7 @@ export const createSavedObjectSanitizedDocSchema = (attributesSchema: SavedObjec migrationVersion: schema.maybe(schema.recordOf(schema.string(), schema.string())), coreMigrationVersion: schema.maybe(schema.string()), updated_at: schema.maybe(schema.string()), + created_at: schema.maybe(schema.string()), version: schema.maybe(schema.string()), originId: schema.maybe(schema.string()), }); diff --git a/packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts b/packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts index adda64d8b4ff3..414ed5bbf1846 100644 --- a/packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts +++ b/packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts @@ -29,6 +29,7 @@ export class SimpleSavedObjectImpl implements SimpleSavedObject public error: SavedObjectType['error']; public references: SavedObjectType['references']; public updatedAt: SavedObjectType['updated_at']; + public createdAt: SavedObjectType['created_at']; public namespaces: SavedObjectType['namespaces']; constructor( @@ -44,6 +45,7 @@ export class SimpleSavedObjectImpl implements SimpleSavedObject coreMigrationVersion, namespaces, updated_at: updatedAt, + created_at: createdAt, }: SavedObjectType ) { this.id = id; @@ -55,6 +57,7 @@ export class SimpleSavedObjectImpl implements SimpleSavedObject this.coreMigrationVersion = coreMigrationVersion; this.namespaces = namespaces; this.updatedAt = updatedAt; + this.createdAt = createdAt; if (error) { this.error = error; } diff --git a/packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts b/packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts index b65c476c54ee0..2e3c30ac17d9c 100644 --- a/packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts +++ b/packages/core/saved-objects/core-saved-objects-browser-mocks/src/simple_saved_object.mock.ts @@ -24,6 +24,7 @@ const simpleSavedObjectMockDefaults: Partial> = { error: undefined, references: [], updatedAt: '', + createdAt: '', namespaces: undefined, }; @@ -41,6 +42,7 @@ const createSimpleSavedObjectMock = ( error: savedObject.error, references: savedObject.references, updatedAt: savedObject.updated_at, + createdAt: savedObject.created_at, namespaces: savedObject.namespaces, get: jest.fn(), set: jest.fn(), diff --git a/packages/core/saved-objects/core-saved-objects-common/src/saved_objects.ts b/packages/core/saved-objects/core-saved-objects-common/src/saved_objects.ts index b9bdbafc213c9..f98c39871353f 100644 --- a/packages/core/saved-objects/core-saved-objects-common/src/saved_objects.ts +++ b/packages/core/saved-objects/core-saved-objects-common/src/saved_objects.ts @@ -74,6 +74,8 @@ export interface SavedObject { type: string; /** An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. */ version?: string; + /** Timestamp of the time this document had been created. */ + created_at?: string; /** Timestamp of the last time this document had been updated. */ updated_at?: string; error?: SavedObjectError; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/kibana_migrator.test.ts.snap b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/kibana_migrator.test.ts.snap index 32c2536ab0296..882da8e096956 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/kibana_migrator.test.ts.snap +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/kibana_migrator.test.ts.snap @@ -7,6 +7,7 @@ Object { "amap": "510f1f0adb69830cf8a1c5ce2923ed82", "bmap": "510f1f0adb69830cf8a1c5ce2923ed82", "coreMigrationVersion": "2f4316de49999235636386fe51dc06c1", + "created_at": "00da57df13e94e9d98437d13ace4bfe0", "migrationVersion": "4a1746014a75ade3a714e1db5763276f", "namespace": "2f4316de49999235636386fe51dc06c1", "namespaces": "2f4316de49999235636386fe51dc06c1", @@ -35,6 +36,9 @@ Object { "coreMigrationVersion": Object { "type": "keyword", }, + "created_at": Object { + "type": "date", + }, "migrationVersion": Object { "dynamic": "true", "type": "object", diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/__snapshots__/build_active_mappings.test.ts.snap b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/__snapshots__/build_active_mappings.test.ts.snap index 9ee998118bde6..4727f8688c61e 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/__snapshots__/build_active_mappings.test.ts.snap +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/__snapshots__/build_active_mappings.test.ts.snap @@ -7,6 +7,7 @@ Object { "aaa": "625b32086eb1d1203564cf85062dd22e", "bbb": "18c78c995965207ed3f6e7fc5c6e55fe", "coreMigrationVersion": "2f4316de49999235636386fe51dc06c1", + "created_at": "00da57df13e94e9d98437d13ace4bfe0", "migrationVersion": "4a1746014a75ade3a714e1db5763276f", "namespace": "2f4316de49999235636386fe51dc06c1", "namespaces": "2f4316de49999235636386fe51dc06c1", @@ -27,6 +28,9 @@ Object { "coreMigrationVersion": Object { "type": "keyword", }, + "created_at": Object { + "type": "date", + }, "migrationVersion": Object { "dynamic": "true", "type": "object", @@ -69,6 +73,7 @@ Object { "_meta": Object { "migrationMappingPropertyHashes": Object { "coreMigrationVersion": "2f4316de49999235636386fe51dc06c1", + "created_at": "00da57df13e94e9d98437d13ace4bfe0", "firstType": "635418ab953d81d93f1190b70a8d3f57", "migrationVersion": "4a1746014a75ade3a714e1db5763276f", "namespace": "2f4316de49999235636386fe51dc06c1", @@ -86,6 +91,9 @@ Object { "coreMigrationVersion": Object { "type": "keyword", }, + "created_at": Object { + "type": "date", + }, "firstType": Object { "dynamic": "strict", "properties": Object { diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/build_active_mappings.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/build_active_mappings.ts index 1a0a502f655bd..f14de6bc72ee0 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/build_active_mappings.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/build_active_mappings.ts @@ -139,6 +139,9 @@ function defaultMapping(): IndexMapping { updated_at: { type: 'date', }, + created_at: { + type: 'date', + }, references: { type: 'nested', properties: { diff --git a/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts b/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts index d21e83cc09905..7752d0dd99e90 100644 --- a/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts +++ b/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts @@ -82,6 +82,7 @@ export interface SavedObjectsRawDocSource { namespaces?: string[]; migrationVersion?: SavedObjectsMigrationVersion; updated_at?: string; + created_at?: string; references?: SavedObjectReference[]; originId?: string; @@ -103,6 +104,7 @@ interface SavedObjectDoc { coreMigrationVersion?: string; version?: string; updated_at?: string; + created_at?: string; originId?: string; } diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index e848c29437351..8783f21a1af9f 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -126,7 +126,6 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { connectorsMongoDB: `${ENTERPRISE_SEARCH_DOCS}connectors-mongodb.html`, connectorsMySQL: `${ENTERPRISE_SEARCH_DOCS}connectors-mysql.html`, connectorsWorkplaceSearch: `${ENTERPRISE_SEARCH_DOCS}connectors.html#connectors-workplace-search`, - crawlerGettingStarted: `${ENTERPRISE_SEARCH_DOCS}crawler-getting-started.html`, crawlerManaging: `${ENTERPRISE_SEARCH_DOCS}crawler-managing.html`, crawlerOverview: `${ENTERPRISE_SEARCH_DOCS}crawler.html`, deployTrainedModels: `${MACHINE_LEARNING_DOCS}ml-nlp-deploy-models.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 9e75b09cd946e..443de50276691 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -111,7 +111,6 @@ export interface DocLinks { readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsWorkplaceSearch: string; - readonly crawlerGettingStarted: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; diff --git a/packages/kbn-guided-onboarding/BUILD.bazel b/packages/kbn-guided-onboarding/BUILD.bazel new file mode 100644 index 0000000000000..b36e63daa8221 --- /dev/null +++ b/packages/kbn-guided-onboarding/BUILD.bazel @@ -0,0 +1,152 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "kbn-guided-onboarding" +PKG_REQUIRE_NAME = "@kbn/guided-onboarding" + +SOURCE_FILES = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +# In this array place runtime dependencies, including other packages and NPM packages +# which must be available for this code to run. +# +# To reference other packages use: +# "//repo/relative/path/to/package" +# eg. "//packages/kbn-utils" +# +# To reference a NPM package use: +# "@npm//name-of-package" +# eg. "@npm//lodash" +RUNTIME_DEPS = [ + "@npm//@elastic/eui", + "@npm//enzyme", + "@npm//react", + "//packages/kbn-i18n-react", + "//packages/kbn-i18n", + "//packages/core/http/core-http-browser", + "//packages/core/ui-settings/core-ui-settings-browser", +] + +# In this array place dependencies necessary to build the types, which will include the +# :npm_module_types target of other packages and packages from NPM, including @types/* +# packages. +# +# To reference the types for another package use: +# "//repo/relative/path/to/package:npm_module_types" +# eg. "//packages/kbn-utils:npm_module_types" +# +# References to NPM packages work the same as RUNTIME_DEPS +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//@elastic/eui", + "@npm//@types/enzyme", + "@npm//@types/react", + "//packages/kbn-i18n-react:npm_module_types", + "//packages/kbn-i18n:npm_module_types", + "//packages/core/http/core-http-browser:npm_module_types", + "//packages/core/ui-settings/core-ui-settings-browser:npm_module_types", + "//packages/core/application/core-application-browser:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, + additional_args = [ + "--copy-files", + "--quiet" + ], +) + + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-guided-onboarding/README.md b/packages/kbn-guided-onboarding/README.md new file mode 100644 index 0000000000000..83863ad2f7383 --- /dev/null +++ b/packages/kbn-guided-onboarding/README.md @@ -0,0 +1,3 @@ +# @kbn/guided-onboarding + +Empty package generated by @kbn/generate diff --git a/packages/kbn-guided-onboarding/index.ts b/packages/kbn-guided-onboarding/index.ts new file mode 100644 index 0000000000000..2bb4e91906cfd --- /dev/null +++ b/packages/kbn-guided-onboarding/index.ts @@ -0,0 +1,11 @@ +/* + * 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 type { GuideState, GuideId } from './src/types'; +export { GuideCard, ObservabilityLinkCard } from './src/components/landing_page'; +export type { UseCase } from './src/components/landing_page'; diff --git a/packages/kbn-guided-onboarding/jest.config.js b/packages/kbn-guided-onboarding/jest.config.js new file mode 100644 index 0000000000000..cf180f15b8a90 --- /dev/null +++ b/packages/kbn-guided-onboarding/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-guided-onboarding'], +}; diff --git a/packages/kbn-guided-onboarding/kibana.jsonc b/packages/kbn-guided-onboarding/kibana.jsonc new file mode 100644 index 0000000000000..4715fec8fbd5e --- /dev/null +++ b/packages/kbn-guided-onboarding/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/guided-onboarding", + "owner": "@elastic/platform-onboarding", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/kbn-guided-onboarding/package.json b/packages/kbn-guided-onboarding/package.json new file mode 100644 index 0000000000000..5838833e14277 --- /dev/null +++ b/packages/kbn-guided-onboarding/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/guided-onboarding", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card.test.tsx.snap b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card.test.tsx.snap new file mode 100644 index 0000000000000..5633d3e4f7818 --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card.test.tsx.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`guide card snapshots should render use case card component for observability 1`] = ` + + } + isDarkTheme={false} + title="Observe my Kubernetes infrastructure" + useCase="observability" +/> +`; + +exports[`guide card snapshots should render use case card component for search 1`] = ` + + } + isDarkTheme={false} + title="Search my data" + useCase="search" +/> +`; + +exports[`guide card snapshots should render use case card component for security 1`] = ` + + } + isDarkTheme={false} + title="Protect my environment" + useCase="security" +/> +`; diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap new file mode 100644 index 0000000000000..9b18465e91be9 --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap @@ -0,0 +1,107 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`guide card footer snapshots should render the footer when the guide has been completed 1`] = ` + + + +
    + + View guide + +
    +
    +`; + +exports[`guide card footer snapshots should render the footer when the guide has not started yet 1`] = ` +
    + + View guide + +
    +`; + +exports[`guide card footer snapshots should render the footer when the guide is in progress 1`] = ` + + + +
    + + Continue + +
    +
    +`; + +exports[`guide card footer snapshots should render the footer when the guide is ready to complete 1`] = ` + + + +
    + + Continue + +
    +
    +`; + +exports[`guide card footer snapshots should render the footer when the guided onboarding has not started yet 1`] = ` +
    + + View guide + +
    +`; diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/observability_link_card.test.tsx.snap b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/observability_link_card.test.tsx.snap new file mode 100644 index 0000000000000..e1dca8fdfb9e9 --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/observability_link_card.test.tsx.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`observability link card snapshots should render link card for observability 1`] = ` + + + + View integrations + + + + } + isDarkTheme={false} + title="Observe my data" + useCase="observability" +/> +`; diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/guide_card.test.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card.test.tsx new file mode 100644 index 0000000000000..85e74e3bb23fc --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card.test.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 { shallow } from 'enzyme'; + +import { GuideCard, GuideCardProps } from './guide_card'; + +const defaultProps: GuideCardProps = { + useCase: 'search', + guides: [], + activateGuide: jest.fn(), + isDarkTheme: false, + addBasePath: jest.fn(), +}; + +describe('guide card', () => { + describe('snapshots', () => { + test('should render use case card component for search', async () => { + const component = await shallow(); + + expect(component).toMatchSnapshot(); + }); + test('should render use case card component for observability', async () => { + const component = await shallow(); + + expect(component).toMatchSnapshot(); + }); + test('should render use case card component for security', async () => { + const component = await shallow(); + + expect(component).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/guide_card.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card.tsx new file mode 100644 index 0000000000000..df9a5abc9d6b5 --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card.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 from 'react'; +import { i18n } from '@kbn/i18n'; + +import { GuideState } from '../../types'; +import { GuideCardFooter } from './guide_card_footer'; +import { UseCase, UseCaseCard } from './use_case_card'; + +type GuideCardConstants = { + [key in UseCase]: { + i18nTexts: { + title: string; + description: string; + }; + }; +}; +const constants: GuideCardConstants = { + search: { + i18nTexts: { + title: i18n.translate('guidedOnboardingPackage.gettingStarted.guideCard.search.cardTitle', { + defaultMessage: 'Search my data', + }), + description: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.search.cardDescription', + { + defaultMessage: + 'Create a search experience for your websites, applications, workplace content, or anything in between.', + } + ), + }, + }, + observability: { + i18nTexts: { + title: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.observability.cardTitle', + { + defaultMessage: 'Observe my Kubernetes infrastructure', + } + ), + description: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.observability.cardDescription', + { + defaultMessage: + 'Monitor your Kubernetes infrastructure by consolidating your logs and metrics.', + } + ), + }, + }, + security: { + i18nTexts: { + title: i18n.translate('guidedOnboardingPackage.gettingStarted.guideCard.security.cardTitle', { + defaultMessage: 'Protect my environment', + }), + description: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.security.cardDescription', + { + defaultMessage: + 'Defend your environment against threats by unifying SIEM, endpoint security, and cloud security.', + } + ), + }, + }, +}; + +export interface GuideCardProps { + useCase: UseCase; + guides: GuideState[]; + activateGuide: (useCase: UseCase, guide?: GuideState) => Promise; + isDarkTheme: boolean; + addBasePath: (url: string) => string; +} +export const GuideCard = ({ + useCase, + guides, + activateGuide, + isDarkTheme, + addBasePath, +}: GuideCardProps) => { + return ( + } + isDarkTheme={isDarkTheme} + addBasePath={addBasePath} + /> + ); +}; diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/guide_card_footer.test.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card_footer.test.tsx new file mode 100644 index 0000000000000..d264afad65244 --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card_footer.test.tsx @@ -0,0 +1,71 @@ +/* + * 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 { shallow } from 'enzyme'; + +import { GuideCardFooter, GuideCardFooterProps } from './guide_card_footer'; +import { GuideState } from '../../types'; + +const defaultProps: GuideCardFooterProps = { + guides: [], + useCase: 'search', + activateGuide: jest.fn(), +}; + +const searchGuideState: GuideState = { + guideId: 'search', + status: 'not_started', + steps: [ + { id: 'add_data', status: 'complete' }, + { id: 'browse_docs', status: 'in_progress' }, + ], + isActive: true, +}; +describe('guide card footer', () => { + describe('snapshots', () => { + test('should render the footer when the guided onboarding has not started yet', async () => { + const component = await shallow(); + expect(component).toMatchSnapshot(); + }); + + test('should render the footer when the guide has not started yet', async () => { + const component = await shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + test('should render the footer when the guide is in progress', async () => { + const component = await shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + test('should render the footer when the guide is ready to complete', async () => { + const component = await shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + test('should render the footer when the guide has been completed', async () => { + const component = await shallow( + + ); + expect(component).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/guide_card_footer.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card_footer.tsx new file mode 100644 index 0000000000000..be7bc3265f357 --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/guide_card_footer.tsx @@ -0,0 +1,114 @@ +/* + * 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 { EuiButton, EuiProgress, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { GuideId, GuideState } from '../../types'; +import { UseCase } from './use_case_card'; + +const viewGuideLabel = i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.startGuide.buttonLabel', + { + defaultMessage: 'View guide', + } +); + +const continueGuideLabel = i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.continueGuide.buttonLabel', + { + defaultMessage: 'Continue', + } +); + +const completedLabel = i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.progress.completedLabel', + { + defaultMessage: 'Completed', + } +); + +const inProgressLabel = i18n.translate( + 'guidedOnboardingPackage.gettingStarted.guideCard.progress.inProgressLabel', + { + defaultMessage: 'In progress', + } +); + +export interface GuideCardFooterProps { + guides: GuideState[]; + useCase: UseCase; + activateGuide: (useCase: UseCase, guideState?: GuideState) => void; +} +export const GuideCardFooter = ({ guides, useCase, activateGuide }: GuideCardFooterProps) => { + const guideState = guides.find((guide) => guide.guideId === (useCase as GuideId)); + const viewGuideButton = ( +
    + activateGuide(useCase, guideState)} + > + {viewGuideLabel} + +
    + ); + // guide has not started yet + if (!guideState || guideState.status === 'not_started') { + return viewGuideButton; + } + const { status, steps } = guideState; + const numberSteps = steps.length; + const numberCompleteSteps = steps.filter((step) => step.status === 'complete').length; + const stepsLabel = i18n.translate('guidedOnboardingPackage.gettingStarted.guideCard.stepsLabel', { + defaultMessage: '{progress} steps', + values: { + progress: `${numberCompleteSteps}/${numberSteps}`, + }, + }); + // guide is completed + if (status === 'complete') { + return ( + <> + + + {viewGuideButton} + + ); + } + // guide is in progress or ready to complete + return ( + <> + + +
    + activateGuide(useCase, guideState)} + > + {continueGuideLabel} + +
    + + ); +}; diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/index.ts b/packages/kbn-guided-onboarding/src/components/landing_page/index.ts new file mode 100644 index 0000000000000..6d91a53775ddf --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { GuideCard } from './guide_card'; +export { ObservabilityLinkCard } from './observability_link_card'; +export type { UseCase } from './use_case_card'; diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.test.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.test.tsx new file mode 100644 index 0000000000000..191211a33953e --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.test.tsx @@ -0,0 +1,26 @@ +/* + * 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 { shallow } from 'enzyme'; +import { ObservabilityLinkCard } from './observability_link_card'; + +const defaultProps = { + navigateToApp: jest.fn(), + isDarkTheme: false, + addBasePath: jest.fn(), +}; + +describe('observability link card', () => { + describe('snapshots', () => { + test('should render link card for observability', async () => { + const component = await shallow(); + expect(component).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx new file mode 100644 index 0000000000000..995725900546d --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx @@ -0,0 +1,84 @@ +/* + * 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 { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import type { NavigateToAppOptions } from '@kbn/core-application-browser'; +import { UseCaseCard } from './use_case_card'; + +interface LinkCardConstants { + observability: { + i18nTexts: { + title: string; + description: string; + }; + }; +} + +const constants: LinkCardConstants = { + observability: { + i18nTexts: { + title: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.linkCard.observability.cardTitle', + { + defaultMessage: 'Observe my data', + } + ), + description: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.linkCard.observability.cardDescription', + { + defaultMessage: + 'Add application, infrastructure, and user data through our pre-built integrations.', + } + ), + }, + }, +}; + +export const ObservabilityLinkCard = ({ + navigateToApp, + isDarkTheme, + addBasePath, +}: { + navigateToApp: (appId: string, options?: NavigateToAppOptions) => Promise; + isDarkTheme: boolean; + addBasePath: (url: string) => string; +}) => { + const navigateToIntegrations = () => { + navigateToApp('integrations', { + path: '/browse/infrastructure', + }); + }; + const button = ( + + + + {i18n.translate('guidedOnboardingPackage.gettingStarted.linkCard.buttonLabel', { + defaultMessage: 'View integrations', + })} + + + + ); + return ( + + ); +}; diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx new file mode 100644 index 0000000000000..ef9373996297c --- /dev/null +++ b/packages/kbn-guided-onboarding/src/components/landing_page/use_case_card.tsx @@ -0,0 +1,105 @@ +/* + * 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, { ReactNode } from 'react'; +import { EuiCard, EuiText, EuiImage } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { GuideId } from '../../types'; + +type UseCaseConstants = { + [key in UseCase]: { + logAltText: string; + betaBadgeLabel: string; + }; +}; +const constants: UseCaseConstants = { + search: { + logAltText: i18n.translate('guidedOnboardingPackage.gettingStarted.search.iconName', { + defaultMessage: 'Enterprise Search logo', + }), + betaBadgeLabel: i18n.translate('guidedOnboardingPackage.gettingStarted.search.betaBadgeLabel', { + defaultMessage: 'search', + }), + }, + observability: { + logAltText: i18n.translate('guidedOnboardingPackage.gettingStarted.observability.iconName', { + defaultMessage: 'Observability logo', + }), + betaBadgeLabel: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.observability.betaBadgeLabel', + { + defaultMessage: 'observe', + } + ), + }, + security: { + logAltText: i18n.translate('guidedOnboardingPackage.gettingStarted.security.iconName', { + defaultMessage: 'Security logo', + }), + betaBadgeLabel: i18n.translate( + 'guidedOnboardingPackage.gettingStarted.security.betaBadgeLabel', + { + defaultMessage: 'security', + } + ), + }, +}; + +export type UseCase = 'search' | 'observability' | 'security'; + +export interface UseCaseCardProps { + useCase: GuideId; + title: string; + description: string; + footer: ReactNode; + isDarkTheme: boolean; + addBasePath: (url: string) => string; +} + +export const UseCaseCard = ({ + useCase, + title, + description, + footer, + isDarkTheme, + addBasePath, +}: UseCaseCardProps) => { + const getImageUrl = (imageName: UseCase) => { + const imagePath = `/plugins/home/assets/solution_logos/${imageName}${ + isDarkTheme ? '_dark' : '' + }.png`; + + return addBasePath(imagePath); + }; + + const titleElement = ( + +

    + {title} +

    +
    + ); + const descriptionElement = ( + +

    {description}

    +
    + ); + return ( + } + title={titleElement} + description={descriptionElement} + footer={footer} + betaBadgeProps={{ + label: constants[useCase].betaBadgeLabel, + }} + /> + ); +}; diff --git a/src/plugins/guided_onboarding/common/types.ts b/packages/kbn-guided-onboarding/src/types.ts similarity index 88% rename from src/plugins/guided_onboarding/common/types.ts rename to packages/kbn-guided-onboarding/src/types.ts index 435dd948d9f80..9a307464cefb8 100644 --- a/src/plugins/guided_onboarding/common/types.ts +++ b/packages/kbn-guided-onboarding/src/types.ts @@ -14,13 +14,21 @@ export type SearchStepIds = 'add_data' | 'browse_docs' | 'search_experience'; export type GuideStepIds = ObservabilityStepIds | SecurityStepIds | SearchStepIds; +export interface GuideState { + guideId: GuideId; + status: GuideStatus; + isActive?: boolean; // Drives the current guide shown in the dropdown panel + steps: GuideStep[]; +} + /** * Allowed states for a guide: - * in_progress: Guide has been started + * not_started: Guide has not been started + * in_progress: At least one step in the guide has been started * ready_to_complete: All steps have been completed, but the "Continue using Elastic" button has not been clicked * complete: All steps and the guide have been completed */ -export type GuideStatus = 'in_progress' | 'ready_to_complete' | 'complete'; +export type GuideStatus = 'not_started' | 'in_progress' | 'ready_to_complete' | 'complete'; /** * Allowed states for each step in a guide: @@ -36,10 +44,3 @@ export interface GuideStep { id: GuideStepIds; status: StepStatus; } - -export interface GuideState { - guideId: GuideId; - status: GuideStatus; - isActive?: boolean; // Drives the current guide shown in the dropdown panel - steps: GuideStep[]; -} diff --git a/packages/kbn-guided-onboarding/tsconfig.json b/packages/kbn-guided-onboarding/tsconfig.json new file mode 100644 index 0000000000000..a88e5af86e42a --- /dev/null +++ b/packages/kbn-guided-onboarding/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ] +} diff --git a/packages/kbn-journeys/journey/journey.ts b/packages/kbn-journeys/journey/journey.ts index c399db0ba91c4..537587fef3872 100644 --- a/packages/kbn-journeys/journey/journey.ts +++ b/packages/kbn-journeys/journey/journey.ts @@ -12,7 +12,7 @@ import { Page } from 'playwright'; import callsites from 'callsites'; import { ToolingLog } from '@kbn/tooling-log'; import { FtrConfigProvider } from '@kbn/test'; -import { FtrProviderContext } from '@kbn/ftr-common-functional-services'; +import { FtrProviderContext, KibanaServer } from '@kbn/ftr-common-functional-services'; import { Auth } from '../services/auth'; import { InputDelays } from '../services/input_delays'; @@ -27,6 +27,7 @@ export interface BaseStepCtx { log: ToolingLog; inputDelays: InputDelays; kbnUrl: KibanaUrl; + kibanaServer: KibanaServer; } export type AnyStep = Step<{}>; diff --git a/packages/kbn-journeys/journey/journey_ftr_harness.ts b/packages/kbn-journeys/journey/journey_ftr_harness.ts index 6154581738ac7..c8e876ce2873e 100644 --- a/packages/kbn-journeys/journey/journey_ftr_harness.ts +++ b/packages/kbn-journeys/journey/journey_ftr_harness.ts @@ -358,6 +358,7 @@ export class JourneyFtrHarness { }) ) ), + kibanaServer: this.kibanaServer, }); return this.#_ctx; diff --git a/packages/kbn-language-documentation-popover/index.ts b/packages/kbn-language-documentation-popover/index.ts index 89d1f238c06d0..2c1746383917a 100644 --- a/packages/kbn-language-documentation-popover/index.ts +++ b/packages/kbn-language-documentation-popover/index.ts @@ -7,4 +7,5 @@ */ export { LanguageDocumentationPopover } from './src/components/documentation_popover'; +export { LanguageDocumentationPopoverContent } from './src/components/documentation_content'; export type { LanguageDocumentationSections } from './src/components/documentation_content'; diff --git a/packages/kbn-language-documentation-popover/src/components/documentation.scss b/packages/kbn-language-documentation-popover/src/components/documentation.scss index 4cf5fbd08cdcd..752797decfa4e 100644 --- a/packages/kbn-language-documentation-popover/src/components/documentation.scss +++ b/packages/kbn-language-documentation-popover/src/components/documentation.scss @@ -1,80 +1,11 @@ -.documentation { - display: flex; - flex-direction: column; - - & > * { - flex: 1; - min-height: 0; - } - - & > * + * { - border-top: $euiBorderThin; - } -} - -.documentation__editor { - - & > * + * { - border-top: $euiBorderThin; - } -} - -.documentation__editorHeader, -.documentation__editorFooter { - padding: $euiSizeS $euiSize; -} - -.documentation__editorFooter { - // make sure docs are rendered in front of monaco - z-index: 1; - background-color: $euiColorLightestShade; -} - -.documentation__editorHeaderGroup, -.documentation__editorFooterGroup { - display: block; // Overrides EUI's styling of `display: flex` on `EuiFlexItem` components -} - -.documentation__editorContent { - min-height: 0; - position: relative; -} - -.documentation__editorPlaceholder { - position: absolute; - top: 0; - left: $euiSize; - right: 0; - color: $euiTextSubduedColor; - // Matches monaco editor - font-family: Menlo, Monaco, 'Courier New', monospace; - pointer-events: none; -} - -.documentation__warningText + .documentation__warningText { - margin-top: $euiSizeS; - border-top: $euiBorderThin; - padding-top: $euiSizeS; -} - -.documentation__editorHelp--inline { - align-items: center; - display: flex; - padding: $euiSizeXS; - - & > * + * { - margin-left: $euiSizeXS; - } -} - -.documentation__editorError { - white-space: nowrap; -} - .documentation__docs { background: $euiColorEmptyShade; } +.documentation__docsHeader { + margin: 0; +} + .documentation__docs--inline { display: flex; flex-direction: column; diff --git a/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx b/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx index 6c36e1a5e54d0..6d91cc403795e 100644 --- a/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx +++ b/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx @@ -38,7 +38,7 @@ describe('###Documentation popover content', () => { test('Documentation component has a header element referring to the language given', () => { const component = mountWithIntl(); const title = findTestSubject(component, 'language-documentation-title'); - expect(title.text()).toEqual('TEST reference'); + expect(title.text()).toEqual('test reference'); }); test('Documentation component has a sidebar navigation list with all the section labels', () => { diff --git a/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx b/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx index c5470aeea6fd1..b7c2e800bbaf5 100644 --- a/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx +++ b/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx @@ -76,7 +76,7 @@ function DocumentationContent({ language, sections }: DocumentationProps) { > {i18n.translate('languageDocumentationPopover.header', { defaultMessage: '{language} reference', - values: { language: language.toUpperCase() }, + values: { language }, })} setIsHelpOpen(false)} - ownFocus={false} button={ diff --git a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx index dcdba80c268d7..59ff70f60d594 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx @@ -114,4 +114,30 @@ describe('FieldComponent', () => { expect(wrapper.getByTestId('fieldAutocompleteComboBox')).toHaveTextContent('_source') ); }); + + it('it allows custom user input if "acceptsCustomOptions" is "true"', async () => { + const mockOnChange = jest.fn(); + const wrapper = render( + + ); + + const fieldAutocompleteComboBox = wrapper.getByTestId('comboBoxSearchInput'); + fireEvent.change(fieldAutocompleteComboBox, { target: { value: 'custom' } }); + await waitFor(() => + expect(wrapper.getByTestId('fieldAutocompleteComboBox')).toHaveTextContent('custom') + ); + }); }); diff --git a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/use_field.test.ts b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/use_field.test.ts index 68748bf82a20f..d060f585e9118 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/use_field.test.ts +++ b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/use_field.test.ts @@ -346,6 +346,18 @@ describe('useField', () => { ]); }); }); + it('should invoke onChange with custom option if one is sent', () => { + const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + act(() => { + result.current.handleCreateCustomOption('madeUpField'); + expect(onChangeMock).toHaveBeenCalledWith([ + { + name: 'madeUpField', + type: 'text', + }, + ]); + }); + }); }); describe('fieldWidth', () => { diff --git a/packages/kbn-securitysolution-autocomplete/src/field/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field/index.tsx index dad13434779e7..704433b79560b 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/index.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field/index.tsx @@ -25,6 +25,7 @@ export const FieldComponent: React.FC = ({ onChange, placeholder, selectedField, + acceptsCustomOptions = false, }): JSX.Element => { const { isInvalid, @@ -35,6 +36,7 @@ export const FieldComponent: React.FC = ({ renderFields, handleTouch, handleValuesChange, + handleCreateCustomOption, } = useField({ indexPattern, fieldTypeFilter, @@ -43,6 +45,29 @@ export const FieldComponent: React.FC = ({ fieldInputWidth, onChange, }); + + if (acceptsCustomOptions) { + return ( + + ); + } + return ( { const [touched, setIsTouched] = useState(false); - const { availableFields, selectedFields } = useMemo( - () => getComboBoxFields(indexPattern, selectedField, fieldTypeFilter), - [indexPattern, fieldTypeFilter, selectedField] - ); + const [customOption, setCustomOption] = useState(null); + + const { availableFields, selectedFields } = useMemo(() => { + const indexPatternsToUse = + customOption != null && indexPattern != null + ? { ...indexPattern, fields: [...indexPattern?.fields, customOption] } + : indexPattern; + return getComboBoxFields(indexPatternsToUse, selectedField, fieldTypeFilter); + }, [indexPattern, fieldTypeFilter, selectedField, customOption]); const { comboOptions, labels, selectedComboOptions, disabledLabelTooltipTexts } = useMemo( () => getComboBoxProps({ availableFields, selectedFields }), @@ -117,6 +122,19 @@ export const useField = ({ [availableFields, labels, onChange] ); + const handleCreateCustomOption = useCallback( + (val: string) => { + const normalizedSearchValue = val.trim().toLowerCase(); + + if (!normalizedSearchValue) { + return; + } + setCustomOption({ name: val, type: 'text' }); + onChange([{ name: val, type: 'text' }]); + }, + [onChange] + ); + const handleTouch = useCallback((): void => { setIsTouched(true); }, [setIsTouched]); @@ -161,5 +179,6 @@ export const useField = ({ renderFields, handleTouch, handleValuesChange, + handleCreateCustomOption, }; }; diff --git a/packages/kbn-securitysolution-exception-list-components/README.md b/packages/kbn-securitysolution-exception-list-components/README.md index e23b85e409960..fe23c66e8988e 100644 --- a/packages/kbn-securitysolution-exception-list-components/README.md +++ b/packages/kbn-securitysolution-exception-list-components/README.md @@ -1,11 +1,11 @@ # @kbn/securitysolution-exception-list-components -This is where the building UI components of the Exception-List live -Most of the components here are imported from `x-pack/plugins/security_solutions/public/detection_engine` +Common exceptions' components # Aim -TODO +- To have most of the Exceptions' components in one place, to be shared accross multiple pages and used for different logic. +- This `package` holds the presetational part of the components only as the API or the logic part should reside under the consumer page # Pattern used @@ -14,9 +14,19 @@ component index.tsx index.styles.ts <-- to hold styles if the component has many custom styles use_component.ts <-- for logic if the Presentational Component has logic - index.test.tsx + component.test.tsx use_component.test.tsx + ``` +# Testing + +In order to unify our testing tools, we configured only two libraries, the `React-Testing-Library` to test the component UI part and the `Reat-Testing-Hooks` to test the component's UI interactions + +# Styling + +In order to follow the `KBN-Packages's` recommendations, to define a custom CSS we can only use the `@emotion/react` or `@emotion/css` libraries + + # Next diff --git a/packages/kbn-securitysolution-exception-list-components/index.ts b/packages/kbn-securitysolution-exception-list-components/index.ts index f5001ff35fd33..6b11782b574dc 100644 --- a/packages/kbn-securitysolution-exception-list-components/index.ts +++ b/packages/kbn-securitysolution-exception-list-components/index.ts @@ -6,11 +6,13 @@ * Side Public License, v 1. */ -export * from './src/search_bar/search_bar'; -export * from './src/empty_viewer_state/empty_viewer_state'; +export * from './src/search_bar'; +export * from './src/empty_viewer_state'; export * from './src/pagination/pagination'; // export * from './src/exceptions_utility/exceptions_utility'; -export * from './src/exception_items/exception_items'; +export * from './src/exception_items'; export * from './src/exception_item_card'; export * from './src/value_with_space_warning'; export * from './src/types'; +export * from './src/list_header'; +export * from './src/header_menu'; diff --git a/packages/kbn-securitysolution-exception-list-components/jest.config.js b/packages/kbn-securitysolution-exception-list-components/jest.config.js index 37a11c23c75ba..00f407dce42fb 100644 --- a/packages/kbn-securitysolution-exception-list-components/jest.config.js +++ b/packages/kbn-securitysolution-exception-list-components/jest.config.js @@ -14,6 +14,13 @@ module.exports = { collectCoverageFrom: [ '/packages/kbn-securitysolution-exception-list-components/**/*.{ts,tsx}', '!/packages/kbn-securitysolution-exception-list-components/**/*.test', + '!/packages/kbn-securitysolution-exception-list-components/**/types/*', + '!/packages/kbn-securitysolution-exception-list-components/**/*.type', + '!/packages/kbn-securitysolution-exception-list-components/**/*.styles', + '!/packages/kbn-securitysolution-exception-list-components/**/mocks/*', + '!/packages/kbn-securitysolution-exception-list-components/**/*.config', + '!/packages/kbn-securitysolution-exception-list-components/**/translations', + '!/packages/kbn-securitysolution-exception-list-components/**/types/*', ], setupFilesAfterEnv: [ '/packages/kbn-securitysolution-exception-list-components/setup_test.ts', diff --git a/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx index 43943e0e8fb97..3e883a0162b6f 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx @@ -9,8 +9,9 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { EmptyViewerState } from './empty_viewer_state'; +import { EmptyViewerState } from '.'; import { ListTypeText, ViewerStatus } from '../types'; +import * as i18n from '../translations'; describe('EmptyViewerState', () => { it('it should render "error" with the default title and body', () => { @@ -23,10 +24,10 @@ describe('EmptyViewerState', () => { ); expect(wrapper.getByTestId('errorViewerState')).toBeTruthy(); - expect(wrapper.getByTestId('errorTitle')).toHaveTextContent('Unable to load exception items'); - expect(wrapper.getByTestId('errorBody')).toHaveTextContent( - 'There was an error loading the exception items. Contact your administrator for help.' + expect(wrapper.getByTestId('errorTitle')).toHaveTextContent( + i18n.EMPTY_VIEWER_STATE_ERROR_TITLE ); + expect(wrapper.getByTestId('errorBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_ERROR_BODY); }); it('it should render "error" when sending the title and body props', () => { const wrapper = render( @@ -65,9 +66,11 @@ describe('EmptyViewerState', () => { expect(wrapper.getByTestId('emptySearchViewerState')).toBeTruthy(); expect(wrapper.getByTestId('emptySearchTitle')).toHaveTextContent( - 'No results match your search criteria' + i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_TITLE + ); + expect(wrapper.getByTestId('emptySearchBody')).toHaveTextContent( + i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_BODY ); - expect(wrapper.getByTestId('emptySearchBody')).toHaveTextContent('Try modifying your search'); }); it('it should render empty search when sending title and body props', () => { const wrapper = render( @@ -111,11 +114,11 @@ describe('EmptyViewerState', () => { const { getByTestId } = wrapper; expect(getByTestId('emptyViewerState')).toBeTruthy(); - expect(getByTestId('emptyTitle')).toHaveTextContent('Add exceptions to this rule'); - expect(getByTestId('emptyBody')).toHaveTextContent( - 'There is no exception in your rule. Create your first rule exception.' + expect(getByTestId('emptyTitle')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE); + expect(getByTestId('emptyBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_BODY); + expect(getByTestId('emptyStateButton')).toHaveTextContent( + i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON('rule') ); - expect(getByTestId('emptyStateButton')).toHaveTextContent('Create rule exception'); }); it('it should render no items screen with default title and body props and listType endPoint', () => { const wrapper = render( @@ -129,10 +132,29 @@ describe('EmptyViewerState', () => { const { getByTestId } = wrapper; expect(getByTestId('emptyViewerState')).toBeTruthy(); - expect(getByTestId('emptyTitle')).toHaveTextContent('Add exceptions to this rule'); - expect(getByTestId('emptyBody')).toHaveTextContent( - 'There is no exception in your rule. Create your first rule exception.' + expect(getByTestId('emptyTitle')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE); + expect(getByTestId('emptyBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_BODY); + expect(getByTestId('emptyStateButton')).toHaveTextContent( + i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON(ListTypeText.ENDPOINT) + ); + }); + it('it should render no items screen and disable the Create exception button if isReadOnly true', () => { + const wrapper = render( + + ); + + const { getByTestId } = wrapper; + expect(getByTestId('emptyViewerState')).toBeTruthy(); + expect(getByTestId('emptyTitle')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE); + expect(getByTestId('emptyBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_BODY); + expect(getByTestId('emptyStateButton')).toHaveTextContent( + i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON(ListTypeText.ENDPOINT) ); - expect(getByTestId('emptyStateButton')).toHaveTextContent('Create endpoint exception'); + expect(getByTestId('emptyStateButton')).toBeDisabled(); }); }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.tsx b/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.tsx rename to packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap new file mode 100644 index 0000000000000..5c0dba4573e06 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap @@ -0,0 +1,667 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ExceptionItemCardComments should render comments panel closed 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
      +
    1. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    2. +
    3. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    4. +
    +
    +
    +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +
    +
    +
      +
    1. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    2. +
    3. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    4. +
    +
    +
    +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`ExceptionItemCardComments should render comments panel opened when accordion is clicked 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
      +
    1. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    2. +
    3. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    4. +
    +
    +
    +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +
    +
    +
      +
    1. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    2. +
    3. +
      +
      + +
      +
      +
      +
      +
      +

      + some old comment +

      +
      +
      +
      +
    4. +
    +
    +
    +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx new file mode 100644 index 0000000000000..64b2d1c9e3a83 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx @@ -0,0 +1,46 @@ +/* + * 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 { fireEvent, render } from '@testing-library/react'; +import { mockGetFormattedComments } from '../../mocks/comments.mock'; +import { ExceptionItemCardComments } from '.'; +import * as i18n from '../translations'; + +const comments = mockGetFormattedComments(); +describe('ExceptionItemCardComments', () => { + it('should render comments panel closed', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + + expect(wrapper.getByTestId('ExceptionItemCardCommentsContainer')).toHaveTextContent( + i18n.exceptionItemCardCommentsAccordion(comments.length) + ); + expect(wrapper.getByTestId('accordionContentPanel')).not.toBeVisible(); + }); + + it('should render comments panel opened when accordion is clicked', () => { + const wrapper = render( + + ); + + const container = wrapper.getByTestId('ExceptionItemCardCommentsContainerTextButton'); + fireEvent.click(container); + expect(wrapper.getByTestId('accordionContentPanel')).toBeVisible(); + expect(wrapper.getByTestId('accordionCommentList')).toBeVisible(); + expect(wrapper.getByTestId('accordionCommentList')).toHaveTextContent('some old comment'); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx similarity index 54% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.tsx rename to packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx index ca08d10f0a049..8d697fd6e1f8a 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx @@ -19,27 +19,30 @@ const accordionCss = css` export interface ExceptionItemCardCommentsProps { comments: EuiCommentProps[]; + dataTestSubj?: string; } -export const ExceptionItemCardComments = memo(({ comments }) => { - return ( - - - {i18n.exceptionItemCardCommentsAccordion(comments.length)} - - } - arrowDisplay="none" - data-test-subj="exceptionsViewerCommentAccordion" - > - - - - - - ); -}); +export const ExceptionItemCardComments = memo( + ({ comments, dataTestSubj }) => { + return ( + + + {i18n.exceptionItemCardCommentsAccordion(comments.length)} + + } + arrowDisplay="none" + data-test-subj="exceptionItemCardComments" + > + + + + + + ); + } +); ExceptionItemCardComments.displayName = 'ExceptionItemCardComments'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx index ae4b76a4a7dc0..73eb10fce68d8 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx @@ -9,7 +9,7 @@ import { render } from '@testing-library/react'; import React from 'react'; -import { ExceptionItemCardConditions } from './conditions'; +import { ExceptionItemCardConditions } from '.'; interface TestEntry { field: string; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/__snapshots__/entry_content.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/__snapshots__/entry_content.test.tsx.snap new file mode 100644 index 0000000000000..4f35694645fde --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/__snapshots__/entry_content.test.tsx.snap @@ -0,0 +1,164 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EntryContent should render a nested value 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + + + +
    + + + + + + + + included in + + + + list_id + + +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + + + +
    + + + + + + + + included in + + + + list_id + + +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx new file mode 100644 index 0000000000000..d30cf9fa2f1d2 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx @@ -0,0 +1,97 @@ +/* + * 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 { ListOperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { OPERATOR_TYPE_LABELS_EXCLUDED, OPERATOR_TYPE_LABELS_INCLUDED } from '../conditions.config'; +import { getEntryOperator, getValue, getValueExpression } from './entry_content.helper'; +import { render } from '@testing-library/react'; +import { + includedExistsTypeEntry, + includedListTypeEntry, + includedMatchTypeEntry, +} from '../../../mocks/entry.mock'; + +describe('entry_content.helper', () => { + describe('getEntryOperator', () => { + it('should return empty if type is nested', () => { + const result = getEntryOperator(ListOperatorTypeEnum.NESTED, 'included'); + expect(result).toBeFalsy(); + expect(result).toEqual(''); + }); + it('should return the correct labels for OPERATOR_TYPE_LABELS_INCLUDED when operator is included', () => { + const allKeys = Object.keys(OPERATOR_TYPE_LABELS_INCLUDED); + const [, ...withoutNested] = allKeys; + withoutNested.forEach((key) => { + const result = getEntryOperator(key as ListOperatorTypeEnum, 'included'); + const expectedLabel = OPERATOR_TYPE_LABELS_INCLUDED[key as ListOperatorTypeEnum]; + expect(result).toEqual(expectedLabel); + }); + }); + it('should return the correct labels for OPERATOR_TYPE_LABELS_EXCLUDED when operator is excluded', () => { + const allKeys = Object.keys(OPERATOR_TYPE_LABELS_EXCLUDED); + const [, ...withoutNested] = allKeys; + withoutNested.forEach((key) => { + const result = getEntryOperator(key as ListOperatorTypeEnum, 'excluded'); + const expectedLabel = + OPERATOR_TYPE_LABELS_EXCLUDED[ + key as Exclude + ]; + expect(result).toEqual(expectedLabel); + }); + }); + it('should return the type when it is neither OPERATOR_TYPE_LABELS_INCLUDED nor OPERATOR_TYPE_LABELS_EXCLUDED', () => { + const result = getEntryOperator('test' as ListOperatorTypeEnum, 'included'); + expect(result).toEqual('test'); + }); + }); + describe('getValue', () => { + it('should return list.id when entry type is "list"', () => { + expect(getValue(includedListTypeEntry)).toEqual('list_id'); + }); + it('should return value when entry type is not "list"', () => { + expect(getValue(includedMatchTypeEntry)).toEqual('matches value'); + }); + it('should return empty string when type does not have value', () => { + expect(getValue(includedExistsTypeEntry)).toEqual(''); + }); + }); + describe('getValueExpression', () => { + it('should render multiple values in badges when operator type is match_any and values is Array', () => { + const wrapper = render( + getValueExpression(ListOperatorTypeEnum.MATCH_ANY, 'included', ['value 1', 'value 2']) + ); + expect(wrapper.getByTestId('matchAnyBadge0')).toHaveTextContent('value 1'); + expect(wrapper.getByTestId('matchAnyBadge1')).toHaveTextContent('value 2'); + }); + it('should return one value when operator type is match_any and values is not Array', () => { + const wrapper = render( + getValueExpression(ListOperatorTypeEnum.MATCH_ANY, 'included', 'value 1') + ); + expect(wrapper.getByTestId('entryValueExpression')).toHaveTextContent('value 1'); + }); + it('should return one value when operator type is a single value', () => { + const wrapper = render( + getValueExpression(ListOperatorTypeEnum.EXISTS, 'included', 'value 1') + ); + expect(wrapper.getByTestId('entryValueExpression')).toHaveTextContent('value 1'); + }); + it('should return value with warning icon when the value contains a leading or trailing space', () => { + const wrapper = render( + getValueExpression(ListOperatorTypeEnum.EXISTS, 'included', ' value 1') + ); + expect(wrapper.getByTestId('entryValueExpression')).toHaveTextContent(' value 1'); + expect(wrapper.getByTestId('valueWithSpaceWarningTooltip')).toBeInTheDocument(); + }); + it('should return value without warning icon when the value does not contain a leading or trailing space', () => { + const wrapper = render( + getValueExpression(ListOperatorTypeEnum.EXISTS, 'included', 'value 1') + ); + expect(wrapper.getByTestId('entryValueExpression')).toHaveTextContent(' value 1'); + expect(wrapper.queryByTestId('valueWithSpaceWarningTooltip')).not.toBeInTheDocument(); + }); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx index 6a64bcc810c08..e8d02dace3a81 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx @@ -15,7 +15,11 @@ import type { Entry } from '../types'; const getEntryValue = (type: string, value?: string | string[]) => { if (type === 'match_any' && Array.isArray(value)) { - return value.map((currentValue) => {currentValue}); + return value.map((currentValue, index) => ( + + {currentValue} + + )); } return value ?? ''; }; @@ -42,6 +46,7 @@ export const getValueExpression = ( diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx new file mode 100644 index 0000000000000..7e02e19d61844 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx @@ -0,0 +1,44 @@ +/* + * 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 } from '@testing-library/react'; +import { includedListTypeEntry } from '../../../mocks/entry.mock'; +import * as i18n from '../../translations'; +import { EntryContent } from '.'; + +describe('EntryContent', () => { + it('should render a single value without AND when index is 0', () => { + const wrapper = render( + + ); + expect(wrapper.getByTestId('EntryContentSingleEntry')).toBeInTheDocument(); + expect(wrapper.getByTestId('entryValueExpression')).toHaveTextContent('list_id'); + }); + it('should render a single value with AND when index is 1', () => { + const wrapper = render( + + ); + expect(wrapper.getByTestId('EntryContentSingleEntry')).toBeInTheDocument(); + expect(wrapper.getByTestId('entryValueExpression')).toHaveTextContent('list_id'); + expect(wrapper.getByText(i18n.CONDITION_AND)).toBeInTheDocument(); + }); + it('should render a nested value', () => { + const wrapper = render( + + ); + expect(wrapper.getByTestId('EntryContentNestedEntry')).toBeInTheDocument(); + expect(wrapper.getByTestId('nstedEntryIcon')).toBeInTheDocument(); + expect(wrapper.getByTestId('entryValueExpression')).toHaveTextContent('list_id'); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx similarity index 79% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.tsx rename to packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx index 6c321a6d0ce04..8a5fe0b998fa4 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { memo } from 'react'; +import React, { FC, memo } from 'react'; import { EuiExpression, EuiToken, EuiFlexGroup } from '@elastic/eui'; import { ListOperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { @@ -18,18 +18,15 @@ import type { Entry } from '../types'; import * as i18n from '../../translations'; import { getValue, getValueExpression } from './entry_content.helper'; -export const EntryContent = memo( - ({ - entry, - index, - isNestedEntry = false, - dataTestSubj, - }: { - entry: Entry; - index: number; - isNestedEntry?: boolean; - dataTestSubj?: string; - }) => { +interface EntryContentProps { + entry: Entry; + index: number; + isNestedEntry?: boolean; + dataTestSubj?: string; +} + +export const EntryContent: FC = memo( + ({ entry, index, isNestedEntry = false, dataTestSubj }) => { const { field, type } = entry; const value = getValue(entry); const operator = 'operator' in entry ? entry.operator : ''; @@ -40,12 +37,14 @@ export const EntryContent = memo(
    {isNestedEntry ? ( - +
    @@ -58,6 +57,7 @@ export const EntryContent = memo( description={index === 0 ? '' : i18n.CONDITION_AND} value={field} color={index === 0 ? 'primary' : 'subdued'} + data-test-subj={`${dataTestSubj || ''}SingleEntry`} /> {getValueExpression(type as ListOperatorTypeEnum, operator, value)} diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx similarity index 94% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.tsx rename to packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx index 8b85a7343afc1..28d9b1d9b09d1 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx @@ -10,8 +10,8 @@ import React, { memo } from 'react'; import { EuiPanel } from '@elastic/eui'; import { borderCss } from './conditions.styles'; -import { EntryContent } from './entry_content/entry_content'; -import { OsCondition } from './os_conditions/os_conditions'; +import { EntryContent } from './entry_content'; +import { OsCondition } from './os_conditions'; import type { CriteriaConditionsProps, Entry } from './types'; export const ExceptionItemCardConditions = memo( diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/__snapshots__/os_conditions.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/__snapshots__/os_conditions.test.tsx.snap new file mode 100644 index 0000000000000..1ace7211d5e5f --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/__snapshots__/os_conditions.test.tsx.snap @@ -0,0 +1,467 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OsCondition should render one OS_LABELS 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    + + + + + + OS + + + + + IS + + + + Mac + + + +
    +
    + , + "container":
    +
    + + + + + + OS + + + + + IS + + + + Mac + + + +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`OsCondition should render two OS_LABELS 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    + + + + + + OS + + + + + IS + + + + Mac, Windows + + + +
    +
    + , + "container":
    +
    + + + + + + OS + + + + + IS + + + + Mac, Windows + + + +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`OsCondition should return any os sent 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    + + + + + + OS + + + + + IS + + + + MacPro + + + +
    +
    + , + "container":
    +
    + + + + + + OS + + + + + IS + + + + MacPro + + + +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`OsCondition should return empty body 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    + , + "container":
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx similarity index 79% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.tsx rename to packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx index 701529ae6717d..ccd829d045bc6 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx @@ -14,7 +14,7 @@ import { OS_LABELS } from '../conditions.config'; import * as i18n from '../../translations'; export interface OsConditionsProps { - dataTestSubj: string; + dataTestSubj?: string; os: ExceptionListItemSchema['os_types']; } @@ -25,8 +25,12 @@ export const OsCondition = memo(({ os, dataTestSubj }) => { return osLabel ? (
    - - + +
    ) : null; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx new file mode 100644 index 0000000000000..99a6f2ce0ecad --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx @@ -0,0 +1,43 @@ +/* + * 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 } from '@testing-library/react'; +import * as i18n from '../../translations'; +import { OS_LABELS } from '../conditions.config'; +import { OsCondition } from '.'; + +describe('OsCondition', () => { + it('should render one OS_LABELS', () => { + const wrapper = render(); + expect(wrapper.getByTestId('osLabel')).toHaveTextContent(i18n.CONDITION_OS); + expect(wrapper.getByTestId('osValue')).toHaveTextContent( + `${i18n.CONDITION_OPERATOR_TYPE_MATCH} ${OS_LABELS.macos}` + ); + expect(wrapper).toMatchSnapshot(); + }); + it('should render two OS_LABELS', () => { + const wrapper = render(); + expect(wrapper.getByTestId('osLabel')).toHaveTextContent(i18n.CONDITION_OS); + expect(wrapper.getByTestId('osValue')).toHaveTextContent( + `${i18n.CONDITION_OPERATOR_TYPE_MATCH} ${OS_LABELS.macos}, ${OS_LABELS.windows}` + ); + expect(wrapper).toMatchSnapshot(); + }); + it('should return empty body', () => { + const wrapper = render(); + expect(wrapper).toMatchSnapshot(); + }); + it('should return any os sent', () => { + const wrapper = render(); + expect(wrapper.getByTestId('osLabel')).toHaveTextContent(i18n.CONDITION_OS); + expect(wrapper.getByTestId('osValue')).toHaveTextContent( + `${i18n.CONDITION_OPERATOR_TYPE_MATCH} MacPro` + ); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx similarity index 65% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.test.tsx rename to packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx index 87a8a3bd3b527..649748f593034 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.test.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx @@ -10,31 +10,11 @@ import React from 'react'; import { fireEvent, render } from '@testing-library/react'; import { ExceptionItemCard } from '.'; -import { getExceptionListItemSchemaMock } from '../test_helpers/exception_list_item_schema.mock'; -import { getCommentsArrayMock } from '../test_helpers/comments.mock'; +import { getExceptionListItemSchemaMock } from '../mocks/exception_list_item_schema.mock'; +import { getCommentsArrayMock, mockGetFormattedComments } from '../mocks/comments.mock'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { rules } from '../mocks/rule_references.mock'; -const ruleReferences: unknown[] = [ - { - exception_lists: [ - { - id: '123', - list_id: 'i_exist', - namespace_type: 'single', - type: 'detection', - }, - { - id: '456', - list_id: 'i_exist_2', - namespace_type: 'single', - type: 'detection', - }, - ], - id: '1a2b3c', - name: 'Simple Rule Query', - rule_id: 'rule-2', - }, -]; describe('ExceptionItemCard', () => { it('it renders header, item meta information and conditions', () => { const exceptionItem = { ...getExceptionListItemSchemaMock(), comments: [] }; @@ -43,7 +23,7 @@ describe('ExceptionItemCard', () => { { ); expect(wrapper.getByTestId('exceptionItemCardHeaderContainer')).toBeInTheDocument(); - // expect(wrapper.getByTestId('exceptionItemCardMetaInfo')).toBeInTheDocument(); + expect(wrapper.getByTestId('exceptionItemCardMetaInfo')).toBeInTheDocument(); expect(wrapper.getByTestId('exceptionItemCardConditions')).toBeInTheDocument(); - // expect(wrapper.queryByTestId('exceptionsViewerCommentAccordion')).not.toBeInTheDocument(); + expect(wrapper.queryByTestId('exceptionsViewerCommentAccordion')).not.toBeInTheDocument(); }); - it('it renders header, item meta information, conditions, and comments if any exist', () => { + it('it should render the header, item meta information, conditions, and the comments', () => { const exceptionItem = { ...getExceptionListItemSchemaMock(), comments: getCommentsArrayMock() }; const wrapper = render( @@ -67,22 +47,22 @@ describe('ExceptionItemCard', () => { exceptionItem={exceptionItem} dataTestSubj="item" listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={ruleReferences} + ruleReferences={rules} onDeleteException={jest.fn()} onEditException={jest.fn()} securityLinkAnchorComponent={() => null} formattedDateComponent={() => null} - getFormattedComments={() => []} + getFormattedComments={mockGetFormattedComments} /> ); expect(wrapper.getByTestId('exceptionItemCardHeaderContainer')).toBeInTheDocument(); - // expect(wrapper.getByTestId('exceptionItemCardMetaInfo')).toBeInTheDocument(); + expect(wrapper.getByTestId('exceptionItemCardMetaInfo')).toBeInTheDocument(); expect(wrapper.getByTestId('exceptionItemCardConditions')).toBeInTheDocument(); - // expect(wrapper.getByTestId('exceptionsViewerCommentAccordion')).toBeInTheDocument(); + expect(wrapper.getByTestId('exceptionsItemCommentAccordion')).toBeInTheDocument(); }); - it('it does not render edit or delete action buttons when "disableActions" is "true"', () => { + it('it should not render edit or delete action buttons when "disableActions" is "true"', () => { const exceptionItem = getExceptionListItemSchemaMock(); const wrapper = render( @@ -93,7 +73,7 @@ describe('ExceptionItemCard', () => { exceptionItem={exceptionItem} dataTestSubj="item" listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={ruleReferences} + ruleReferences={rules} securityLinkAnchorComponent={() => null} formattedDateComponent={() => null} getFormattedComments={() => []} @@ -102,7 +82,7 @@ describe('ExceptionItemCard', () => { expect(wrapper.queryByTestId('itemActionButton')).not.toBeInTheDocument(); }); - it('it invokes "onEditException" when edit button clicked', () => { + it('it should invoke the "onEditException" when edit button clicked', () => { const mockOnEditException = jest.fn(); const exceptionItem = getExceptionListItemSchemaMock(); @@ -111,7 +91,7 @@ describe('ExceptionItemCard', () => { exceptionItem={exceptionItem} dataTestSubj="exceptionItemCardHeader" listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={ruleReferences} + ruleReferences={rules} onDeleteException={jest.fn()} onEditException={mockOnEditException} securityLinkAnchorComponent={() => null} @@ -120,12 +100,12 @@ describe('ExceptionItemCard', () => { /> ); - fireEvent.click(wrapper.getByTestId('exceptionItemCardHeaderActionButton')); + fireEvent.click(wrapper.getByTestId('exceptionItemCardHeaderButtonIcon')); fireEvent.click(wrapper.getByTestId('exceptionItemCardHeaderActionItemedit')); expect(mockOnEditException).toHaveBeenCalledWith(getExceptionListItemSchemaMock()); }); - it('it invokes "onDeleteException" when delete button clicked', () => { + it('it should invoke the "onDeleteException" when delete button clicked', () => { const mockOnDeleteException = jest.fn(); const exceptionItem = getExceptionListItemSchemaMock(); @@ -134,7 +114,7 @@ describe('ExceptionItemCard', () => { exceptionItem={exceptionItem} dataTestSubj="exceptionItemCardHeader" listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={ruleReferences} + ruleReferences={rules} onEditException={jest.fn()} onDeleteException={mockOnDeleteException} securityLinkAnchorComponent={() => null} @@ -142,7 +122,7 @@ describe('ExceptionItemCard', () => { getFormattedComments={() => []} /> ); - fireEvent.click(wrapper.getByTestId('exceptionItemCardHeaderActionButton')); + fireEvent.click(wrapper.getByTestId('exceptionItemCardHeaderButtonIcon')); fireEvent.click(wrapper.getByTestId('exceptionItemCardHeaderActionItemdelete')); expect(mockOnDeleteException).toHaveBeenCalledWith({ @@ -152,21 +132,25 @@ describe('ExceptionItemCard', () => { }); }); - // TODO Fix this Test - // it('it renders comment accordion closed to begin with', () => { - // const exceptionItem = getExceptionListItemSchemaMock(); - // exceptionItem.comments = getCommentsArrayMock(); - // const wrapper = render( - // - // ); - - // expect(wrapper.queryByTestId('accordion-comment-list')).not.toBeVisible(); - // }); + it('it should render comment accordion closed to begin with', () => { + const exceptionItem = getExceptionListItemSchemaMock(); + exceptionItem.comments = getCommentsArrayMock(); + const wrapper = render( + null} + formattedDateComponent={() => null} + getFormattedComments={mockGetFormattedComments} + /> + ); + + expect(wrapper.getByTestId('exceptionsItemCommentAccordion')).toBeInTheDocument(); + expect(wrapper.getByTestId('exceptionItemCardComments')).toBeVisible(); + expect(wrapper.getByTestId('accordionContentPanel')).not.toBeVisible(); + }); }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx index c3705750d015d..a9aa5c7dedd87 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useMemo, useCallback, FC } from 'react'; +import React, { FC, ElementType } from 'react'; import { EuiPanel, EuiFlexGroup, EuiFlexItem, EuiCommentProps } from '@elastic/eui'; import type { CommentsArray, @@ -14,7 +14,6 @@ import type { ExceptionListTypeEnum, } from '@kbn/securitysolution-io-ts-list-types'; -import * as i18n from './translations'; import { ExceptionItemCardHeader, ExceptionItemCardConditions, @@ -22,18 +21,19 @@ import { ExceptionItemCardComments, } from '.'; -import type { ExceptionListItemIdentifiers } from '../types'; +import type { ExceptionListItemIdentifiers, Rule } from '../types'; +import { useExceptionItemCard } from './use_exception_item_card'; export interface ExceptionItemProps { dataTestSubj?: string; disableActions?: boolean; exceptionItem: ExceptionListItemSchema; listType: ExceptionListTypeEnum; - ruleReferences: any[]; // rulereferences + ruleReferences: Rule[]; editActionLabel?: string; deleteActionLabel?: string; - securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - formattedDateComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + securityLinkAnchorComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + formattedDateComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common getFormattedComments: (comments: CommentsArray) => EuiCommentProps[]; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common onDeleteException: (arg: ExceptionListItemIdentifiers) => void; onEditException: (item: ExceptionListItemSchema) => void; @@ -53,47 +53,24 @@ const ExceptionItemCardComponent: FC = ({ onDeleteException, onEditException, }) => { - const handleDelete = useCallback((): void => { - onDeleteException({ - id: exceptionItem.id, - name: exceptionItem.name, - namespaceType: exceptionItem.namespace_type, - }); - }, [onDeleteException, exceptionItem.id, exceptionItem.name, exceptionItem.namespace_type]); - - const handleEdit = useCallback((): void => { - onEditException(exceptionItem); - }, [onEditException, exceptionItem]); - - const formattedComments = useMemo((): EuiCommentProps[] => { - return getFormattedComments(exceptionItem.comments); - }, [exceptionItem.comments, getFormattedComments]); - - const actions: Array<{ - key: string; - icon: string; - label: string | boolean; - onClick: () => void; - }> = useMemo( - () => [ - { - key: 'edit', - icon: 'controlsHorizontal', - label: editActionLabel || i18n.exceptionItemCardEditButton(listType), - onClick: handleEdit, - }, - { - key: 'delete', - icon: 'trash', - label: deleteActionLabel || listType === i18n.exceptionItemCardDeleteButton(listType), - onClick: handleDelete, - }, - ], - [editActionLabel, listType, deleteActionLabel, handleDelete, handleEdit] - ); + const { actions, formattedComments } = useExceptionItemCard({ + listType, + editActionLabel, + deleteActionLabel, + exceptionItem, + getFormattedComments, + onEditException, + onDeleteException, + }); return ( - - + + = ({ = ({ {formattedComments.length > 0 && ( )} diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx index 7f7f20dfc234d..71bc57e98a274 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx @@ -8,30 +8,13 @@ import React from 'react'; -import { getExceptionListItemSchemaMock } from '../../test_helpers/exception_list_item_schema.mock'; -import * as i18n from '../translations'; -import { ExceptionItemCardHeader } from './header'; +import { getExceptionListItemSchemaMock } from '../../mocks/exception_list_item_schema.mock'; +import { ExceptionItemCardHeader } from '.'; import { fireEvent, render } from '@testing-library/react'; -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { actions, handleDelete, handleEdit } from '../../mocks/header.mock'; -const handleEdit = jest.fn(); -const handleDelete = jest.fn(); -const actions = [ - { - key: 'edit', - icon: 'pencil', - label: i18n.exceptionItemCardEditButton(ExceptionListTypeEnum.DETECTION), - onClick: handleEdit, - }, - { - key: 'delete', - icon: 'trash', - label: i18n.exceptionItemCardDeleteButton(ExceptionListTypeEnum.DETECTION), - onClick: handleDelete, - }, -]; describe('ExceptionItemCardHeader', () => { - it('it renders item name', () => { + it('it should render item name', () => { const wrapper = render( { expect(wrapper.getByTestId('exceptionItemHeaderTitle')).toHaveTextContent('some name'); }); - it('it displays actions', () => { + it('it should display actions', () => { const wrapper = render( { /> ); - // click on popover - fireEvent.click(wrapper.getByTestId('exceptionItemHeaderActionButton')); + fireEvent.click(wrapper.getByTestId('exceptionItemHeaderButtonIcon')); fireEvent.click(wrapper.getByTestId('exceptionItemHeaderActionItemedit')); expect(handleEdit).toHaveBeenCalled(); @@ -61,7 +43,7 @@ describe('ExceptionItemCardHeader', () => { expect(handleDelete).toHaveBeenCalled(); }); - it('it disables actions if disableActions is true', () => { + it('it should disable actions if disableActions is true', () => { const wrapper = render( { /> ); - expect(wrapper.getByTestId('exceptionItemHeaderActionButton')).toBeDisabled(); + expect(wrapper.getByTestId('exceptionItemHeaderButtonIcon')).toBeDisabled(); }); }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx deleted file mode 100644 index d58cb8d99b7a1..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.tsx +++ /dev/null @@ -1,83 +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, { memo, useMemo, useState } from 'react'; -import type { EuiContextMenuPanelProps } from '@elastic/eui'; -import { - EuiButtonIcon, - EuiContextMenuPanel, - EuiFlexGroup, - EuiFlexItem, - EuiPopover, - EuiTitle, - EuiContextMenuItem, -} from '@elastic/eui'; -import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export interface ExceptionItemCardHeaderProps { - item: ExceptionListItemSchema; - actions: Array<{ key: string; icon: string; label: string | boolean; onClick: () => void }>; - disableActions?: boolean; - dataTestSubj: string; -} - -export const ExceptionItemCardHeader = memo( - ({ item, actions, disableActions = false, dataTestSubj }) => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - const onItemActionsClick = () => setIsPopoverOpen((isOpen) => !isOpen); - const onClosePopover = () => setIsPopoverOpen(false); - - const itemActions = useMemo((): EuiContextMenuPanelProps['items'] => { - return actions.map((action) => ( - { - onClosePopover(); - action.onClick(); - }} - > - {action.label} - - )); - }, [dataTestSubj, actions]); - - return ( - - - -

    {item.name}

    -
    -
    - - - } - panelPaddingSize="none" - isOpen={isPopoverOpen} - closePopover={onClosePopover} - data-test-subj={`${dataTestSubj}Items`} - > - - - -
    - ); - } -); - -ExceptionItemCardHeader.displayName = 'ExceptionItemCardHeader'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx new file mode 100644 index 0000000000000..27b53db53673c --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx @@ -0,0 +1,44 @@ +/* + * 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, { memo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { HeaderMenu } from '../../header_menu'; + +export interface ExceptionItemCardHeaderProps { + item: ExceptionListItemSchema; + actions: Array<{ key: string; icon: string; label: string | boolean; onClick: () => void }>; + disableActions?: boolean; + dataTestSubj: string; +} + +export const ExceptionItemCardHeader = memo( + ({ item, actions, disableActions = false, dataTestSubj }) => { + return ( + + + +

    {item.name}

    +
    +
    + + + +
    + ); + } +); + +ExceptionItemCardHeader.displayName = 'ExceptionItemCardHeader'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts index c0fd3fafc86d5..37a4d04561979 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -export * from './conditions/conditions'; -export * from './header/header'; -export * from './meta/meta'; -export * from './comments/comments'; +export * from './conditions'; +export * from './header'; +export * from './meta'; +export * from './comments'; export * from './exception_item_card'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/__snapshots__/details_info.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/__snapshots__/details_info.test.tsx.snap new file mode 100644 index 0000000000000..0575fac4f345b --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/__snapshots__/details_info.test.tsx.snap @@ -0,0 +1,411 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MetaInfoDetails should render lastUpdate as JSX Element 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + created_by +
    +
    +
    + + + +

    + Last update value +

    +
    +
    +
    +
    +
    +
    + by +
    +
    +
    +
    +
    + + + + value + + + +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + created_by +
    +
    +
    + + + +

    + Last update value +

    +
    +
    +
    +
    +
    +
    + by +
    +
    +
    +
    +
    + + + + value + + + +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`MetaInfoDetails should render lastUpdate as string 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + created_by +
    +
    +
    + + + + last update + + + +
    +
    +
    + by +
    +
    +
    +
    +
    + + + + value + + + +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + created_by +
    +
    +
    + + + + last update + + + +
    +
    +
    + by +
    +
    +
    +
    +
    + + + + value + + + +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx new file mode 100644 index 0000000000000..7c994e0cce6b2 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.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 { render } from '@testing-library/react'; +import { MetaInfoDetails } from '.'; + +describe('MetaInfoDetails', () => { + it('should render lastUpdate as string', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('MetaInfoDetailslastUpdate')).toHaveTextContent('last update'); + }); + it('should render lastUpdate as JSX Element', () => { + const wrapper = render( + Last update value

    } + lastUpdateValue="value" + /> + ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('MetaInfoDetailslastUpdate')).toHaveTextContent('Last update value'); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx similarity index 85% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.tsx rename to packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx index 3d075f50096d0..f18b5c0dd31df 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx @@ -13,11 +13,10 @@ import { euiThemeVars } from '@kbn/ui-theme'; import * as i18n from '../../translations'; interface MetaInfoDetailsProps { - fieldName: string; label: string; lastUpdate: JSX.Element | string; lastUpdateValue: string; - dataTestSubj: string; + dataTestSubj?: string; } const euiBadgeFontFamily = css` @@ -26,13 +25,19 @@ const euiBadgeFontFamily = css` export const MetaInfoDetails = memo( ({ label, lastUpdate, lastUpdateValue, dataTestSubj }) => { return ( - + {label} - + {lastUpdate} @@ -42,8 +47,8 @@ export const MetaInfoDetails = memo( {i18n.EXCEPTION_ITEM_CARD_META_BY} - - + + {lastUpdateValue} diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx new file mode 100644 index 0000000000000..1d7d6a3568380 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx @@ -0,0 +1,97 @@ +/* + * 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, { memo, useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import * as i18n from '../translations'; +import type { Rule } from '../../types'; +import { MetaInfoDetails } from './details_info'; +import { HeaderMenu } from '../../header_menu'; +import { generateLinkedRulesMenuItems } from '../../generate_linked_rules_menu_item'; + +const itemCss = css` + border-right: 1px solid #d3dae6; + padding: ${euiThemeVars.euiSizeS} ${euiThemeVars.euiSizeM} ${euiThemeVars.euiSizeS} 0; +`; + +export interface ExceptionItemCardMetaInfoProps { + item: ExceptionListItemSchema; + rules: Rule[]; + dataTestSubj: string; + formattedDateComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common +} + +export const ExceptionItemCardMetaInfo = memo( + ({ item, rules, dataTestSubj, securityLinkAnchorComponent, formattedDateComponent }) => { + const FormattedDateComponent = formattedDateComponent; + + const referencedLinks = useMemo( + () => + generateLinkedRulesMenuItems({ + dataTestSubj, + linkedRules: rules, + securityLinkAnchorComponent, + }), + [dataTestSubj, rules, securityLinkAnchorComponent] + ); + return ( + + {FormattedDateComponent !== null && ( + <> + + + } + lastUpdateValue={item.created_by} + dataTestSubj={`${dataTestSubj || ''}CreatedBy`} + /> + + + + + } + lastUpdateValue={item.updated_by} + dataTestSubj={`${dataTestSubj || ''}UpdatedBy`} + /> + + + )} + + + + + ); + } +); +ExceptionItemCardMetaInfo.displayName = 'ExceptionItemCardMetaInfo'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx index c5ad9bd7af313..3a42760afaba8 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx @@ -8,38 +8,17 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { getExceptionListItemSchemaMock } from '../../test_helpers/exception_list_item_schema.mock'; +import { getExceptionListItemSchemaMock } from '../../mocks/exception_list_item_schema.mock'; -import { ExceptionItemCardMetaInfo } from './meta'; -import { RuleReference } from '../../types'; +import { ExceptionItemCardMetaInfo } from '.'; +import { rules } from '../../mocks/rule_references.mock'; -const ruleReferences = [ - { - exception_lists: [ - { - id: '123', - list_id: 'i_exist', - namespace_type: 'single', - type: 'detection', - }, - { - id: '456', - list_id: 'i_exist_2', - namespace_type: 'single', - type: 'detection', - }, - ], - id: '1a2b3c', - name: 'Simple Rule Query', - rule_id: 'rule-2', - }, -]; describe('ExceptionItemCardMetaInfo', () => { it('it should render creation info with sending custom formattedDateComponent', () => { const wrapper = render( null} formattedDateComponent={({ fieldName, value }) => ( @@ -62,7 +41,7 @@ describe('ExceptionItemCardMetaInfo', () => { const wrapper = render( null} formattedDateComponent={({ fieldName, value }) => ( @@ -84,71 +63,67 @@ describe('ExceptionItemCardMetaInfo', () => { const wrapper = render( null} formattedDateComponent={() => null} /> ); - expect(wrapper.getByTestId('exceptionItemMetaAffectedRulesButton')).toHaveTextContent( - 'Affects 1 rule' - ); + expect(wrapper.getByTestId('exceptionItemMetaEmptyButton')).toHaveTextContent('Affects 1 rule'); }); - it('it renders references info when multiple references exist', () => { + it('it should render references info when multiple references exist', () => { const wrapper = render( null} formattedDateComponent={() => null} /> ); - expect(wrapper.getByTestId('exceptionItemMetaAffectedRulesButton')).toHaveTextContent( + expect(wrapper.getByTestId('exceptionItemMetaEmptyButton')).toHaveTextContent( 'Affects 2 rules' ); }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx deleted file mode 100644 index 91e0a9cdd19b8..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.tsx +++ /dev/null @@ -1,123 +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, { memo, useMemo, useState } from 'react'; -import type { EuiContextMenuPanelProps } from '@elastic/eui'; -import { - EuiContextMenuItem, - EuiContextMenuPanel, - EuiFlexGroup, - EuiFlexItem, - EuiToolTip, - EuiButtonEmpty, - EuiPopover, -} from '@elastic/eui'; -import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { css } from '@emotion/react'; -import * as i18n from '../translations'; -import type { RuleReference } from '../../types'; -import { MetaInfoDetails } from './details_info/details_info'; - -const itemCss = css` - border-right: 1px solid #d3dae6; - padding: 4px 12px 4px 0; -`; - -export interface ExceptionItemCardMetaInfoProps { - item: ExceptionListItemSchema; - references: RuleReference[]; - dataTestSubj: string; - formattedDateComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common -} - -export const ExceptionItemCardMetaInfo = memo( - ({ item, references, dataTestSubj, securityLinkAnchorComponent, formattedDateComponent }) => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - const onAffectedRulesClick = () => setIsPopoverOpen((isOpen) => !isOpen); - const onClosePopover = () => setIsPopoverOpen(false); - - const FormattedDateComponent = formattedDateComponent; - const itemActions = useMemo((): EuiContextMenuPanelProps['items'] => { - if (references == null || securityLinkAnchorComponent === null) { - return []; - } - - const SecurityLinkAnchor = securityLinkAnchorComponent; - return references.map((reference) => ( - - - - - - )); - }, [references, securityLinkAnchorComponent, dataTestSubj]); - - return ( - - {FormattedDateComponent !== null && ( - <> - - - } - lastUpdateValue={item.created_by} - dataTestSubj={`${dataTestSubj}CreatedBy`} - /> - - - - - } - lastUpdateValue={item.updated_by} - dataTestSubj={`${dataTestSubj}UpdatedBy`} - /> - - - )} - - - {i18n.AFFECTED_RULES(references.length)} - - } - panelPaddingSize="none" - isOpen={isPopoverOpen} - closePopover={onClosePopover} - data-test-subj={`${dataTestSubj}Items`} - > - - - - - ); - } -); -ExceptionItemCardMetaInfo.displayName = 'ExceptionItemCardMetaInfo'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts new file mode 100644 index 0000000000000..b8bbfaa70b612 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts @@ -0,0 +1,122 @@ +/* + * 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 { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { getExceptionListItemSchemaMock } from '../mocks/exception_list_item_schema.mock'; +import { useExceptionItemCard } from './use_exception_item_card'; +import * as i18n from './translations'; +import { mockGetFormattedComments } from '../mocks/comments.mock'; + +const onEditException = jest.fn(); +const onDeleteException = jest.fn(); +const getFormattedComments = jest.fn(); +const exceptionItem = getExceptionListItemSchemaMock(); +describe('useExceptionItemCard', () => { + it('should call onEditException with the correct params', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionItemCard({ + listType: ExceptionListTypeEnum.DETECTION, + exceptionItem, + onEditException, + onDeleteException, + getFormattedComments, + }) + ); + const { actions } = current; + + act(() => { + actions[0].onClick(); + }); + expect(onEditException).toHaveBeenCalledWith(exceptionItem); + }); + it('should call onDeleteException with the correct params', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionItemCard({ + listType: ExceptionListTypeEnum.DETECTION, + exceptionItem, + onEditException, + onDeleteException, + getFormattedComments, + }) + ); + const { actions } = current; + + act(() => { + actions[1].onClick(); + }); + expect(onDeleteException).toHaveBeenCalledWith({ + id: exceptionItem.id, + name: exceptionItem.name, + namespaceType: exceptionItem.namespace_type, + }); + }); + it('should return the default actions labels', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionItemCard({ + listType: ExceptionListTypeEnum.DETECTION, + exceptionItem, + onEditException, + onDeleteException, + getFormattedComments, + }) + ); + const { actions } = current; + const [editAction, deleteAction] = actions; + + expect(editAction.label).toEqual( + i18n.exceptionItemCardEditButton(ExceptionListTypeEnum.DETECTION) + ); + expect(deleteAction.label).toEqual( + i18n.exceptionItemCardDeleteButton(ExceptionListTypeEnum.DETECTION) + ); + }); + it('should return the default sent labels props', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionItemCard({ + listType: ExceptionListTypeEnum.DETECTION, + exceptionItem, + editActionLabel: 'Edit', + deleteActionLabel: 'Delete', + onEditException, + onDeleteException, + getFormattedComments, + }) + ); + const { actions } = current; + const [editAction, deleteAction] = actions; + + expect(editAction.label).toEqual('Edit'); + expect(deleteAction.label).toEqual('Delete'); + }); + it('should return formattedComments', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionItemCard({ + listType: ExceptionListTypeEnum.DETECTION, + exceptionItem, + editActionLabel: 'Edit', + deleteActionLabel: 'Delete', + onEditException, + onDeleteException, + getFormattedComments: mockGetFormattedComments, + }) + ); + const { formattedComments } = current; + expect(formattedComments[0].username).toEqual('some user'); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts new file mode 100644 index 0000000000000..dda7ae7d7aa04 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts @@ -0,0 +1,81 @@ +/* + * 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 { useCallback, useMemo } from 'react'; +import { EuiCommentProps } from '@elastic/eui'; + +import { + CommentsArray, + ExceptionListItemSchema, + ExceptionListTypeEnum, +} from '@kbn/securitysolution-io-ts-list-types'; +import * as i18n from './translations'; +import { ExceptionListItemIdentifiers } from '../types'; + +interface UseExceptionItemCardProps { + exceptionItem: ExceptionListItemSchema; + listType: ExceptionListTypeEnum; + editActionLabel?: string; + deleteActionLabel?: string; + getFormattedComments: (comments: CommentsArray) => EuiCommentProps[]; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + onDeleteException: (arg: ExceptionListItemIdentifiers) => void; + onEditException: (item: ExceptionListItemSchema) => void; +} + +export const useExceptionItemCard = ({ + listType, + editActionLabel, + deleteActionLabel, + exceptionItem, + getFormattedComments, + onEditException, + onDeleteException, +}: UseExceptionItemCardProps) => { + const handleDelete = useCallback((): void => { + onDeleteException({ + id: exceptionItem.id, + name: exceptionItem.name, + namespaceType: exceptionItem.namespace_type, + }); + }, [onDeleteException, exceptionItem.id, exceptionItem.name, exceptionItem.namespace_type]); + + const handleEdit = useCallback((): void => { + onEditException(exceptionItem); + }, [onEditException, exceptionItem]); + + const formattedComments = useMemo((): EuiCommentProps[] => { + return getFormattedComments(exceptionItem.comments); + }, [exceptionItem.comments, getFormattedComments]); + + const actions: Array<{ + key: string; + icon: string; + label: string | boolean; + onClick: () => void; + }> = useMemo( + () => [ + { + key: 'edit', + icon: 'controlsHorizontal', + label: editActionLabel || i18n.exceptionItemCardEditButton(listType), + onClick: handleEdit, + }, + { + key: 'delete', + icon: 'trash', + label: deleteActionLabel || i18n.exceptionItemCardDeleteButton(listType), + onClick: handleDelete, + }, + ], + [editActionLabel, listType, deleteActionLabel, handleDelete, handleEdit] + ); + return { + actions, + formattedComments, + }; +}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx index 39c429dd1f1dd..da5df52996952 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx @@ -8,13 +8,17 @@ import React from 'react'; -import { getExceptionListItemSchemaMock } from '../test_helpers/exception_list_item_schema.mock'; +import { getExceptionListItemSchemaMock } from '../mocks/exception_list_item_schema.mock'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { ExceptionItems } from './exception_items'; +import { ExceptionItems } from '.'; import { ViewerStatus } from '../types'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; +import { ruleReferences } from '../mocks/rule_references.mock'; +import { Pagination } from '@elastic/eui'; +import { mockGetFormattedComments } from '../mocks/comments.mock'; +import { securityLinkAnchorComponentMock } from '../mocks/security_link_component.mock'; const onCreateExceptionListItem = jest.fn(); const onDeleteException = jest.fn(); @@ -25,7 +29,7 @@ const pagination = { pageIndex: 0, pageSize: 0, totalItemCount: 0 }; describe('ExceptionsViewerItems', () => { describe('Viewing EmptyViewerState', () => { - it('it renders empty prompt if "viewerStatus" is "empty"', () => { + it('it should render empty prompt if "viewerStatus" is "empty"', () => { const wrapper = render( { getFormattedComments={() => []} /> ); - // expect(wrapper).toMatchSnapshot(); expect(wrapper.getByTestId('emptyViewerState')).toBeInTheDocument(); expect(wrapper.queryByTestId('exceptionsContainer')).not.toBeInTheDocument(); }); - it('it renders no search results found prompt if "viewerStatus" is "empty_search"', () => { + it('it should render no search results found prompt if "viewerStatus" is "empty_search"', () => { const wrapper = render( { getFormattedComments={() => []} /> ); - // expect(wrapper).toMatchSnapshot(); expect(wrapper.getByTestId('emptySearchViewerState')).toBeInTheDocument(); expect(wrapper.queryByTestId('exceptionsContainer')).not.toBeInTheDocument(); }); - - it('it renders exceptions if "viewerStatus" and "null"', () => { + }); + describe('Exception Items and Pagination', () => { + it('it should render exceptions if exception array is not empty', () => { const wrapper = render( { getFormattedComments={() => []} /> ); - // expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('exceptionsContainer')).toBeInTheDocument(); + expect(wrapper.getByTestId('exceptionItemCard')).toBeInTheDocument(); + expect(wrapper.getAllByTestId('exceptionItemCard')).toHaveLength(1); + }); + it('it should render pagination section', () => { + const exceptions = [ + getExceptionListItemSchemaMock(), + { ...getExceptionListItemSchemaMock(), id: '2' }, + ]; + const wrapper = render( + null} + formattedDateComponent={() => null} + exceptionsUtilityComponent={() => null} + getFormattedComments={() => []} + /> + ); expect(wrapper.getByTestId('exceptionsContainer')).toBeTruthy(); + expect(wrapper.getAllByTestId('exceptionItemCard')).toHaveLength(2); + expect(wrapper.getByTestId('pagination')).toBeInTheDocument(); + }); + }); + + describe('securityLinkAnchorComponent, formattedDateComponent, exceptionsUtilityComponent and getFormattedComments', () => { + it('it should render sent securityLinkAnchorComponent', () => { + const wrapper = render( + null} + exceptionsUtilityComponent={() => null} + getFormattedComments={() => []} + /> + ); + expect(wrapper.getByTestId('exceptionsContainer')).toBeInTheDocument(); + fireEvent.click(wrapper.getByTestId('exceptionItemCardMetaInfoEmptyButton')); + expect(wrapper.getByTestId('securityLinkAnchorComponent')).toBeInTheDocument(); + }); + it('it should render sent exceptionsUtilityComponent', () => { + const exceptionsUtilityComponent = ({ + pagination: utilityPagination, + lastUpdated, + }: { + pagination: Pagination; + lastUpdated: string; + }) => ( +
    + {lastUpdated} + {utilityPagination.pageIndex} +
    + ); + const wrapper = render( + null} + formattedDateComponent={() => null} + exceptionsUtilityComponent={exceptionsUtilityComponent} + getFormattedComments={() => []} + /> + ); + expect(wrapper.getByTestId('exceptionsContainer')).toBeInTheDocument(); + expect(wrapper.getByTestId('exceptionsUtilityComponent')).toBeInTheDocument(); + expect(wrapper.getByTestId('lastUpdateTestUtility')).toHaveTextContent('1666003695578'); + expect(wrapper.getByTestId('paginationTestUtility')).toHaveTextContent('0'); + }); + it('it should render sent formattedDateComponent', () => { + const formattedDateComponent = ({ + fieldName, + value, + }: { + fieldName: string; + value: string; + }) => ( +
    + {fieldName} + {value} +
    + ); + const wrapper = render( + null} + formattedDateComponent={formattedDateComponent} + exceptionsUtilityComponent={() => null} + getFormattedComments={() => []} + /> + ); + expect(wrapper.getByTestId('exceptionsContainer')).toBeInTheDocument(); + expect(wrapper.getAllByTestId('formattedDateComponent')).toHaveLength(2); + expect(wrapper.getAllByTestId('fieldNameTestFormatted')[0]).toHaveTextContent('created_at'); + expect(wrapper.getAllByTestId('fieldNameTestFormatted')[1]).toHaveTextContent('updated_at'); + expect(wrapper.getAllByTestId('valueTestFormatted')[0]).toHaveTextContent( + '2020-04-20T15:25:31.830Z' + ); + expect(wrapper.getAllByTestId('valueTestFormatted')[0]).toHaveTextContent( + '2020-04-20T15:25:31.830Z' + ); + }); + it('it should use getFormattedComments to extract comments', () => { + const wrapper = render( + null} + formattedDateComponent={() => null} + exceptionsUtilityComponent={() => null} + getFormattedComments={mockGetFormattedComments} + /> + ); + expect(wrapper.getByTestId('exceptionsContainer')).toBeInTheDocument(); + expect(wrapper.getByTestId('exceptionsItemCommentAccordion')).toBeInTheDocument(); }); }); - // TODO Add Exception Items and Pagination interactions }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx similarity index 75% rename from packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.tsx rename to packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx index 80ab3d99f6eb8..647ff3a14458a 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { ElementType } from 'react'; import { css } from '@emotion/react'; import type { FC } from 'react'; import { EuiCommentProps, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; @@ -47,9 +47,12 @@ interface ExceptionItemsProps { listType: ExceptionListTypeEnum; ruleReferences: RuleReferences; pagination: PaginationType; - securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - formattedDateComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - exceptionsUtilityComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + editActionLabel?: string; + deleteActionLabel?: string; + dataTestSubj?: string; + securityLinkAnchorComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + formattedDateComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + exceptionsUtilityComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common getFormattedComments: (comments: CommentsArray) => EuiCommentProps[]; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common onCreateExceptionListItem?: () => void; onDeleteException: (arg: ExceptionListItemIdentifiers) => void; @@ -68,6 +71,9 @@ const ExceptionItemsComponent: FC = ({ emptyViewerBody, emptyViewerButtonText, pagination, + dataTestSubj, + editActionLabel, + deleteActionLabel, securityLinkAnchorComponent, exceptionsUtilityComponent, formattedDateComponent, @@ -96,24 +102,31 @@ const ExceptionItemsComponent: FC = ({ {exceptions.map((exception) => ( - + = ({ diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/__snapshots__/generate_linked_rules_menu_item.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/__snapshots__/generate_linked_rules_menu_item.test.tsx.snap new file mode 100644 index 0000000000000..7c2e71a7ffe93 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/__snapshots__/generate_linked_rules_menu_item.test.tsx.snap @@ -0,0 +1,267 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateLinedRulesMenuItems should render the first linked rules with left icon and does not apply the css if the length is 1 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    + +
    + , + "container":
    + +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`generateLinedRulesMenuItems should render the second linked rule and apply the css when the length is > 1 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    + +
    + , + "container":
    + +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx new file mode 100644 index 0000000000000..2158f05f63534 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx @@ -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 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 { render } from '@testing-library/react'; +import { ReactElement } from 'react'; +import { ElementType } from 'react'; +import { generateLinkedRulesMenuItems } from '.'; +import { rules } from '../mocks/rule_references.mock'; +import { + getSecurityLinkAction, + securityLinkAnchorComponentMock, +} from '../mocks/security_link_component.mock'; + +const dataTestSubj = 'generateLinedRulesMenuItemsTest'; +const linkedRules = rules; + +describe('generateLinedRulesMenuItems', () => { + it('should not render if the linkedRules length is falsy', () => { + const result = generateLinkedRulesMenuItems({ + dataTestSubj, + linkedRules: [], + securityLinkAnchorComponent: securityLinkAnchorComponentMock, + }); + expect(result).toBeNull(); + }); + it('should not render if the securityLinkAnchorComponent length is falsy', () => { + const result = generateLinkedRulesMenuItems({ + dataTestSubj, + linkedRules, + securityLinkAnchorComponent: null as unknown as ElementType, + }); + expect(result).toBeNull(); + }); + it('should render the first linked rules with left icon and does not apply the css if the length is 1', () => { + const result: ReactElement[] = generateLinkedRulesMenuItems({ + dataTestSubj, + linkedRules, + securityLinkAnchorComponent: securityLinkAnchorComponentMock, + leftIcon: 'check', + }) as ReactElement[]; + + result.map((link) => { + const wrapper = render(link); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('generateLinedRulesMenuItemsTestActionItem1a2b3c')); + expect(wrapper.getByTestId('generateLinedRulesMenuItemsTestLeftIcon')); + }); + }); + it('should render the second linked rule and apply the css when the length is > 1', () => { + const result: ReactElement[] = getSecurityLinkAction(dataTestSubj); + + const wrapper = render(result[1]); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('generateLinedRulesMenuItemsTestActionItem2a2b3c')); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx new file mode 100644 index 0000000000000..a78a76319cbb5 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React, { ElementType, ReactElement } from 'react'; +import { EuiContextMenuItem, EuiFlexGroup, EuiFlexItem, EuiIcon, IconType } from '@elastic/eui'; +import { Rule } from '../types'; +import { itemContentCss, containerCss } from './menu_link.styles'; + +interface MenuItemLinkedRulesProps { + leftIcon?: IconType; + dataTestSubj?: string; + linkedRules: Rule[]; + securityLinkAnchorComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common +} + +export const generateLinkedRulesMenuItems = ({ + dataTestSubj, + linkedRules, + securityLinkAnchorComponent, + leftIcon = '', +}: MenuItemLinkedRulesProps): ReactElement[] | null => { + if (!linkedRules.length || securityLinkAnchorComponent === null) return null; + + const SecurityLinkAnchor = securityLinkAnchorComponent; + return linkedRules.map((rule) => { + return ( + 1 ? containerCss : ''} + data-test-subj={`${dataTestSubj || ''}ActionItem${rule.id}`} + key={rule.id} + > + + {leftIcon ? ( + + + + ) : null} + + + + + + ); + }); +}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts new file mode 100644 index 0000000000000..0cfbcf522bc24 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts @@ -0,0 +1,18 @@ +/* + * 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 { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; + +export const containerCss = css` + border-bottom: 1px solid ${euiThemeVars.euiColorLightShade}; +`; + +export const itemContentCss = css` + color: ${euiThemeVars.euiColorPrimary}; + flex-basis: content; +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap new file mode 100644 index 0000000000000..dd808cfd1889c --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap @@ -0,0 +1,626 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`HeaderMenu should render button icon with default settings 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`HeaderMenu should render custom Actions 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`HeaderMenu should render empty button icon with actions and open the popover when clicked 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`HeaderMenu should render empty button icon with actions and should not open the popover when clicked if disableActions 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`HeaderMenu should render empty button icon with different icon settings 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx new file mode 100644 index 0000000000000..b07079c721ff7 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx @@ -0,0 +1,106 @@ +/* + * 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 { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { HeaderMenu } from '.'; +import { actions } from '../mocks/header.mock'; +import { getSecurityLinkAction } from '../mocks/security_link_component.mock'; + +describe('HeaderMenu', () => { + it('should render button icon with default settings', () => { + const wrapper = render(); + + expect(wrapper).toMatchSnapshot(); + + expect(wrapper.getByTestId('ButtonIcon')).toBeInTheDocument(); + expect(wrapper.queryByTestId('EmptyButton')).not.toBeInTheDocument(); + expect(wrapper.queryByTestId('MenuPanel')).not.toBeInTheDocument(); + }); + + it('should render empty button icon with different icon settings', () => { + const wrapper = render( + + ); + + expect(wrapper).toMatchSnapshot(); + + expect(wrapper.getByTestId('EmptyButton')).toBeInTheDocument(); + expect(wrapper.queryByTestId('ButtonIcon')).not.toBeInTheDocument(); + expect(wrapper.queryByTestId('MenuPanel')).not.toBeInTheDocument(); + }); + + it('should render empty button icon with actions and open the popover when clicked', () => { + const wrapper = render( + + ); + + expect(wrapper).toMatchSnapshot(); + + expect(wrapper.getByTestId('EmptyButton')).toBeInTheDocument(); + expect(wrapper.queryByTestId('ButtonIcon')).not.toBeInTheDocument(); + fireEvent.click(wrapper.getByTestId('EmptyButton')); + expect(wrapper.getByTestId('ActionItemedit')).toBeInTheDocument(); + expect(wrapper.getByTestId('MenuPanel')).toBeInTheDocument(); + }); + it('should render empty button icon with actions and should not open the popover when clicked if disableActions', () => { + const wrapper = render( + + ); + + expect(wrapper).toMatchSnapshot(); + + expect(wrapper.getByTestId('EmptyButton')).toBeInTheDocument(); + expect(wrapper.queryByTestId('ButtonIcon')).not.toBeInTheDocument(); + fireEvent.click(wrapper.getByTestId('EmptyButton')); + expect(wrapper.queryByTestId('ActionItemedit')).not.toBeInTheDocument(); + expect(wrapper.queryByTestId('MenuPanel')).not.toBeInTheDocument(); + }); + + it('should call onEdit if action has onClick', () => { + const onEdit = jest.fn(); + const customAction = [...actions]; + customAction[0].onClick = onEdit; + const wrapper = render(); + fireEvent.click(wrapper.getByTestId('ButtonIcon')); + fireEvent.click(wrapper.getByTestId('ActionItemedit')); + expect(onEdit).toBeCalled(); + }); + + it('should render custom Actions', () => { + const customActions = getSecurityLinkAction('headerMenuTest'); + const wrapper = render( + + ); + + expect(wrapper).toMatchSnapshot(); + + expect(wrapper.getByTestId('EmptyButton')).toBeInTheDocument(); + fireEvent.click(wrapper.getByTestId('EmptyButton')); + expect(wrapper.queryByTestId('MenuPanel')).toBeInTheDocument(); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx new file mode 100644 index 0000000000000..43154a865a436 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx @@ -0,0 +1,125 @@ +/* + * 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, { FC, ReactElement, useMemo, useState } from 'react'; +import { + EuiButtonEmpty, + EuiButtonIcon, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiFlexGroup, + EuiPopover, + IconType, + PanelPaddingSize, + PopoverAnchorPosition, +} from '@elastic/eui'; +import { ButtonContentIconSide } from '@elastic/eui/src/components/button/_button_content_deprecated'; + +interface Action { + key: string; + icon: string; + label: string | boolean; + onClick: () => void; +} +interface HeaderMenuComponentProps { + disableActions: boolean; + actions: Action[] | ReactElement[] | null; + text?: string; + iconType?: IconType; + iconSide?: ButtonContentIconSide; + dataTestSubj?: string; + emptyButton?: boolean; + useCustomActions?: boolean; + anchorPosition?: PopoverAnchorPosition; + panelPaddingSize?: PanelPaddingSize; +} + +const HeaderMenuComponent: FC = ({ + text, + dataTestSubj, + actions, + disableActions, + emptyButton, + useCustomActions, + iconType = 'boxesHorizontal', + iconSide = 'left', + anchorPosition = 'downCenter', + panelPaddingSize = 's', +}) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const onAffectedRulesClick = () => setIsPopoverOpen((isOpen) => !isOpen); + const onClosePopover = () => setIsPopoverOpen(false); + + const itemActions = useMemo(() => { + if (useCustomActions || actions === null) return actions; + return (actions as Action[]).map((action) => ( + { + onClosePopover(); + if (typeof action.onClick === 'function') action.onClick(); + }} + > + {action.label} + + )); + }, [actions, dataTestSubj, useCustomActions]); + + return ( + + + {text} + + ) : ( + + {text} + + ) + } + panelPaddingSize={panelPaddingSize} + isOpen={isPopoverOpen} + closePopover={onClosePopover} + anchorPosition={anchorPosition} + data-test-subj={`${dataTestSubj || ''}Items`} + > + {!itemActions ? null : ( + + )} + + + ); +}; +HeaderMenuComponent.displayName = 'HeaderMenuComponent'; + +export const HeaderMenu = React.memo(HeaderMenuComponent); + +HeaderMenu.displayName = 'HeaderMenu'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap new file mode 100644 index 0000000000000..98f026e4ce947 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap @@ -0,0 +1,1711 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ExceptionListHeader should render edit modal 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +

    +
    + + List Name + + +
    +

    +
    +
    +

    +

    +
    + + List description + + +
    +
    +
    + List ID + : +
    +
    + List_Id +
    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +

    + Edit List Name +

    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +

    +
    + + List Name + + +
    +

    +
    +
    +

    +

    +
    + + List description + + +
    +
    +
    + List ID + : +
    +
    + List_Id +
    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`ExceptionListHeader should render the List Header with name, default description and actions 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +

    +
    + + List Name + + +
    +

    +
    +
    +

    +

    +
    + + Add a description + + +
    +
    +
    + List ID + : +
    +
    + List_Id +
    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +

    +
    + + List Name + + +
    +

    +
    +
    +

    +

    +
    + + Add a description + + +
    +
    +
    + List ID + : +
    +
    + List_Id +
    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`ExceptionListHeader should render the List Header with name, default description and disabled actions because of the ReadOnly mode 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +

    +
    + + List Name + +
    +

    +
    +
    +

    +

    +
    + + Add a description + +
    +
    +
    + List ID + : +
    +
    + List_Id +
    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    + +
    +
    +
    +

    +
    + + List Name + +
    +

    +
    +
    +

    +

    +
    + + Add a description + +
    +
    +
    + List ID + : +
    +
    + List_Id +
    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/__snapshots__/edit_modal.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/__snapshots__/edit_modal.test.tsx.snap new file mode 100644 index 0000000000000..8de3d7e099f40 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/__snapshots__/edit_modal.test.tsx.snap @@ -0,0 +1,227 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EditModal should render the title and description from listDetails 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    + +
    +
    +
    +

    + Edit list name +

    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + , + "container":
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx new file mode 100644 index 0000000000000..39786c1723b4f --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx @@ -0,0 +1,71 @@ +/* + * 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 { fireEvent, render } from '@testing-library/react'; +import { EditModal } from '.'; + +const onSave = jest.fn(); +const onCancel = jest.fn(); + +describe('EditModal', () => { + it('should render the title and description from listDetails', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('editModalTitle')).toHaveTextContent('list name'); + }); + it('should call onSave', () => { + const wrapper = render( + + ); + fireEvent.submit(wrapper.getByTestId('editModalForm')); + expect(onSave).toBeCalled(); + }); + it('should call onCancel', () => { + const wrapper = render( + + ); + fireEvent.click(wrapper.getByTestId('editModalCancelBtn')); + expect(onCancel).toBeCalled(); + }); + + it('should call change title, description and call onSave with the new props', () => { + const wrapper = render( + + ); + fireEvent.change(wrapper.getByTestId('editModalNameTextField'), { + target: { value: 'New list name' }, + }); + fireEvent.change(wrapper.getByTestId('editModalDescriptionTextField'), { + target: { value: 'New description name' }, + }); + fireEvent.submit(wrapper.getByTestId('editModalForm')); + + expect(onSave).toBeCalledWith({ + name: 'New list name', + description: 'New description name', + }); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx new file mode 100644 index 0000000000000..8ef4174128436 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx @@ -0,0 +1,99 @@ +/* + * 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, { ChangeEvent, FC, useState } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + useGeneratedHtmlId, +} from '@elastic/eui'; +import * as i18n from '../../translations'; +import { ListDetails } from '../../types'; + +interface EditModalProps { + listDetails: ListDetails; + onSave: (newListDetails: ListDetails) => void; + onCancel: () => void; +} + +const EditModalComponent: FC = ({ listDetails, onSave, onCancel }) => { + const modalFormId = useGeneratedHtmlId({ prefix: 'modalForm' }); + const [newListDetails, setNewListDetails] = useState(listDetails); + + const onChange = ({ target }: ChangeEvent) => { + const { name, value } = target; + setNewListDetails({ ...newListDetails, [name]: value }); + }; + const onSubmit = () => { + onSave(newListDetails); + }; + return ( + + + +

    {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_TITLE(listDetails.name)}

    +
    +
    + + + + + + + + + + + + + + + + {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_CANCEL_BUTTON} + + + + {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_SAVE_BUTTON} + + +
    + ); +}; +EditModalComponent.displayName = 'EditModalComponent'; + +export const EditModal = React.memo(EditModalComponent); + +EditModal.displayName = 'EditModal'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx new file mode 100644 index 0000000000000..570be26e2e84c --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx @@ -0,0 +1,126 @@ +/* + * 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 type { FC } from 'react'; +import { EuiIcon, EuiPageHeader, EuiText } from '@elastic/eui'; +import * as i18n from '../translations'; +import { + textWithEditContainerCss, + textCss, + descriptionContainerCss, + headerCss, +} from './list_header.styles'; +import { MenuItems } from './menu_items'; +import { TextWithEdit } from '../text_with_edit'; +import { EditModal } from './edit_modal'; +import { ListDetails, Rule } from '../types'; +import { useExceptionListHeader } from './use_list_header'; + +interface ExceptionListHeaderComponentProps { + name: string; + description?: string; + listId: string; + isReadonly: boolean; + linkedRules: Rule[]; + dataTestSubj?: string; + breadcrumbLink?: string; + securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + onEditListDetails: (listDetails: ListDetails) => void; + onExportList: () => void; + onDeleteList: () => void; + onManageRules: () => void; +} + +const ExceptionListHeaderComponent: FC = ({ + name, + description, + listId, + linkedRules, + isReadonly, + dataTestSubj, + securityLinkAnchorComponent, + breadcrumbLink, + onEditListDetails, + onExportList, + onDeleteList, + onManageRules, +}) => { + const { isModalVisible, listDetails, onEdit, onSave, onCancel } = useExceptionListHeader({ + name, + description, + onEditListDetails, + }); + return ( +
    + + } + responsive + data-test-subj={`${dataTestSubj || ''}PageHeader`} + description={ +
    + +
    + {i18n.EXCEPTION_LIST_HEADER_LIST_ID}: + {listId} +
    +
    + } + rightSideItems={[ + , + ]} + breadcrumbs={[ + { + text: ( +
    + + {i18n.EXCEPTION_LIST_HEADER_BREADCRUMB} +
    + ), + color: 'primary', + 'aria-current': false, + href: breadcrumbLink, + onClick: (e) => e.preventDefault(), + }, + ]} + /> + {isModalVisible && ( + + )} +
    + ); +}; + +ExceptionListHeaderComponent.displayName = 'ExceptionListHeaderComponent'; + +export const ExceptionListHeader = React.memo(ExceptionListHeaderComponent); + +ExceptionListHeader.displayName = 'ExceptionListHeader'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts b/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts new file mode 100644 index 0000000000000..ab9d6a5c79d53 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts @@ -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 { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; + +export const headerCss = css` + margin: ${euiThemeVars.euiSize}; +`; + +export const headerMenuCss = css` + border-right: 1px solid #d3dae6; + padding: ${euiThemeVars.euiSizeXS} ${euiThemeVars.euiSizeL} ${euiThemeVars.euiSizeXS} 0; +`; +export const textWithEditContainerCss = css` + display: flex; + width: fit-content; + align-items: baseline; + margin-bottom: ${euiThemeVars.euiSizeS}; + h1 { + margin-bottom: 0; + } +`; +export const textCss = css` + font-size: ${euiThemeVars.euiFontSize}; + color: ${euiThemeVars.euiTextSubduedColor}; + margin-left: ${euiThemeVars.euiSizeXS}; +`; +export const descriptionContainerCss = css` + margin-top: -${euiThemeVars.euiSizeL}; + margin-bottom: -${euiThemeVars.euiSizeL}; +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx new file mode 100644 index 0000000000000..df56194ce88e2 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx @@ -0,0 +1,104 @@ +/* + * 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 { fireEvent, render } from '@testing-library/react'; +import { ExceptionListHeader } from '.'; +import * as i18n from '../translations'; +import { securityLinkAnchorComponentMock } from '../mocks/security_link_component.mock'; + +import { useExceptionListHeader as useExceptionListHeaderMock } from './use_list_header'; +const onEditListDetails = jest.fn(); +const onExportList = jest.fn(); +const onDeleteList = jest.fn(); +const onManageRules = jest.fn(); +jest.mock('./use_list_header'); + +describe('ExceptionListHeader', () => { + beforeAll(() => { + (useExceptionListHeaderMock as jest.Mock).mockReturnValue({ + isModalVisible: false, + listDetails: { name: 'List Name', description: '' }, + onSave: jest.fn(), + onCancel: jest.fn(), + }); + }); + it('should render the List Header with name, default description and disabled actions because of the ReadOnly mode', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + fireEvent.click(wrapper.getByTestId('RightSideMenuItemsContainer')); + expect(wrapper.queryByTestId('MenuActions')).not.toBeInTheDocument(); + expect(wrapper.getByTestId('DescriptionText')).toHaveTextContent( + i18n.EXCEPTION_LIST_HEADER_DESCRIPTION + ); + expect(wrapper.queryByTestId('EditTitleIcon')).not.toBeInTheDocument(); + expect(wrapper.getByTestId('ListID')).toHaveTextContent( + `${i18n.EXCEPTION_LIST_HEADER_LIST_ID}:List_Id` + ); + expect(wrapper.getByTestId('Breadcrumb')).toHaveTextContent( + i18n.EXCEPTION_LIST_HEADER_BREADCRUMB + ); + }); + it('should render the List Header with name, default description and actions', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + fireEvent.click(wrapper.getByTestId('RightSideMenuItemsContainer')); + expect(wrapper.getByTestId('DescriptionText')).toHaveTextContent( + i18n.EXCEPTION_LIST_HEADER_DESCRIPTION + ); + expect(wrapper.queryByTestId('TitleEditIcon')).toBeInTheDocument(); + expect(wrapper.queryByTestId('DescriptionEditIcon')).toBeInTheDocument(); + }); + it('should render edit modal', () => { + (useExceptionListHeaderMock as jest.Mock).mockReturnValue({ + isModalVisible: true, + listDetails: { name: 'List Name', description: 'List description' }, + onSave: jest.fn(), + onCancel: jest.fn(), + }); + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('EditModal')).toBeInTheDocument(); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap new file mode 100644 index 0000000000000..ab3ad9df8aa81 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap @@ -0,0 +1,248 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MenuItems should render linkedRules, manageRules and menuActions 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + , + "container":
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx new file mode 100644 index 0000000000000..1e13a8ac3d0f2 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx @@ -0,0 +1,112 @@ +/* + * 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 { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { FC, useMemo } from 'react'; +import { HeaderMenu } from '../../header_menu'; +import { headerMenuCss } from '../list_header.styles'; +import * as i18n from '../../translations'; +import { Rule } from '../../types'; +import { generateLinkedRulesMenuItems } from '../../generate_linked_rules_menu_item'; +interface MenuItemsProps { + isReadonly: boolean; + dataTestSubj?: string; + linkedRules: Rule[]; + securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + onExportList: () => void; + onDeleteList: () => void; + onManageRules: () => void; +} + +const MenuItemsComponent: FC = ({ + dataTestSubj, + linkedRules, + securityLinkAnchorComponent, + isReadonly, + onExportList, + onDeleteList, + onManageRules, +}) => { + const referencedLinks = useMemo( + () => + generateLinkedRulesMenuItems({ + leftIcon: 'check', + dataTestSubj, + linkedRules, + securityLinkAnchorComponent, + }), + [dataTestSubj, linkedRules, securityLinkAnchorComponent] + ); + return ( + + + + + + + { + if (typeof onExportList === 'function') onManageRules(); + }} + > + {i18n.EXCEPTION_LIST_HEADER_MANAGE_RULES_BUTTON} + + + + + { + if (typeof onExportList === 'function') onExportList(); + }, + }, + { + key: '2', + icon: 'trash', + label: i18n.EXCEPTION_LIST_HEADER_DELETE_ACTION, + onClick: () => { + if (typeof onDeleteList === 'function') onDeleteList(); + }, + }, + ]} + disableActions={isReadonly} + anchorPosition="downCenter" + /> + + + ); +}; + +MenuItemsComponent.displayName = 'MenuItemsComponent'; + +export const MenuItems = React.memo(MenuItemsComponent); + +MenuItems.displayName = 'MenuItems'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx new file mode 100644 index 0000000000000..95d03a5b4678e --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx @@ -0,0 +1,81 @@ +/* + * 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 { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { MenuItems } from '.'; +import { rules } from '../../mocks/rule_references.mock'; +import { securityLinkAnchorComponentMock } from '../../mocks/security_link_component.mock'; + +const onExportList = jest.fn(); +const onDeleteList = jest.fn(); +const onManageRules = jest.fn(); +describe('MenuItems', () => { + it('should render linkedRules, manageRules and menuActions', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('LinkedRulesMenuItems')).toHaveTextContent('Linked to 1 rules'); + expect(wrapper.getByTestId('ManageRulesButton')).toBeInTheDocument(); + expect(wrapper.getByTestId('MenuActionsButtonIcon')).toBeInTheDocument(); + }); + it('should call onManageRules', () => { + const wrapper = render( + + ); + fireEvent.click(wrapper.getByTestId('ManageRulesButton')); + expect(onManageRules).toHaveBeenCalled(); + }); + it('should call onExportList', () => { + const wrapper = render( + + ); + fireEvent.click(wrapper.getByTestId('MenuActionsButtonIcon')); + fireEvent.click(wrapper.getByTestId('MenuActionsActionItem1')); + + expect(onExportList).toHaveBeenCalled(); + }); + it('should call onDeleteList', () => { + const wrapper = render( + + ); + fireEvent.click(wrapper.getByTestId('MenuActionsButtonIcon')); + fireEvent.click(wrapper.getByTestId('MenuActionsActionItem2')); + + expect(onDeleteList).toHaveBeenCalled(); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts b/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts new file mode 100644 index 0000000000000..9ddd782e132cd --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts @@ -0,0 +1,92 @@ +/* + * 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 { waitFor } from '@testing-library/dom'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { useExceptionListHeader } from './use_list_header'; + +describe('useExceptionListHeader', () => { + const onEditListDetails = jest.fn(); + it('should return the default values', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionListHeader({ name: 'list name', description: '', onEditListDetails }) + ); + const { isModalVisible, listDetails } = current; + expect(isModalVisible).toBeFalsy(); + expect(listDetails).toStrictEqual({ name: 'list name', description: '' }); + }); + it('should change the isModalVisible to be true when onEdit is called', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionListHeader({ name: 'list name', description: '', onEditListDetails }) + ); + const { isModalVisible, onEdit } = current; + act(() => { + onEdit(); + }); + + waitFor(() => { + expect(isModalVisible).toBeTruthy(); + }); + }); + + it('should call onEditListDetails with the new details after editing', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionListHeader({ name: 'list name', description: '', onEditListDetails }) + ); + const { isModalVisible, onEdit } = current; + act(() => { + onEdit(); + }); + + waitFor(() => { + expect(isModalVisible).toBeTruthy(); + }); + + const { onSave } = current; + act(() => { + onSave({ name: 'New name', description: 'New Description' }); + }); + + waitFor(() => { + expect(isModalVisible).toBeFalsy(); + expect(onEditListDetails).toBeCalledWith({ + name: 'New name', + description: 'New Description', + }); + }); + }); + it('should close the Modal when the cancel is called', () => { + const { + result: { current }, + } = renderHook(() => + useExceptionListHeader({ name: 'list name', description: '', onEditListDetails }) + ); + const { isModalVisible, onEdit } = current; + act(() => { + onEdit(); + }); + + waitFor(() => { + expect(isModalVisible).toBeTruthy(); + }); + + const { onCancel } = current; + act(() => { + onCancel(); + }); + + waitFor(() => { + expect(isModalVisible).toBeFalsy(); + }); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts b/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts new file mode 100644 index 0000000000000..01ddbf1ac68c6 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts @@ -0,0 +1,42 @@ +/* + * 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 { useState } from 'react'; +import { ListDetails } from '../types'; + +interface UseExceptionListHeaderProps { + name: string; + description?: string; + onEditListDetails: (listDetails: ListDetails) => void; +} +export const useExceptionListHeader = ({ + name, + description, + onEditListDetails, +}: UseExceptionListHeaderProps) => { + const [isModalVisible, setIsModalVisible] = useState(false); + const [listDetails, setListDetails] = useState({ name, description }); + const onEdit = () => { + setIsModalVisible(true); + }; + const onSave = (newListDetails: ListDetails) => { + setIsModalVisible(false); + setListDetails(newListDetails); + if (typeof onEditListDetails === 'function') onEditListDetails(newListDetails); + }; + const onCancel = () => { + setIsModalVisible(false); + }; + + return { + isModalVisible, + listDetails, + onEdit, + onSave, + onCancel, + }; +}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/test_helpers/comments.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx similarity index 78% rename from packages/kbn-securitysolution-exception-list-components/src/test_helpers/comments.mock.ts rename to packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx index 3e83aa53f0f23..3d562f1aa316a 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/test_helpers/comments.mock.ts +++ b/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import React from 'react'; import type { Comment, CommentsArray } from '@kbn/securitysolution-io-ts-list-types'; export const getCommentsMock = (): Comment => ({ @@ -16,3 +17,9 @@ export const getCommentsMock = (): Comment => ({ }); export const getCommentsArrayMock = (): CommentsArray => [getCommentsMock(), getCommentsMock()]; + +export const mockGetFormattedComments = () => + getCommentsArrayMock().map((comment) => ({ + username: comment.created_by, + children:

    {comment.comment}

    , + })); diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts new file mode 100644 index 0000000000000..7b82d120a9470 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.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 { Entry } from '../exception_item_card/conditions/types'; + +export const includedListTypeEntry: Entry = { + field: '', + operator: 'included', + type: 'list', + list: { id: 'list_id', type: 'boolean' }, +}; + +export const includedMatchTypeEntry: Entry = { + field: '', + operator: 'included', + type: 'match', + value: 'matches value', +}; + +export const includedExistsTypeEntry: Entry = { + field: '', + operator: 'included', + type: 'exists', +}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/test_helpers/exception_list_item_schema.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/test_helpers/exception_list_item_schema.mock.ts rename to packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts new file mode 100644 index 0000000000000..55e3199e0a99e --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.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 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 const handleEdit = jest.fn(); +export const handleDelete = jest.fn(); +export const actions = [ + { + key: 'edit', + icon: 'pencil', + label: 'Edit detection exception', + onClick: handleEdit, + }, + { + key: 'delete', + icon: 'trash', + label: 'Delete detection exception', + onClick: handleDelete, + }, +]; diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts new file mode 100644 index 0000000000000..d2a5e0ab0a756 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts @@ -0,0 +1,42 @@ +/* + * 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 { Rule, RuleReference } from '../types'; + +export const rules: Rule[] = [ + { + exception_lists: [ + { + id: '123', + list_id: 'i_exist', + namespace_type: 'single', + type: 'detection', + }, + { + id: '456', + list_id: 'i_exist_2', + namespace_type: 'single', + type: 'detection', + }, + ], + id: '1a2b3c', + name: 'Simple Rule Query', + rule_id: 'rule-2', + }, +]; + +export const ruleReference: RuleReference = { + name: 'endpoint list', + id: 'endpoint_list', + referenced_rules: rules, + listId: 'endpoint_list_id', +}; + +export const ruleReferences = { + endpoint_list_id: ruleReference, +}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx b/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx new file mode 100644 index 0000000000000..db0a64affc182 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx @@ -0,0 +1,36 @@ +/* + * 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, { ReactElement } from 'react'; +import { generateLinkedRulesMenuItems } from '../generate_linked_rules_menu_item'; +import { rules } from './rule_references.mock'; +export const securityLinkAnchorComponentMock = ({ + referenceName, + referenceId, +}: { + referenceName: string; + referenceId: string; +}) => ( + +); + +export const getSecurityLinkAction = (dataTestSubj: string) => + generateLinkedRulesMenuItems({ + dataTestSubj, + linkedRules: [ + ...rules, + { + exception_lists: [], + id: '2a2b3c', + name: 'Simple Rule Query 2', + rule_id: 'rule-2', + }, + ], + securityLinkAnchorComponent: securityLinkAnchorComponentMock, + }) as ReactElement[]; diff --git a/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.tsx b/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx similarity index 92% rename from packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.tsx rename to packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx index bb8dc6ee62559..a40393bac8fcc 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx @@ -9,7 +9,7 @@ import React, { useCallback } from 'react'; import type { FC } from 'react'; -import type { SearchFilterConfig } from '@elastic/eui'; +import type { IconType, SearchFilterConfig } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiSearchBar } from '@elastic/eui'; import type { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import type { GetExceptionItemProps } from '../types'; @@ -55,6 +55,8 @@ interface SearchBarProps { isSearching?: boolean; dataTestSubj?: string; filters?: SearchFilterConfig[]; // TODO about filters + isButtonFilled?: boolean; + buttonIconType?: IconType; onSearch: (arg: GetExceptionItemProps) => void; onAddExceptionClick: (type: ExceptionListTypeEnum) => void; } @@ -66,6 +68,8 @@ const SearchBarComponent: FC = ({ isSearching, dataTestSubj, filters = [], + isButtonFilled = true, + buttonIconType, onSearch, onAddExceptionClick, }) => { @@ -101,7 +105,8 @@ const SearchBarComponent: FC = ({ data-test-subj={`${dataTestSubj || ''}Button`} onClick={handleAddException} isDisabled={isSearching} - fill + fill={isButtonFilled} + iconType={buttonIconType} > {addExceptionButtonText} diff --git a/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx index ac82bb3b6e850..e6efe4eefb29b 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx +++ b/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx @@ -11,7 +11,7 @@ import { fireEvent, render } from '@testing-library/react'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { SearchBar } from './search_bar'; +import { SearchBar } from '.'; describe('SearchBar', () => { it('it does not display add exception button if user is read only', () => { diff --git a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/__snapshots__/text_with_edit.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/__snapshots__/text_with_edit.test.tsx.snap new file mode 100644 index 0000000000000..4543f84553ae6 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/__snapshots__/text_with_edit.test.tsx.snap @@ -0,0 +1,189 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TextWithEdit should not render the edit icon when isReadonly is true 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    + + Test + +
    +
    + , + "container":
    +
    + + Test + +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`TextWithEdit should render the edit icon when isReadonly is false 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    + + Test + + +
    +
    + , + "container":
    +
    + + Test + + +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx new file mode 100644 index 0000000000000..5b56b27053396 --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { FC } from 'react'; +import { EuiButtonIcon } from '@elastic/eui'; +import { Interpolation, Theme } from '@emotion/react'; +import { textWithEditContainerCss } from '../list_header/list_header.styles'; + +interface TextWithEditProps { + isReadonly: boolean; + dataTestSubj?: string; + text: string; + textCss?: Interpolation; + onEdit?: () => void; +} + +const TextWithEditComponent: FC = ({ + isReadonly, + dataTestSubj, + text, + onEdit, + textCss, +}) => { + return ( +
    + + {text} + + {isReadonly ? null : ( + (typeof onEdit === 'function' ? onEdit() : null)} + /> + )} +
    + ); +}; +TextWithEditComponent.displayName = 'TextWithEditComponent'; + +export const TextWithEdit = React.memo(TextWithEditComponent); + +TextWithEdit.displayName = 'TextWithEdit'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx new file mode 100644 index 0000000000000..a6973830e1d4e --- /dev/null +++ b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx @@ -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 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 { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { TextWithEdit } from '.'; + +describe('TextWithEdit', () => { + it('should not render the edit icon when isReadonly is true', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('TextWithEditTestText')).toHaveTextContent('Test'); + expect(wrapper.queryByTestId('TextWithEditTestEditIcon')).not.toBeInTheDocument(); + }); + it('should render the edit icon when isReadonly is false', () => { + const wrapper = render( + + ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.getByTestId('TextWithEditTestText')).toHaveTextContent('Test'); + expect(wrapper.getByTestId('TextWithEditTestEditIcon')).toBeInTheDocument(); + }); + it('should not call onEdit', () => { + const onEdit = ''; + const wrapper = render( + + ); + const editIcon = wrapper.getByTestId('TextWithEditTestEditIcon'); + expect(wrapper.getByTestId('TextWithEditTestText')).toHaveTextContent('Test'); + expect(editIcon).toBeInTheDocument(); + fireEvent.click(editIcon); + }); + it('should call onEdit', () => { + const onEdit = jest.fn(); + + const wrapper = render( + + ); + expect(wrapper.getByTestId('TextWithEditTestText')).toHaveTextContent('Test'); + expect(wrapper.queryByTestId('TextWithEditTestEditIcon')).toBeInTheDocument(); + fireEvent.click(wrapper.getByTestId('TextWithEditTestEditIcon')); + expect(onEdit).toBeCalled(); + }); +}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/translations.ts b/packages/kbn-securitysolution-exception-list-components/src/translations.ts index c919ef423c545..c5740958abcf4 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/translations.ts +++ b/packages/kbn-securitysolution-exception-list-components/src/translations.ts @@ -55,3 +55,88 @@ export const EMPTY_VIEWER_STATE_ERROR_BODY = i18n.translate( 'There was an error loading the exception items. Contact your administrator for help.', } ); +export const EXCEPTION_LIST_HEADER_EXPORT_ACTION = i18n.translate( + 'exceptionList-components.exception_list_header_export_action', + { + defaultMessage: 'Export exception list', + } +); +export const EXCEPTION_LIST_HEADER_DELETE_ACTION = i18n.translate( + 'exceptionList-components.exception_list_header_delete_action', + { + defaultMessage: 'Delete exception list', + } +); +export const EXCEPTION_LIST_HEADER_MANAGE_RULES_BUTTON = i18n.translate( + 'exceptionList-components.exception_list_header_manage_rules_button', + { + defaultMessage: 'Manage rules', + } +); + +export const EXCEPTION_LIST_HEADER_LINKED_RULES = (noOfRules: number) => + i18n.translate('exceptionList-components.exception_list_header_linked_rules', { + values: { noOfRules }, + defaultMessage: 'Linked to {noOfRules} rules', + }); + +export const EXCEPTION_LIST_HEADER_BREADCRUMB = i18n.translate( + 'exceptionList-components.exception_list_header_breadcrumb', + { + defaultMessage: 'Rule exceptions', + } +); + +export const EXCEPTION_LIST_HEADER_LIST_ID = i18n.translate( + 'exceptionList-components.exception_list_header_list_id', + { + defaultMessage: 'List ID', + } +); + +export const EXCEPTION_LIST_HEADER_NAME = i18n.translate( + 'exceptionList-components.exception_list_header_name', + { + defaultMessage: 'Add a name', + } +); + +export const EXCEPTION_LIST_HEADER_DESCRIPTION = i18n.translate( + 'exceptionList-components.exception_list_header_description', + { + defaultMessage: 'Add a description', + } +); + +export const EXCEPTION_LIST_HEADER_EDIT_MODAL_TITLE = (listName: string) => + i18n.translate('exceptionList-components.exception_list_header_edit_modal_name', { + defaultMessage: 'Edit {listName}', + values: { listName }, + }); + +export const EXCEPTION_LIST_HEADER_EDIT_MODAL_SAVE_BUTTON = i18n.translate( + 'exceptionList-components.exception_list_header_edit_modal_save_button', + { + defaultMessage: 'Save', + } +); + +export const EXCEPTION_LIST_HEADER_EDIT_MODAL_CANCEL_BUTTON = i18n.translate( + 'exceptionList-components.exception_list_header_edit_modal_cancel_button', + { + defaultMessage: 'Cancel', + } +); +export const EXCEPTION_LIST_HEADER_NAME_TEXTBOX = i18n.translate( + 'exceptionList-components.exception_list_header_Name_textbox', + { + defaultMessage: 'Name', + } +); + +export const EXCEPTION_LIST_HEADER_DESCRIPTION_TEXTBOX = i18n.translate( + 'exceptionList-components.exception_list_header_description_textbox', + { + defaultMessage: 'Description', + } +); diff --git a/packages/kbn-securitysolution-exception-list-components/src/types/index.ts b/packages/kbn-securitysolution-exception-list-components/src/types/index.ts index dbb402ca78451..d799879916dee 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/types/index.ts +++ b/packages/kbn-securitysolution-exception-list-components/src/types/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { ListArray } from '@kbn/securitysolution-io-ts-list-types'; import type { Pagination } from '@elastic/eui'; import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; @@ -42,7 +42,7 @@ export interface ExceptionListSummaryProps { export type ViewerFlyoutName = 'addException' | 'editException' | null; export interface RuleReferences { - [key: string]: any[]; // TODO fix + [key: string]: RuleReference; } export interface ExceptionListItemIdentifiers { @@ -56,10 +56,21 @@ export enum ListTypeText { DETECTION = 'empty', RULE_DEFAULT = 'empty_search', } +export interface Rule { + name: string; + id: string; + rule_id: string; + exception_lists: ListArray; +} export interface RuleReference { name: string; id: string; - ruleId: string; - exceptionLists: ExceptionListSchema[]; + referenced_rules: Rule[]; + listId?: string; +} + +export interface ListDetails { + name: string; + description?: string; } diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/index.ts index 75d5352c9f63e..7a200e4f4c8f9 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/index.ts @@ -20,7 +20,6 @@ export * from './src/default_severity_mapping_array'; export * from './src/default_threat_array'; export * from './src/default_to_string'; export * from './src/default_uuid'; -export * from './src/from'; export * from './src/language'; export * from './src/machine_learning_job_id'; export * from './src/max_signals'; @@ -28,6 +27,7 @@ export * from './src/normalized_ml_job_id'; export * from './src/references_default_array'; export * from './src/risk_score'; export * from './src/risk_score_mapping'; +export * from './src/rule_schedule'; export * from './src/saved_object_attributes'; export * from './src/severity'; export * from './src/severity_mapping'; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts index 023af9fc7050e..2e0d814bf93c5 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts @@ -6,42 +6,47 @@ * Side Public License, v 1. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import * as t from 'io-ts'; import { saved_object_attributes } from '../saved_object_attributes'; +export type RuleActionGroup = t.TypeOf; +export const RuleActionGroup = t.string; + +export type RuleActionId = t.TypeOf; +export const RuleActionId = t.string; + +export type RuleActionTypeId = t.TypeOf; +export const RuleActionTypeId = t.string; + /** * Params is an "object", since it is a type of RuleActionParams which is action templates. * @see x-pack/plugins/alerting/common/rule.ts */ -export const action_group = t.string; -export const action_id = t.string; -export const action_action_type_id = t.string; -export const action_params = saved_object_attributes; +export type RuleActionParams = t.TypeOf; +export const RuleActionParams = saved_object_attributes; -export const action = t.exact( +export type RuleAction = t.TypeOf; +export const RuleAction = t.exact( t.type({ - group: action_group, - id: action_id, - action_type_id: action_action_type_id, - params: action_params, + group: RuleActionGroup, + id: RuleActionId, + action_type_id: RuleActionTypeId, + params: RuleActionParams, }) ); -export type Action = t.TypeOf; +export type RuleActionArray = t.TypeOf; +export const RuleActionArray = t.array(RuleAction); -export const actions = t.array(action); -export type Actions = t.TypeOf; - -export const actionsCamel = t.array( - t.exact( - t.type({ - group: action_group, - id: action_id, - actionTypeId: action_action_type_id, - params: action_params, - }) - ) +export type RuleActionCamel = t.TypeOf; +export const RuleActionCamel = t.exact( + t.type({ + group: RuleActionGroup, + id: RuleActionId, + actionTypeId: RuleActionTypeId, + params: RuleActionParams, + }) ); -export type ActionsCamel = t.TypeOf; + +export type RuleActionArrayCamel = t.TypeOf; +export const RuleActionArrayCamel = t.array(RuleActionCamel); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts index 9d741aa65e079..be90cdc0816ef 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts @@ -8,12 +8,16 @@ import * as t from 'io-ts'; import { Either } from 'fp-ts/lib/Either'; -import { actions, Actions } from '../actions'; +import { RuleActionArray } from '../actions'; -export const DefaultActionsArray = new t.Type( +export const DefaultActionsArray = new t.Type< + RuleActionArray, + RuleActionArray | undefined, + unknown +>( 'DefaultActionsArray', - actions.is, - (input, context): Either => - input == null ? t.success([]) : actions.validate(input, context), + RuleActionArray.is, + (input, context): Either => + input == null ? t.success([]) : RuleActionArray.validate(input, context), t.identity ); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts index 55b76ab7c1a4e..d91499ee36089 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; import { Either } from 'fp-ts/lib/Either'; -import { from } from '../from'; +import { From } from '../from'; /** * Types the DefaultFromString as: @@ -21,7 +21,7 @@ export const DefaultFromString = new t.Type if (input == null) { return t.success('now-6m'); } - return from.validate(input, context); + return From.validate(input, context); }, t.identity ); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts index 8bd913af9255b..6d2314f684f1c 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts @@ -8,11 +8,11 @@ import * as t from 'io-ts'; import { Either } from 'fp-ts/lib/Either'; -import { RiskScoreMapping, risk_score_mapping } from '../risk_score_mapping'; +import { RiskScoreMapping } from '../risk_score_mapping'; /** * Types the DefaultStringArray as: - * - If null or undefined, then a default risk_score_mapping array will be set + * - If null or undefined, then a default RiskScoreMapping array will be set */ export const DefaultRiskScoreMappingArray = new t.Type< RiskScoreMapping, @@ -20,8 +20,8 @@ export const DefaultRiskScoreMappingArray = new t.Type< unknown >( 'DefaultRiskScoreMappingArray', - risk_score_mapping.is, + RiskScoreMapping.is, (input, context): Either => - input == null ? t.success([]) : risk_score_mapping.validate(input, context), + input == null ? t.success([]) : RiskScoreMapping.validate(input, context), t.identity ); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts index 58a96eef5a14f..b8e37e45c35f9 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts @@ -8,11 +8,11 @@ import * as t from 'io-ts'; import { Either } from 'fp-ts/lib/Either'; -import { SeverityMapping, severity_mapping } from '../severity_mapping'; +import { SeverityMapping } from '../severity_mapping'; /** * Types the DefaultStringArray as: - * - If null or undefined, then a default severity_mapping array will be set + * - If null or undefined, then a default SeverityMapping array will be set */ export const DefaultSeverityMappingArray = new t.Type< SeverityMapping, @@ -20,8 +20,8 @@ export const DefaultSeverityMappingArray = new t.Type< unknown >( 'DefaultSeverityMappingArray', - severity_mapping.is, + SeverityMapping.is, (input, context): Either => - input == null ? t.success([]) : severity_mapping.validate(input, context), + input == null ? t.success([]) : SeverityMapping.validate(input, context), t.identity ); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts index 30b3c727d87a2..97747696b90a3 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts @@ -12,7 +12,8 @@ import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; const stringValidator = (input: unknown): input is string => typeof input === 'string'; -export const from = new t.Type( +export type From = t.TypeOf; +export const From = new t.Type( 'From', t.string.is, (input, context): Either => { @@ -23,7 +24,3 @@ export const from = new t.Type( }, t.identity ); -export type From = t.TypeOf; - -export const fromOrUndefined = t.union([from, t.undefined]); -export type FromOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts index 98b9c33e7e3ea..c4f301d6a7c5d 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts @@ -6,8 +6,6 @@ * Side Public License, v 1. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import * as t from 'io-ts'; import { Either } from 'fp-ts/lib/Either'; @@ -16,6 +14,7 @@ import { Either } from 'fp-ts/lib/Either'; * - Natural Number (positive integer and not a float), * - Between the values [0 and 100] inclusive. */ +export type RiskScore = t.TypeOf; export const RiskScore = new t.Type( 'RiskScore', t.number.is, @@ -26,11 +25,3 @@ export const RiskScore = new t.Type( }, t.identity ); - -export type RiskScoreC = typeof RiskScore; - -export const risk_score = RiskScore; -export type RiskScore = t.TypeOf; - -export const riskScoreOrUndefined = t.union([risk_score, t.undefined]); -export type RiskScoreOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts index be07bab64f469..5b56e85cf4e8b 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts @@ -6,25 +6,19 @@ * Side Public License, v 1. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import * as t from 'io-ts'; import { operator } from '@kbn/securitysolution-io-ts-types'; -import { riskScoreOrUndefined } from '../risk_score'; +import { RiskScore } from '../risk_score'; -export const risk_score_mapping_field = t.string; -export const risk_score_mapping_value = t.string; -export const risk_score_mapping_item = t.exact( +export type RiskScoreMappingItem = t.TypeOf; +export const RiskScoreMappingItem = t.exact( t.type({ - field: risk_score_mapping_field, - value: risk_score_mapping_value, + field: t.string, + value: t.string, operator, - risk_score: riskScoreOrUndefined, + risk_score: t.union([RiskScore, t.undefined]), }) ); -export const risk_score_mapping = t.array(risk_score_mapping_item); -export type RiskScoreMapping = t.TypeOf; - -export const riskScoreMappingOrUndefined = t.union([risk_score_mapping, t.undefined]); -export type RiskScoreMappingOrUndefined = t.TypeOf; +export type RiskScoreMapping = t.TypeOf; +export const RiskScoreMapping = t.array(RiskScoreMappingItem); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts new file mode 100644 index 0000000000000..63fdfafe5631c --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.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 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 t from 'io-ts'; +import { From } from '../from'; + +export type RuleInterval = t.TypeOf; +export const RuleInterval = t.string; // we need a more specific schema + +export type RuleIntervalFrom = t.TypeOf; +export const RuleIntervalFrom = From; + +/** + * TODO: Create a regular expression type or custom date math part type here + */ +export type RuleIntervalTo = t.TypeOf; +export const RuleIntervalTo = t.string; // we need a more specific schema diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts index 4caafa6b6ecb2..19a35b56e05b4 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts @@ -8,8 +8,5 @@ import * as t from 'io-ts'; -export const severity = t.keyof({ low: null, medium: null, high: null, critical: null }); -export type Severity = t.TypeOf; - -export const severityOrUndefined = t.union([severity, t.undefined]); -export type SeverityOrUndefined = t.TypeOf; +export type Severity = t.TypeOf; +export const Severity = t.keyof({ low: null, medium: null, high: null, critical: null }); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts index 1a3fd50039c29..203f862426c37 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts @@ -6,27 +6,20 @@ * Side Public License, v 1. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import * as t from 'io-ts'; import { operator } from '@kbn/securitysolution-io-ts-types'; -import { severity } from '../severity'; +import { Severity } from '../severity'; -export const severity_mapping_field = t.string; -export const severity_mapping_value = t.string; -export const severity_mapping_item = t.exact( +export type SeverityMappingItem = t.TypeOf; +export const SeverityMappingItem = t.exact( t.type({ - field: severity_mapping_field, + field: t.string, operator, - value: severity_mapping_value, - severity, + value: t.string, + severity: Severity, }) ); -export type SeverityMappingItem = t.TypeOf; - -export const severity_mapping = t.array(severity_mapping_item); -export type SeverityMapping = t.TypeOf; -export const severityMappingOrUndefined = t.union([severity_mapping, t.undefined]); -export type SeverityMappingOrUndefined = t.TypeOf; +export type SeverityMapping = t.TypeOf; +export const SeverityMapping = t.array(SeverityMappingItem); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts index d7d636ad0994e..fbc75ca67693e 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts @@ -6,15 +6,12 @@ * Side Public License, v 1. */ -import { TimeDuration } from '@kbn/securitysolution-io-ts-types'; import * as t from 'io-ts'; +import { TimeDuration } from '@kbn/securitysolution-io-ts-types'; -export const throttle = t.union([ +export type RuleActionThrottle = t.TypeOf; +export const RuleActionThrottle = t.union([ t.literal('no_actions'), t.literal('rule'), TimeDuration({ allowedUnits: ['h', 'd'] }), ]); -export type Throttle = t.TypeOf; - -export const throttleOrNull = t.union([throttle, t.null]); -export type ThrottleOrNull = t.TypeOf; diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts index 6f4bc7d51052f..945afbbc8604e 100644 --- a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts @@ -14,7 +14,6 @@ import { EntriesArray, Entry, EntryNested, - ExceptionListItemSchema, ExceptionListType, ListSchema, NamespaceType, @@ -27,6 +26,8 @@ import { entry, exceptionListItemSchema, nestedEntryItem, + CreateRuleExceptionListItemSchema, + createRuleExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import { DataViewBase, @@ -55,6 +56,7 @@ import { EmptyEntry, EmptyNestedEntry, ExceptionsBuilderExceptionItem, + ExceptionsBuilderReturnExceptionItem, FormattedBuilderEntry, OperatorOption, } from '../types'; @@ -65,59 +67,60 @@ export const isEntryNested = (item: BuilderEntry): item is EntryNested => { export const filterExceptionItems = ( exceptions: ExceptionsBuilderExceptionItem[] -): Array => { - return exceptions.reduce>( - (acc, exception) => { - const entries = exception.entries.reduce((nestedAcc, singleEntry) => { - const strippedSingleEntry = removeIdFromItem(singleEntry); - - if (entriesNested.is(strippedSingleEntry)) { - const nestedEntriesArray = strippedSingleEntry.entries.filter((singleNestedEntry) => { - const noIdSingleNestedEntry = removeIdFromItem(singleNestedEntry); - const [validatedNestedEntry] = validate(noIdSingleNestedEntry, nestedEntryItem); - return validatedNestedEntry != null; - }); - const noIdNestedEntries = nestedEntriesArray.map((singleNestedEntry) => - removeIdFromItem(singleNestedEntry) - ); - - const [validatedNestedEntry] = validate( - { ...strippedSingleEntry, entries: noIdNestedEntries }, - entriesNested - ); - - if (validatedNestedEntry != null) { - return [...nestedAcc, { ...singleEntry, entries: nestedEntriesArray }]; - } - return nestedAcc; - } else { - const [validatedEntry] = validate(strippedSingleEntry, entry); - - if (validatedEntry != null) { - return [...nestedAcc, singleEntry]; - } - return nestedAcc; +): ExceptionsBuilderReturnExceptionItem[] => { + return exceptions.reduce((acc, exception) => { + const entries = exception.entries.reduce((nestedAcc, singleEntry) => { + const strippedSingleEntry = removeIdFromItem(singleEntry); + if (entriesNested.is(strippedSingleEntry)) { + const nestedEntriesArray = strippedSingleEntry.entries.filter((singleNestedEntry) => { + const noIdSingleNestedEntry = removeIdFromItem(singleNestedEntry); + const [validatedNestedEntry] = validate(noIdSingleNestedEntry, nestedEntryItem); + return validatedNestedEntry != null; + }); + const noIdNestedEntries = nestedEntriesArray.map((singleNestedEntry) => + removeIdFromItem(singleNestedEntry) + ); + + const [validatedNestedEntry] = validate( + { ...strippedSingleEntry, entries: noIdNestedEntries }, + entriesNested + ); + + if (validatedNestedEntry != null) { + return [...nestedAcc, { ...singleEntry, entries: nestedEntriesArray }]; } - }, []); - - if (entries.length === 0) { - return acc; + return nestedAcc; + } else { + const [validatedEntry] = validate(strippedSingleEntry, entry); + if (validatedEntry != null) { + return [...nestedAcc, singleEntry]; + } + return nestedAcc; } + }, []); - const item = { ...exception, entries }; + if (entries.length === 0) { + return acc; + } - if (exceptionListItemSchema.is(item)) { - return [...acc, item]; - } else if (createExceptionListItemSchema.is(item)) { - const { meta, ...rest } = item; - const itemSansMetaId: CreateExceptionListItemSchema = { ...rest, meta: undefined }; - return [...acc, itemSansMetaId]; - } else { - return acc; - } - }, - [] - ); + const item = { ...exception, entries }; + + if (exceptionListItemSchema.is(item)) { + return [...acc, item]; + } else if ( + createExceptionListItemSchema.is(item) || + createRuleExceptionListItemSchema.is(item) + ) { + const { meta, ...rest } = item; + const itemSansMetaId: CreateExceptionListItemSchema | CreateRuleExceptionListItemSchema = { + ...rest, + meta: undefined, + }; + return [...acc, itemSansMetaId]; + } else { + return acc; + } + }, []); }; export const addIdToEntries = (entries: EntriesArray): EntriesArray => { @@ -136,15 +139,15 @@ export const addIdToEntries = (entries: EntriesArray): EntriesArray => { export const getNewExceptionItem = ({ listId, namespaceType, - ruleName, + name, }: { listId: string | undefined; namespaceType: NamespaceType | undefined; - ruleName: string; + name: string; }): CreateExceptionListItemBuilderSchema => { return { comments: [], - description: 'Exception list item', + description: `Exception list item`, entries: addIdToEntries([ { field: '', @@ -158,7 +161,7 @@ export const getNewExceptionItem = ({ meta: { temporaryUuid: uuid.v4(), }, - name: `${ruleName} - exception list item`, + name, namespace_type: namespaceType, tags: [], type: 'simple', @@ -769,13 +772,15 @@ export const getCorrespondingKeywordField = ({ * @param parent nested entries hold copy of their parent for use in various logic * @param parentIndex corresponds to the entry index, this might seem obvious, but * was added to ensure that nested items could be identified with their parent entry + * @param allowCustomFieldOptions determines if field must be found to match in indexPattern or not */ export const getFormattedBuilderEntry = ( indexPattern: DataViewBase, item: BuilderEntry, itemIndex: number, parent: EntryNested | undefined, - parentIndex: number | undefined + parentIndex: number | undefined, + allowCustomFieldOptions: boolean ): FormattedBuilderEntry => { const { fields } = indexPattern; const field = parent != null ? `${parent.field}.${item.field}` : item.field; @@ -800,10 +805,14 @@ export const getFormattedBuilderEntry = ( value: getEntryValue(item), }; } else { + const fieldToUse = allowCustomFieldOptions + ? foundField ?? { name: item.field, type: 'keyword' } + : foundField; + return { correspondingKeywordField, entryIndex: itemIndex, - field: foundField, + field: fieldToUse, id: item.id != null ? item.id : `${itemIndex}`, nested: undefined, operator: getExceptionOperatorSelect(item), @@ -819,8 +828,7 @@ export const getFormattedBuilderEntry = ( * * @param patterns DataViewBase containing available fields on rule index * @param entries exception item entries - * @param addNested boolean noting whether or not UI is currently - * set to add a nested field + * @param allowCustomFieldOptions determines if field must be found to match in indexPattern or not * @param parent nested entries hold copy of their parent for use in various logic * @param parentIndex corresponds to the entry index, this might seem obvious, but * was added to ensure that nested items could be identified with their parent entry @@ -828,6 +836,7 @@ export const getFormattedBuilderEntry = ( export const getFormattedBuilderEntries = ( indexPattern: DataViewBase, entries: BuilderEntry[], + allowCustomFieldOptions: boolean, parent?: EntryNested, parentIndex?: number ): FormattedBuilderEntry[] => { @@ -839,7 +848,8 @@ export const getFormattedBuilderEntries = ( item, index, parent, - parentIndex + parentIndex, + allowCustomFieldOptions ); return [...acc, newItemEntry]; } else { @@ -869,7 +879,13 @@ export const getFormattedBuilderEntries = ( } if (isEntryNested(item)) { - const nestedItems = getFormattedBuilderEntries(indexPattern, item.entries, item, index); + const nestedItems = getFormattedBuilderEntries( + indexPattern, + item.entries, + allowCustomFieldOptions, + item, + index + ); return [...acc, parentEntry, ...nestedItems]; } diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index ff13005aaf922..377bffcfdacc9 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -44,6 +44,7 @@ kibana_vars=( data.search.asyncSearch.waitForCompletion data.search.asyncSearch.keepAlive data.search.asyncSearch.batchedReduceSize + data.search.asyncSearch.pollInterval data.search.sessions.defaultExpiration data.search.sessions.enabled data.search.sessions.maxUpdateRetries diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx index 399d653e0b4b6..a497a629553fa 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx @@ -619,8 +619,8 @@ export const HeatmapComponent: FC = memo( xScale={xScale} ySortPredicate={yAxisColumn ? getSortPredicate(yAxisColumn) : 'dataIndex'} xSortPredicate={xAxisColumn ? getSortPredicate(xAxisColumn) : 'dataIndex'} - xAxisLabelName={xAxisColumn?.name} - yAxisLabelName={yAxisColumn?.name} + xAxisLabelName={xAxisColumn?.name || ''} + yAxisLabelName={yAxisColumn?.name || ''} xAxisTitle={args.gridConfig.isXAxisTitleVisible ? xAxisTitle : undefined} yAxisTitle={args.gridConfig.isYAxisTitleVisible ? yAxisTitle : undefined} xAxisLabelFormatter={(v) => diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts index 6c88d0ff6a62c..efdbe7e2d0088 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts @@ -77,14 +77,10 @@ export const errors = { i18n.translate('expressionXY.reusable.function.xyVis.errors.notUsedFillOpacityError', { defaultMessage: '`fillOpacity` argument is applicable only for area charts.', }), - valueLabelsForNotBarsOrHistogramBarsChartsError: () => - i18n.translate( - 'expressionXY.reusable.function.xyVis.errors.valueLabelsForNotBarsOrHistogramBarsChartsError', - { - defaultMessage: - '`valueLabels` argument is applicable only for bar charts, which are not histograms.', - } - ), + valueLabelsForNotBarsChartsError: () => + i18n.translate('expressionXY.reusable.function.xyVis.errors.valueLabelsForNotBarChartsError', { + defaultMessage: '`valueLabels` argument is applicable only for bar charts.', + }), dataBoundsForNotLineChartError: () => i18n.translate('expressionXY.reusable.function.xyVis.errors.dataBoundsForNotLineChartError', { defaultMessage: 'Only line charts can be fit to the data bounds', @@ -127,10 +123,6 @@ export const hasBarLayer = (layers: Array) => layers.some(({ seriesType }) => seriesType === SeriesTypes.AREA); -export const hasHistogramBarLayer = ( - layers: Array -) => layers.some(({ seriesType, isHistogram }) => seriesType === SeriesTypes.BAR && isHistogram); - export const isValidExtentWithCustomMode = (extent: AxisExtentConfigResult) => { const isValidLowerBound = extent.lowerBound === undefined || (extent.lowerBound !== undefined && extent.lowerBound <= 0); @@ -212,13 +204,9 @@ export const validateFillOpacity = (fillOpacity: number | undefined, hasArea: bo } }; -export const validateValueLabels = ( - valueLabels: ValueLabelMode, - hasBar: boolean, - hasNotHistogramBars: boolean -) => { - if ((!hasBar || !hasNotHistogramBars) && valueLabels !== ValueLabelModes.HIDE) { - throw new Error(errors.valueLabelsForNotBarsOrHistogramBarsChartsError()); +export const validateValueLabels = (valueLabels: ValueLabelMode, hasBar: boolean) => { + if (!hasBar && valueLabels !== ValueLabelModes.HIDE) { + throw new Error(errors.valueLabelsForNotBarsChartsError()); } }; diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts index f7577efc45b86..ac867401dbe24 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts @@ -15,7 +15,6 @@ import { DataLayerConfigResult, XYLayerConfig, XyVisFn, XYArgs } from '../types' import { hasAreaLayer, hasBarLayer, - hasHistogramBarLayer, validateExtents, validateFillOpacity, validateMarkSizeRatioLimits, @@ -112,9 +111,7 @@ export const xyVisFn: XyVisFn['fn'] = async (data, args, handlers) => { validateAddTimeMarker(dataLayers, args.addTimeMarker); validateMinTimeBarInterval(dataLayers, hasBar, args.minTimeBarInterval); - const hasNotHistogramBars = !hasHistogramBarLayer(dataLayers); - - validateValueLabels(args.valueLabels, hasBar, hasNotHistogramBars); + validateValueLabels(args.valueLabels, hasBar); validateMarkSizeRatioWithAccessor(args.markSizeRatio, dataLayers[0].markSizeAccessor); validateMarkSizeRatioLimits(args.markSizeRatio); validateLineWidthForChartType(lineWidth, args.seriesType); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap index a756ad587f396..5156571218658 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap @@ -5119,7 +5119,7 @@ exports[`XYChart component it renders stacked area 1`] = ` "getAll": [Function], } } - shouldShowValueLabels={false} + shouldShowValueLabels={true} syncColors={false} timeZone="UTC" titles={ @@ -6101,7 +6101,7 @@ exports[`XYChart component it renders stacked bar 1`] = ` "getAll": [Function], } } - shouldShowValueLabels={false} + shouldShowValueLabels={true} syncColors={false} timeZone="UTC" titles={ @@ -7083,7 +7083,7 @@ exports[`XYChart component it renders stacked horizontal bar 1`] = ` "getAll": [Function], } } - shouldShowValueLabels={false} + shouldShowValueLabels={true} syncColors={false} timeZone="UTC" titles={ diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index 240c4e182d43e..c03cb9a664f1a 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -523,12 +523,7 @@ export function XYChart({ }; }; - const shouldShowValueLabels = uiState - ? valueLabels !== ValueLabelModes.HIDE - : // No stacked bar charts - dataLayers.every((layer) => !layer.isStacked) && - // No histogram charts - !isHistogramViz; + const shouldShowValueLabels = !uiState || valueLabels !== ValueLabelModes.HIDE; const valueLabelsStyling = shouldShowValueLabels && diff --git a/src/plugins/console/public/lib/autocomplete_entities/mapping.ts b/src/plugins/console/public/lib/autocomplete_entities/mapping.ts index ddb6905fa6e53..71e72dac0a280 100644 --- a/src/plugins/console/public/lib/autocomplete_entities/mapping.ts +++ b/src/plugins/console/public/lib/autocomplete_entities/mapping.ts @@ -121,23 +121,9 @@ export class Mapping implements BaseMapping { }; loadMappings = (mappings: IndicesGetMappingResponse) => { - const maxMappingSize = Object.keys(mappings).length > 10 * 1024 * 1024; - let mappingsResponse; - if (maxMappingSize) { - // eslint-disable-next-line no-console - console.warn( - `Mapping size is larger than 10MB (${ - Object.keys(mappings).length / 1024 / 1024 - } MB). Ignoring...` - ); - mappingsResponse = {}; - } else { - mappingsResponse = mappings; - } - this.perIndexTypes = {}; - Object.entries(mappingsResponse).forEach(([index, indexMapping]) => { + Object.entries(mappings).forEach(([index, indexMapping]) => { const normalizedIndexMappings: Record = {}; let transformedMapping: Record = indexMapping; diff --git a/src/plugins/console/server/lib/utils/index.ts b/src/plugins/console/server/lib/utils/index.ts index 0da3e36b575e3..2c595640eefbf 100644 --- a/src/plugins/console/server/lib/utils/index.ts +++ b/src/plugins/console/server/lib/utils/index.ts @@ -8,3 +8,4 @@ export { encodePath } from './encode_path'; export { toURL } from './to_url'; +export { streamToJSON } from './stream_to_json'; diff --git a/src/plugins/console/server/lib/utils/stream_to_json.test.ts b/src/plugins/console/server/lib/utils/stream_to_json.test.ts new file mode 100644 index 0000000000000..780d3adb4a145 --- /dev/null +++ b/src/plugins/console/server/lib/utils/stream_to_json.test.ts @@ -0,0 +1,35 @@ +/* + * 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 { Readable } from 'stream'; +import { streamToJSON } from './stream_to_json'; +import type { IncomingMessage } from 'http'; + +describe('streamToString', () => { + it('should limit the response size', async () => { + const stream = new Readable({ + read() { + this.push('a'.repeat(1000)); + }, + }); + await expect( + streamToJSON(stream as IncomingMessage, 500) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Response size limit exceeded"`); + }); + + it('should parse the response', async () => { + const stream = new Readable({ + read() { + this.push('{"test": "test"}'); + this.push(null); + }, + }); + const result = await streamToJSON(stream as IncomingMessage, 5000); + expect(result).toEqual({ test: 'test' }); + }); +}); diff --git a/src/plugins/console/server/lib/utils/stream_to_json.ts b/src/plugins/console/server/lib/utils/stream_to_json.ts new file mode 100644 index 0000000000000..5ff1974e9fd47 --- /dev/null +++ b/src/plugins/console/server/lib/utils/stream_to_json.ts @@ -0,0 +1,27 @@ +/* + * 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 { IncomingMessage } from 'http'; + +export function streamToJSON(stream: IncomingMessage, limit: number) { + return new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + stream.on('data', (chunk) => { + chunks.push(chunk); + if (Buffer.byteLength(Buffer.concat(chunks)) > limit) { + stream.destroy(); + reject(new Error('Response size limit exceeded')); + } + }); + stream.on('end', () => { + const response = Buffer.concat(chunks).toString('utf8'); + resolve(JSON.parse(response)); + }); + stream.on('error', reject); + }); +} diff --git a/src/plugins/console/server/routes/api/console/autocomplete_entities/register_get_route.ts b/src/plugins/console/server/routes/api/console/autocomplete_entities/register_get_route.ts index 9d5778f0a9b0f..98bd51e901b09 100644 --- a/src/plugins/console/server/routes/api/console/autocomplete_entities/register_get_route.ts +++ b/src/plugins/console/server/routes/api/console/autocomplete_entities/register_get_route.ts @@ -7,8 +7,10 @@ */ import type { IScopedClusterClient } from '@kbn/core/server'; import { parse } from 'query-string'; +import type { IncomingMessage } from 'http'; import type { RouteDependencies } from '../../..'; import { API_BASE_PATH } from '../../../../../common/constants'; +import { streamToJSON } from '../../../../lib/utils'; interface Settings { indices: boolean; @@ -17,40 +19,74 @@ interface Settings { dataStreams: boolean; } +const RESPONSE_SIZE_LIMIT = 10 * 1024 * 1024; +// Limit the response size to 10MB, because the response can be very large and sending it to the client +// can cause the browser to hang. + async function getMappings(esClient: IScopedClusterClient, settings: Settings) { if (settings.fields) { - return esClient.asInternalUser.indices.getMapping(); + const stream = await esClient.asInternalUser.indices.getMapping(undefined, { + asStream: true, + }); + return streamToJSON(stream as unknown as IncomingMessage, RESPONSE_SIZE_LIMIT); } // If the user doesn't want autocomplete suggestions, then clear any that exist. - return Promise.resolve({}); + return {}; } async function getAliases(esClient: IScopedClusterClient, settings: Settings) { if (settings.indices) { - return esClient.asInternalUser.indices.getAlias(); + const stream = await esClient.asInternalUser.indices.getAlias(undefined, { + asStream: true, + }); + return streamToJSON(stream as unknown as IncomingMessage, RESPONSE_SIZE_LIMIT); } // If the user doesn't want autocomplete suggestions, then clear any that exist. - return Promise.resolve({}); + return {}; } async function getDataStreams(esClient: IScopedClusterClient, settings: Settings) { if (settings.dataStreams) { - return esClient.asInternalUser.indices.getDataStream(); + const stream = await esClient.asInternalUser.indices.getDataStream(undefined, { + asStream: true, + }); + return streamToJSON(stream as unknown as IncomingMessage, RESPONSE_SIZE_LIMIT); + } + // If the user doesn't want autocomplete suggestions, then clear any that exist. + return {}; +} + +async function getLegacyTemplates(esClient: IScopedClusterClient, settings: Settings) { + if (settings.templates) { + const stream = await esClient.asInternalUser.indices.getTemplate(undefined, { + asStream: true, + }); + return streamToJSON(stream as unknown as IncomingMessage, RESPONSE_SIZE_LIMIT); + } + // If the user doesn't want autocomplete suggestions, then clear any that exist. + return {}; +} + +async function getComponentTemplates(esClient: IScopedClusterClient, settings: Settings) { + if (settings.templates) { + const stream = await esClient.asInternalUser.cluster.getComponentTemplate(undefined, { + asStream: true, + }); + return streamToJSON(stream as unknown as IncomingMessage, RESPONSE_SIZE_LIMIT); } // If the user doesn't want autocomplete suggestions, then clear any that exist. - return Promise.resolve({}); + return {}; } -async function getTemplates(esClient: IScopedClusterClient, settings: Settings) { +async function getIndexTemplates(esClient: IScopedClusterClient, settings: Settings) { if (settings.templates) { - return Promise.all([ - esClient.asInternalUser.indices.getTemplate(), - esClient.asInternalUser.indices.getIndexTemplate(), - esClient.asInternalUser.cluster.getComponentTemplate(), - ]); + const stream = await esClient.asInternalUser.indices.getIndexTemplate(undefined, { + asStream: true, + }); + return streamToJSON(stream as unknown as IncomingMessage, RESPONSE_SIZE_LIMIT); } // If the user doesn't want autocomplete suggestions, then clear any that exist. - return Promise.resolve([]); + return {}; } export function registerGetRoute({ router, lib: { handleEsError } }: RouteDependencies) { @@ -71,11 +107,32 @@ export function registerGetRoute({ router, lib: { handleEsError } }: RouteDepend } const esClient = (await ctx.core).elasticsearch.client; - const mappings = await getMappings(esClient, settings); - const aliases = await getAliases(esClient, settings); - const dataStreams = await getDataStreams(esClient, settings); - const [legacyTemplates = {}, indexTemplates = {}, componentTemplates = {}] = - await getTemplates(esClient, settings); + + // Wait for all requests to complete, in case one of them fails return the successfull ones + const results = await Promise.allSettled([ + getMappings(esClient, settings), + getAliases(esClient, settings), + getDataStreams(esClient, settings), + getLegacyTemplates(esClient, settings), + getIndexTemplates(esClient, settings), + getComponentTemplates(esClient, settings), + ]); + + const [ + mappings, + aliases, + dataStreams, + legacyTemplates, + indexTemplates, + componentTemplates, + ] = results.map((result) => { + // If the request was successful, return the result + if (result.status === 'fulfilled') { + return result.value; + } + // If the request failed, return an empty object + return {}; + }); return response.ok({ body: { diff --git a/src/plugins/controls/public/control_group/control_group_renderer.tsx b/src/plugins/controls/public/control_group/control_group_renderer.tsx new file mode 100644 index 0000000000000..a1560a02568c0 --- /dev/null +++ b/src/plugins/controls/public/control_group/control_group_renderer.tsx @@ -0,0 +1,84 @@ +/* + * 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 uuid from 'uuid'; +import useLifecycles from 'react-use/lib/useLifecycles'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; + +import { IEmbeddable } from '@kbn/embeddable-plugin/public'; + +import { pluginServices } from '../services'; +import { getDefaultControlGroupInput } from '../../common'; +import { ControlGroupInput, ControlGroupOutput, CONTROL_GROUP_TYPE } from './types'; +import { ControlGroupContainer } from './embeddable/control_group_container'; + +export interface ControlGroupRendererProps { + input?: Partial>; + onEmbeddableLoad: (controlGroupContainer: ControlGroupContainer) => void; +} + +export const ControlGroupRenderer = ({ input, onEmbeddableLoad }: ControlGroupRendererProps) => { + const controlsRoot = useRef(null); + const [controlGroupContainer, setControlGroupContainer] = useState(); + + const id = useMemo(() => uuid.v4(), []); + + /** + * Use Lifecycles to load initial control group container + */ + useLifecycles( + () => { + const { embeddable } = pluginServices.getServices(); + + (async () => { + const container = (await embeddable + .getEmbeddableFactory< + ControlGroupInput, + ControlGroupOutput, + IEmbeddable + >(CONTROL_GROUP_TYPE) + ?.create({ id, ...getDefaultControlGroupInput(), ...input })) as ControlGroupContainer; + + if (controlsRoot.current) { + container.render(controlsRoot.current); + } + setControlGroupContainer(container); + onEmbeddableLoad(container); + })(); + }, + () => { + controlGroupContainer?.destroy(); + } + ); + + /** + * Update embeddable input when props input changes + */ + useEffect(() => { + let updateCanceled = false; + (async () => { + // check if applying input from props would result in any changes to the embeddable input + const isInputEqual = await controlGroupContainer?.getExplicitInputIsEqual({ + ...controlGroupContainer?.getInput(), + ...input, + }); + if (!controlGroupContainer || isInputEqual || updateCanceled) return; + controlGroupContainer.updateInput({ ...input }); + })(); + + return () => { + updateCanceled = true; + }; + }, [controlGroupContainer, input]); + + return
    ; +}; + +// required for dynamic import using React.lazy() +// eslint-disable-next-line import/no-default-export +export default ControlGroupRenderer; diff --git a/src/plugins/controls/public/control_group/control_group_strings.ts b/src/plugins/controls/public/control_group/control_group_strings.ts index 238a3b73f7576..381321c876c3e 100644 --- a/src/plugins/controls/public/control_group/control_group_strings.ts +++ b/src/plugins/controls/public/control_group/control_group_strings.ts @@ -9,10 +9,6 @@ import { i18n } from '@kbn/i18n'; export const ControlGroupStrings = { - getEmbeddableTitle: () => - i18n.translate('controls.controlGroup.title', { - defaultMessage: 'Control group', - }), getControlButtonTitle: () => i18n.translate('controls.controlGroup.toolbarButtonTitle', { defaultMessage: 'Controls', diff --git a/src/plugins/controls/public/control_group/editor/control_editor.tsx b/src/plugins/controls/public/control_group/editor/control_editor.tsx index fdc54dd3cad62..1e9c42ff420de 100644 --- a/src/plugins/controls/public/control_group/editor/control_editor.tsx +++ b/src/plugins/controls/public/control_group/editor/control_editor.tsx @@ -14,7 +14,7 @@ * Side Public License, v 1. */ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import useMount from 'react-use/lib/useMount'; import { @@ -36,7 +36,6 @@ import { EuiTextColor, } from '@elastic/eui'; import { DataViewListItem, DataView, DataViewField } from '@kbn/data-views-plugin/common'; -import { IFieldSubTypeMulti } from '@kbn/es-query'; import { LazyDataViewPicker, LazyFieldPicker, @@ -53,6 +52,7 @@ import { } from '../../types'; import { CONTROL_WIDTH_OPTIONS } from './editor_constants'; import { pluginServices } from '../../services'; +import { loadFieldRegistryFromDataViewId } from './data_control_editor_tools'; interface EditControlProps { embeddable?: ControlEmbeddable; isCreate: boolean; @@ -97,7 +97,7 @@ export const ControlEditor = ({ }: EditControlProps) => { const { dataViews: { getIdsWithTitle, getDefaultId, get }, - controls: { getControlTypes, getControlFactory }, + controls: { getControlFactory }, } = pluginServices.getServices(); const [state, setState] = useState({ dataViewListItems: [], @@ -112,49 +112,14 @@ export const ControlEditor = ({ embeddable ? embeddable.getInput().fieldName : undefined ); - const doubleLinkFields = (dataView: DataView) => { - // double link the parent-child relationship specifically for case-sensitivity support for options lists - const fieldRegistry: DataControlFieldRegistry = {}; - - for (const field of dataView.fields.getAll()) { - if (!fieldRegistry[field.name]) { - fieldRegistry[field.name] = { field, compatibleControlTypes: [] }; - } - const parentFieldName = (field.subType as IFieldSubTypeMulti)?.multi?.parent; - if (parentFieldName) { - fieldRegistry[field.name].parentFieldName = parentFieldName; - - const parentField = dataView.getFieldByName(parentFieldName); - if (!fieldRegistry[parentFieldName] && parentField) { - fieldRegistry[parentFieldName] = { field: parentField, compatibleControlTypes: [] }; - } - fieldRegistry[parentFieldName].childFieldName = field.name; - } - } - return fieldRegistry; - }; - - const fieldRegistry = useMemo(() => { - if (!state.selectedDataView) return; - const newFieldRegistry: DataControlFieldRegistry = doubleLinkFields(state.selectedDataView); - - const controlFactories = getControlTypes().map( - (controlType) => getControlFactory(controlType) as IEditableControlFactory - ); - state.selectedDataView.fields.map((dataViewField) => { - for (const factory of controlFactories) { - if (factory.isFieldCompatible) { - factory.isFieldCompatible(newFieldRegistry[dataViewField.name]); - } - } - - if (newFieldRegistry[dataViewField.name]?.compatibleControlTypes.length === 0) { - delete newFieldRegistry[dataViewField.name]; + const [fieldRegistry, setFieldRegistry] = useState(); + useEffect(() => { + (async () => { + if (state.selectedDataView?.id) { + setFieldRegistry(await loadFieldRegistryFromDataViewId(state.selectedDataView.id)); } - }); - - return newFieldRegistry; - }, [state.selectedDataView, getControlFactory, getControlTypes]); + })(); + }, [state.selectedDataView]); useMount(() => { let mounted = true; diff --git a/src/plugins/controls/public/control_group/editor/data_control_editor_tools.ts b/src/plugins/controls/public/control_group/editor/data_control_editor_tools.ts new file mode 100644 index 0000000000000..cb0d1db5f4a89 --- /dev/null +++ b/src/plugins/controls/public/control_group/editor/data_control_editor_tools.ts @@ -0,0 +1,70 @@ +/* + * 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 { IFieldSubTypeMulti } from '@kbn/es-query'; +import { DataView } from '@kbn/data-views-plugin/common'; + +import { pluginServices } from '../../services'; +import { DataControlFieldRegistry, IEditableControlFactory } from '../../types'; + +const dataControlFieldRegistryCache: { [key: string]: DataControlFieldRegistry } = {}; + +const doubleLinkFields = (dataView: DataView) => { + // double link the parent-child relationship specifically for case-sensitivity support for options lists + const fieldRegistry: DataControlFieldRegistry = {}; + + for (const field of dataView.fields.getAll()) { + if (!fieldRegistry[field.name]) { + fieldRegistry[field.name] = { field, compatibleControlTypes: [] }; + } + const parentFieldName = (field.subType as IFieldSubTypeMulti)?.multi?.parent; + if (parentFieldName) { + fieldRegistry[field.name].parentFieldName = parentFieldName; + + const parentField = dataView.getFieldByName(parentFieldName); + if (!fieldRegistry[parentFieldName] && parentField) { + fieldRegistry[parentFieldName] = { field: parentField, compatibleControlTypes: [] }; + } + fieldRegistry[parentFieldName].childFieldName = field.name; + } + } + return fieldRegistry; +}; + +export const loadFieldRegistryFromDataViewId = async ( + dataViewId: string +): Promise => { + if (dataControlFieldRegistryCache[dataViewId]) { + return dataControlFieldRegistryCache[dataViewId]; + } + const { + dataViews, + controls: { getControlTypes, getControlFactory }, + } = pluginServices.getServices(); + const dataView = await dataViews.get(dataViewId); + + const newFieldRegistry: DataControlFieldRegistry = doubleLinkFields(dataView); + + const controlFactories = getControlTypes().map( + (controlType) => getControlFactory(controlType) as IEditableControlFactory + ); + dataView.fields.map((dataViewField) => { + for (const factory of controlFactories) { + if (factory.isFieldCompatible) { + factory.isFieldCompatible(newFieldRegistry[dataViewField.name]); + } + } + + if (newFieldRegistry[dataViewField.name]?.compatibleControlTypes.length === 0) { + delete newFieldRegistry[dataViewField.name]; + } + }); + dataControlFieldRegistryCache[dataViewId] = newFieldRegistry; + + return newFieldRegistry; +}; diff --git a/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx b/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx index a1d8bc06f822a..35c251a179d09 100644 --- a/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx +++ b/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx @@ -9,7 +9,7 @@ import { skip, debounceTime, distinctUntilChanged } from 'rxjs/operators'; import React from 'react'; import ReactDOM from 'react-dom'; -import { Filter, uniqFilters } from '@kbn/es-query'; +import { compareFilters, COMPARE_ALL_OPTIONS, Filter, uniqFilters } from '@kbn/es-query'; import { BehaviorSubject, merge, Subject, Subscription } from 'rxjs'; import { EuiContextMenuPanel } from '@elastic/eui'; @@ -39,10 +39,11 @@ import { ControlGroupStrings } from '../control_group_strings'; import { EditControlGroup } from '../editor/edit_control_group'; import { ControlGroup } from '../component/control_group_component'; import { controlGroupReducers } from '../state/control_group_reducers'; -import { ControlEmbeddable, ControlInput, ControlOutput } from '../../types'; +import { ControlEmbeddable, ControlInput, ControlOutput, DataControlInput } from '../../types'; import { CreateControlButton, CreateControlButtonTypes } from '../editor/create_control'; import { CreateTimeSliderControlButton } from '../editor/create_time_slider_control'; import { TIME_SLIDER_CONTROL } from '../../time_slider'; +import { loadFieldRegistryFromDataViewId } from '../editor/data_control_editor_tools'; let flyoutRef: OverlayRef | undefined; export const setFlyoutRef = (newRef: OverlayRef | undefined) => { @@ -70,6 +71,9 @@ export class ControlGroupContainer extends Container< typeof controlGroupReducers >; + public onFiltersPublished$: Subject; + public onControlRemoved$: Subject; + public setLastUsedDataViewId = (lastUsedDataViewId: string) => { this.lastUsedDataViewId = lastUsedDataViewId; }; @@ -87,6 +91,27 @@ export class ControlGroupContainer extends Container< flyoutRef = undefined; } + public async addDataControlFromField({ + uuid, + dataViewId, + fieldName, + title, + }: { + uuid?: string; + dataViewId: string; + fieldName: string; + title?: string; + }) { + const fieldRegistry = await loadFieldRegistryFromDataViewId(dataViewId); + const field = fieldRegistry[fieldName]; + return this.addNewEmbeddable(field.compatibleControlTypes[0], { + id: uuid, + dataViewId, + fieldName, + title: title ?? fieldName, + } as DataControlInput); + } + /** * Returns a button that allows controls to be created externally using the embeddable * @param buttonType Controls the button styling @@ -185,6 +210,8 @@ export class ControlGroupContainer extends Container< ); this.recalculateFilters$ = new Subject(); + this.onFiltersPublished$ = new Subject(); + this.onControlRemoved$ = new Subject(); // build redux embeddable tools this.reduxEmbeddableTools = reduxEmbeddablePackage.createTools< @@ -249,6 +276,10 @@ export class ControlGroupContainer extends Container< return Object.keys(this.getInput().panels).length; }; + public updateFilterContext = (filters: Filter[]) => { + this.updateInput({ filters }); + }; + private recalculateFilters = () => { const allFilters: Filter[] = []; let timeslice; @@ -259,7 +290,11 @@ export class ControlGroupContainer extends Container< timeslice = childOutput.timeslice; } }); - this.updateOutput({ filters: uniqFilters(allFilters), timeslice }); + // if filters are different, publish them + if (!compareFilters(this.output.filters ?? [], allFilters ?? [], COMPARE_ALL_OPTIONS)) { + this.updateOutput({ filters: uniqFilters(allFilters), timeslice }); + this.onFiltersPublished$.next(allFilters); + } }; private recalculateDataViews = () => { @@ -304,6 +339,7 @@ export class ControlGroupContainer extends Container< order: currentOrder - 1, }; } + this.onControlRemoved$.next(idToRemove); return newPanels; } diff --git a/src/plugins/controls/public/control_group/embeddable/control_group_container_factory.ts b/src/plugins/controls/public/control_group/embeddable/control_group_container_factory.ts index bcbd31955f36e..366ad399baeea 100644 --- a/src/plugins/controls/public/control_group/embeddable/control_group_container_factory.ts +++ b/src/plugins/controls/public/control_group/embeddable/control_group_container_factory.ts @@ -14,12 +14,12 @@ * Side Public License, v 1. */ +import { i18n } from '@kbn/i18n'; import { Container, EmbeddableFactoryDefinition } from '@kbn/embeddable-plugin/public'; import { lazyLoadReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public'; import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common'; import { ControlGroupInput, CONTROL_GROUP_TYPE } from '../types'; -import { ControlGroupStrings } from '../control_group_strings'; import { createControlGroupExtract, createControlGroupInject, @@ -40,7 +40,9 @@ export class ControlGroupContainerFactory implements EmbeddableFactoryDefinition public isEditable = async () => false; public readonly getDisplayName = () => { - return ControlGroupStrings.getEmbeddableTitle(); + return i18n.translate('controls.controlGroup.title', { + defaultMessage: 'Control group', + }); }; public getDefaultInput(): Partial { diff --git a/src/plugins/controls/public/control_group/index.ts b/src/plugins/controls/public/control_group/index.ts index 60050786d7c11..ded1c29934d6e 100644 --- a/src/plugins/controls/public/control_group/index.ts +++ b/src/plugins/controls/public/control_group/index.ts @@ -6,8 +6,13 @@ * Side Public License, v 1. */ +import React from 'react'; + export type { ControlGroupContainer } from './embeddable/control_group_container'; export type { ControlGroupInput, ControlGroupOutput } from './types'; export { CONTROL_GROUP_TYPE } from './types'; export { ControlGroupContainerFactory } from './embeddable/control_group_container_factory'; + +export type { ControlGroupRendererProps } from './control_group_renderer'; +export const LazyControlGroupRenderer = React.lazy(() => import('./control_group_renderer')); diff --git a/src/plugins/controls/public/index.ts b/src/plugins/controls/public/index.ts index f55df5fa0f53a..ac7a2ab23df84 100644 --- a/src/plugins/controls/public/index.ts +++ b/src/plugins/controls/public/index.ts @@ -51,6 +51,7 @@ export { } from './range_slider'; export { LazyControlsCallout, type CalloutProps } from './controls_callout'; +export { LazyControlGroupRenderer, type ControlGroupRendererProps } from './control_group'; export function plugin() { return new ControlsPlugin(); diff --git a/src/plugins/controls/public/services/embeddable/embeddable.story.ts b/src/plugins/controls/public/services/embeddable/embeddable.story.ts new file mode 100644 index 0000000000000..caeb5c0395fa7 --- /dev/null +++ b/src/plugins/controls/public/services/embeddable/embeddable.story.ts @@ -0,0 +1,18 @@ +/* + * 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 { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; +import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { ControlsEmbeddableService } from './types'; + +export type EmbeddableServiceFactory = PluginServiceFactory; +export const embeddableServiceFactory: EmbeddableServiceFactory = () => { + const { doStart } = embeddablePluginMock.createInstance(); + const start = doStart(); + return { getEmbeddableFactory: start.getEmbeddableFactory }; +}; diff --git a/src/plugins/controls/public/services/embeddable/embeddable_service.ts b/src/plugins/controls/public/services/embeddable/embeddable_service.ts new file mode 100644 index 0000000000000..06111098e673b --- /dev/null +++ b/src/plugins/controls/public/services/embeddable/embeddable_service.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 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 { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; +import { ControlsEmbeddableService } from './types'; +import { ControlsPluginStartDeps } from '../../types'; + +export type EmbeddableServiceFactory = KibanaPluginServiceFactory< + ControlsEmbeddableService, + ControlsPluginStartDeps +>; + +export const embeddableServiceFactory: EmbeddableServiceFactory = ({ startPlugins }) => { + return { + getEmbeddableFactory: startPlugins.embeddable.getEmbeddableFactory, + }; +}; diff --git a/src/plugins/controls/public/services/embeddable/types.ts b/src/plugins/controls/public/services/embeddable/types.ts new file mode 100644 index 0000000000000..4ddbecd9dbb30 --- /dev/null +++ b/src/plugins/controls/public/services/embeddable/types.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. + */ + +import { EmbeddableStart } from '@kbn/embeddable-plugin/public'; + +export interface ControlsEmbeddableService { + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; +} diff --git a/src/plugins/controls/public/services/plugin_services.story.ts b/src/plugins/controls/public/services/plugin_services.story.ts index b464286c7ca3a..64affcbd9903b 100644 --- a/src/plugins/controls/public/services/plugin_services.story.ts +++ b/src/plugins/controls/public/services/plugin_services.story.ts @@ -23,6 +23,7 @@ import { themeServiceFactory } from './theme/theme.story'; import { optionsListServiceFactory } from './options_list/options_list.story'; import { controlsServiceFactory } from './controls/controls.story'; +import { embeddableServiceFactory } from './embeddable/embeddable.story'; export const providers: PluginServiceProviders = { dataViews: new PluginServiceProvider(dataViewsServiceFactory), @@ -32,6 +33,7 @@ export const providers: PluginServiceProviders = { overlays: new PluginServiceProvider(overlaysServiceFactory), settings: new PluginServiceProvider(settingsServiceFactory), theme: new PluginServiceProvider(themeServiceFactory), + embeddable: new PluginServiceProvider(embeddableServiceFactory), controls: new PluginServiceProvider(controlsServiceFactory), optionsList: new PluginServiceProvider(optionsListServiceFactory), diff --git a/src/plugins/controls/public/services/plugin_services.stub.ts b/src/plugins/controls/public/services/plugin_services.stub.ts index 08be260ce052c..a55d68fa4550f 100644 --- a/src/plugins/controls/public/services/plugin_services.stub.ts +++ b/src/plugins/controls/public/services/plugin_services.stub.ts @@ -25,8 +25,10 @@ import { settingsServiceFactory } from './settings/settings.story'; import { unifiedSearchServiceFactory } from './unified_search/unified_search.story'; import { themeServiceFactory } from './theme/theme.story'; import { registry as stubRegistry } from './plugin_services.story'; +import { embeddableServiceFactory } from './embeddable/embeddable.story'; export const providers: PluginServiceProviders = { + embeddable: new PluginServiceProvider(embeddableServiceFactory), controls: new PluginServiceProvider(controlsServiceFactory), data: new PluginServiceProvider(dataServiceFactory), dataViews: new PluginServiceProvider(dataViewsServiceFactory), diff --git a/src/plugins/controls/public/services/plugin_services.ts b/src/plugins/controls/public/services/plugin_services.ts index f1811063e39a5..20950d42df516 100644 --- a/src/plugins/controls/public/services/plugin_services.ts +++ b/src/plugins/controls/public/services/plugin_services.ts @@ -25,6 +25,7 @@ import { optionsListServiceFactory } from './options_list/options_list_service'; import { settingsServiceFactory } from './settings/settings_service'; import { unifiedSearchServiceFactory } from './unified_search/unified_search_service'; import { themeServiceFactory } from './theme/theme_service'; +import { embeddableServiceFactory } from './embeddable/embeddable_service'; export const providers: PluginServiceProviders< ControlsServices, @@ -38,6 +39,7 @@ export const providers: PluginServiceProviders< overlays: new PluginServiceProvider(overlaysServiceFactory), settings: new PluginServiceProvider(settingsServiceFactory), theme: new PluginServiceProvider(themeServiceFactory), + embeddable: new PluginServiceProvider(embeddableServiceFactory), unifiedSearch: new PluginServiceProvider(unifiedSearchServiceFactory), }; diff --git a/src/plugins/controls/public/services/types.ts b/src/plugins/controls/public/services/types.ts index 48b5aef7e29ba..f0785f9991bed 100644 --- a/src/plugins/controls/public/services/types.ts +++ b/src/plugins/controls/public/services/types.ts @@ -15,11 +15,13 @@ import { ControlsHTTPService } from './http/types'; import { ControlsOptionsListService } from './options_list/types'; import { ControlsSettingsService } from './settings/types'; import { ControlsThemeService } from './theme/types'; +import { ControlsEmbeddableService } from './embeddable/types'; export interface ControlsServices { // dependency services dataViews: ControlsDataViewsService; overlays: ControlsOverlaysService; + embeddable: ControlsEmbeddableService; data: ControlsDataService; unifiedSearch: ControlsUnifiedSearchService; http: ControlsHTTPService; diff --git a/src/plugins/data/common/search/session/types.ts b/src/plugins/data/common/search/session/types.ts index 7824a1db6362e..0f2e14be19572 100644 --- a/src/plugins/data/common/search/session/types.ts +++ b/src/plugins/data/common/search/session/types.ts @@ -91,6 +91,8 @@ export interface SearchSessionRequestStatus { */ export interface SearchSessionStatusResponse { status: SearchSessionStatus; + + errors?: string[]; } /** diff --git a/src/plugins/data/config.ts b/src/plugins/data/config.ts index 05d52b4e127b3..688f65038aa11 100644 --- a/src/plugins/data/config.ts +++ b/src/plugins/data/config.ts @@ -47,10 +47,31 @@ export const searchSessionsConfigSchema = schema.object({ }); export const searchConfigSchema = schema.object({ + /** + * Config for search strategies that use async search based API underneath + */ asyncSearch: schema.object({ + /** + * Block and wait until the search is completed up to the timeout (see es async_search's `wait_for_completion_timeout`) + * TODO: we should optimize this as 100ms is likely not optimal (https://github.com/elastic/kibana/issues/143277) + */ waitForCompletion: schema.duration({ defaultValue: '100ms' }), + /** + * How long the async search needs to be available after each search poll. Ongoing async searches and any saved search results are deleted after this period. + * (see es async_search's `keep_alive`) + * Note: This is applicable to the searches before the search session is saved. + * After search session is saved `keep_alive` is extended using `data.search.sessions.defaultExpiration` config + */ keepAlive: schema.duration({ defaultValue: '1m' }), + /** + * Affects how often partial results become available, which happens whenever shard results are reduced (see es async_search's `batched_reduce_size`) + */ batchedReduceSize: schema.number({ defaultValue: 64 }), + /** + * How long to wait before polling the async_search after the previous poll response. + * If not provided, then default dynamic interval with backoff is used. + */ + pollInterval: schema.maybe(schema.number({ min: 1000 })), }), aggs: schema.object({ shardDelay: schema.object({ diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts index 73c86d8845a18..35bbecfdb5c4d 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts @@ -34,6 +34,7 @@ jest.mock('../errors/search_session_incomplete_warning', () => ({ })); import { SearchSessionIncompleteWarning } from '../errors/search_session_incomplete_warning'; +import { getMockSearchConfig } from '../../../config.mock'; let searchInterceptor: SearchInterceptor; let mockCoreSetup: MockedKeys; @@ -122,6 +123,7 @@ describe('SearchInterceptor', () => { executionContext: mockCoreSetup.executionContext, session: sessionService, theme: themeServiceMock.createSetupContract(), + searchConfig: getMockSearchConfig({}), }); }); diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts index baa5eb30bca4c..f88387e4e44e9 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts @@ -72,6 +72,7 @@ import { ISessionService, SearchSessionState } from '../session'; import { SearchResponseCache } from './search_response_cache'; import { createRequestHash } from './utils'; import { SearchAbortController } from './search_abort_controller'; +import { SearchConfigSchema } from '../../../config'; export interface SearchInterceptorDeps { bfetch: BfetchPublicSetup; @@ -83,6 +84,7 @@ export interface SearchInterceptorDeps { usageCollector?: SearchUsageCollector; session: ISessionService; theme: ThemeServiceSetup; + searchConfig: SearchConfigSchema; } const MAX_CACHE_ITEMS = 50; @@ -302,6 +304,7 @@ export class SearchInterceptor { }); return pollSearch(search, cancel, { + pollInterval: this.deps.searchConfig.asyncSearch.pollInterval, ...options, abortSignal: searchAbortController.getSignal(), }).pipe( diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index e7b753838edff..dbba423c8ea88 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -134,6 +134,7 @@ export class SearchService implements Plugin { usageCollector: this.usageCollector!, session: this.sessionService, theme, + searchConfig: this.initializerContext.config.get().search, }); expressions.registerFunction( diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx index 0581af4a872ff..39c8b8d0fc38c 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx @@ -49,7 +49,7 @@ const DeleteConfirm = (props: DeleteButtonProps & { onActionDismiss: OnActionDis onCancel={onActionDismiss} onConfirm={async () => { setIsLoading(true); - await api.sendCancel(id); + await api.sendDelete(id); onActionDismiss(); }} confirmButtonText={confirm} diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/actions/inspect_button.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/actions/inspect_button.tsx index 4ba404e708662..6776acff20151 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/actions/inspect_button.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/actions/inspect_button.tsx @@ -35,7 +35,7 @@ const InspectFlyout = ({ uiSettings, searchSession }: InspectFlyoutProps) => { { initialState: {}, restoreState: {}, version: '8.0.0', + idMapping: {}, }; }); @@ -119,6 +120,30 @@ describe('Background Search Session management status labels', () => { expect(label.text()).toBe('Expired'); }); + test('error', () => { + session.status = SearchSessionStatus.ERROR; + + const statusIndicator = mount( + + + + ); + + const label = statusIndicator + .find(`[data-test-subj="sessionManagementStatusLabel"][data-test-status="error"]`) + .first(); + expect(label.text()).toBe('Error'); + + const tooltip = statusIndicator.find('EuiToolTip'); + expect((tooltip.first().props() as EuiToolTipProps).content).toMatchInlineSnapshot( + `"One or more searches failed to complete. Use the \\"Inspect\\" action to see the underlying errors."` + ); + }); + test('error handling', () => { session.status = SearchSessionStatus.COMPLETE; (session as any).created = null; diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/status.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/status.tsx index bb41ff05c1099..68dec9750cf2e 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/status.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/status.tsx @@ -116,10 +116,15 @@ const getStatusAttributes = ({ textColor: 'danger', icon: , label: {getStatusText(session.status)}, - toolTipContent: i18n.translate('data.mgmt.searchSessions.status.message.error', { - defaultMessage: 'Error: {error}', - values: { error: (session as any).error || 'unknown' }, - }), + toolTipContent: + session.errors && session.errors.length > 0 + ? i18n.translate('data.mgmt.searchSessions.status.message.error', { + defaultMessage: + 'One or more searches failed to complete. Use the "Inspect" action to see the underlying errors.', + }) + : i18n.translate('data.mgmt.searchSessions.status.message.unknownError', { + defaultMessage: 'Unknown error', + }), }; case SearchSessionStatus.COMPLETE: diff --git a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts index 73e1e8dc08668..52b72afd30ab3 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts +++ b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts @@ -80,8 +80,10 @@ describe('Search Sessions Management API', () => { ], "appId": "pizza", "created": undefined, + "errors": undefined, "expires": undefined, "id": "hello-pizza-123", + "idMapping": Array [], "initialState": Object {}, "name": "Veggie", "numSearches": 0, @@ -192,7 +194,7 @@ describe('Search Sessions Management API', () => { notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); - await api.sendCancel('abc-123-cool-session-ID'); + await api.sendDelete('abc-123-cool-session-ID'); expect(mockCoreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith({ title: 'The search session was deleted.', @@ -207,7 +209,7 @@ describe('Search Sessions Management API', () => { notifications: mockCoreStart.notifications, application: mockCoreStart.application, }); - await api.sendCancel('abc-123-cool-session-ID'); + await api.sendDelete('abc-123-cool-session-ID'); expect(mockCoreStart.notifications.toasts.addError).toHaveBeenCalledWith( new Error('implementation is so bad'), diff --git a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts index 4fac2d36203c4..ee5b4d504e294 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts +++ b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts @@ -35,7 +35,11 @@ function getActions(status: UISearchSessionState) { actions.push(ACTION.DELETE); } - if (status === SearchSessionStatus.EXPIRED) { + if ( + status === SearchSessionStatus.EXPIRED || + status === SearchSessionStatus.ERROR || + status === SearchSessionStatus.CANCELLED + ) { actions.push(ACTION.DELETE); } @@ -77,6 +81,7 @@ const mapToUISession = } = savedObject.attributes; const status = sessionStatuses[savedObject.id]?.status; + const errors = sessionStatuses[savedObject.id]?.errors; const actions = getActions(status); // TODO: initialState should be saved without the searchSessionID @@ -97,8 +102,10 @@ const mapToUISession = reloadUrl: reloadUrl!, initialState, restoreState, + idMapping, numSearches: Object.keys(idMapping).length, version, + errors, }; }; @@ -165,17 +172,12 @@ export class SearchSessionsMgmtAPI { return []; } - public reloadSearchSession(reloadUrl: string) { - this.deps.usageCollector?.trackSessionReloaded(); - this.deps.application.navigateToUrl(reloadUrl); - } - public getExtendByDuration() { return this.config.defaultExpiration; } - // Cancel and expire - public async sendCancel(id: string): Promise { + // Delete and expire + public async sendDelete(id: string): Promise { this.deps.usageCollector?.trackSessionDeleted(); try { await this.sessionsClient.delete(id); diff --git a/src/plugins/data/public/search/session/sessions_mgmt/lib/get_columns.test.tsx b/src/plugins/data/public/search/session/sessions_mgmt/lib/get_columns.test.tsx index 690713ac9232f..3fd53ccfddec2 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/lib/get_columns.test.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/lib/get_columns.test.tsx @@ -77,6 +77,7 @@ describe('Search Sessions Management table column factory', () => { initialState: {}, restoreState: {}, version: '7.14.0', + idMapping: {}, }; }); diff --git a/src/plugins/data/public/search/session/sessions_mgmt/types.ts b/src/plugins/data/public/search/session/sessions_mgmt/types.ts index d21b4371099c7..9ec4a2e013fad 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/types.ts +++ b/src/plugins/data/public/search/session/sessions_mgmt/types.ts @@ -32,6 +32,7 @@ export interface UISession { created: string; expires: string | null; status: UISearchSessionState; + idMapping: SearchSessionSavedObjectAttributes['idMapping']; numSearches: number; actions?: ACTION[]; reloadUrl: string; @@ -39,4 +40,5 @@ export interface UISession { initialState: Record; restoreState: Record; version: string; + errors?: string[]; } diff --git a/src/plugins/data/server/search/session/get_search_status.ts b/src/plugins/data/server/search/session/get_search_status.ts index fb34fff1c1d43..f9b14fefdf397 100644 --- a/src/plugins/data/server/search/session/get_search_status.ts +++ b/src/plugins/data/server/search/session/get_search_status.ts @@ -33,8 +33,8 @@ export async function getSearchStatus( return { status: SearchStatus.ERROR, error: i18n.translate('data.search.statusError', { - defaultMessage: `Search completed with a {errorCode} status`, - values: { errorCode: response.completion_status }, + defaultMessage: `Search {searchId} completed with a {errorCode} status`, + values: { searchId: asyncId, errorCode: response.completion_status }, }), }; } else if (!response.is_partial && !response.is_running) { @@ -52,10 +52,11 @@ export async function getSearchStatus( return { status: SearchStatus.ERROR, error: i18n.translate('data.search.statusThrow', { - defaultMessage: `Search status threw an error {message} ({errorCode}) status`, + defaultMessage: `Search status for search with id {searchId} threw an error {message} (statusCode: {errorCode})`, values: { message: e.message, errorCode: e.statusCode || 500, + searchId: asyncId, }, }), }; diff --git a/src/plugins/data/server/search/session/get_session_status.test.ts b/src/plugins/data/server/search/session/get_session_status.test.ts index b7e323a15f065..1d59fd11c471e 100644 --- a/src/plugins/data/server/search/session/get_session_status.test.ts +++ b/src/plugins/data/server/search/session/get_session_status.test.ts @@ -47,7 +47,9 @@ describe('getSessionStatus', () => { idMapping: {}, touched: moment(), }; - expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); + expect(await getSessionStatus(deps, session, mockConfig)).toEqual({ + status: SearchSessionStatus.IN_PROGRESS, + }); }); test("returns an error status if there's at least one error", async () => { @@ -74,7 +76,10 @@ describe('getSessionStatus', () => { c: { id: 'c' }, }, }; - expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.ERROR); + expect(await getSessionStatus(deps, session, mockConfig)).toEqual({ + status: SearchSessionStatus.ERROR, + errors: ['Search b completed with a 500 status'], + }); }); test('expires a session if expired < now', async () => { @@ -83,7 +88,9 @@ describe('getSessionStatus', () => { expires: moment().subtract(2, 'm'), }; - expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.EXPIRED); + expect(await getSessionStatus(deps, session, mockConfig)).toEqual({ + status: SearchSessionStatus.EXPIRED, + }); }); test('doesnt expire if expire > now', async () => { @@ -95,7 +102,9 @@ describe('getSessionStatus', () => { }, expires: moment().add(2, 'm'), }; - expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); + expect(await getSessionStatus(deps, session, mockConfig)).toEqual({ + status: SearchSessionStatus.IN_PROGRESS, + }); }); test('returns cancelled status if session was cancelled', async () => { @@ -108,7 +117,7 @@ describe('getSessionStatus', () => { }; expect( await getSessionStatus(deps, session as SearchSessionSavedObjectAttributes, mockConfig) - ).toBe(SearchSessionStatus.CANCELLED); + ).toEqual({ status: SearchSessionStatus.CANCELLED }); }); test('returns a complete status if all are complete', async () => { @@ -121,7 +130,9 @@ describe('getSessionStatus', () => { c: { id: 'c' }, }, }; - expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.COMPLETE); + expect(await getSessionStatus(deps, session, mockConfig)).toEqual({ + status: SearchSessionStatus.COMPLETE, + }); }); test('returns a running status if some are still running', async () => { @@ -141,6 +152,8 @@ describe('getSessionStatus', () => { c: { id: 'c' }, }, }; - expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); + expect(await getSessionStatus(deps, session, mockConfig)).toEqual({ + status: SearchSessionStatus.IN_PROGRESS, + }); }); }); diff --git a/src/plugins/data/server/search/session/get_session_status.ts b/src/plugins/data/server/search/session/get_session_status.ts index b89b4c487c32c..e1cb50a6c4cd4 100644 --- a/src/plugins/data/server/search/session/get_session_status.ts +++ b/src/plugins/data/server/search/session/get_session_status.ts @@ -17,15 +17,15 @@ export async function getSessionStatus( deps: { internalClient: ElasticsearchClient }, session: SearchSessionSavedObjectAttributes, config: SearchSessionsConfigSchema -): Promise { +): Promise<{ status: SearchSessionStatus; errors?: string[] }> { if (session.isCanceled === true) { - return SearchSessionStatus.CANCELLED; + return { status: SearchSessionStatus.CANCELLED }; } const now = moment(); if (moment(session.expires).isBefore(now)) { - return SearchSessionStatus.EXPIRED; + return { status: SearchSessionStatus.EXPIRED }; } const searches = Object.values(session.idMapping); @@ -40,13 +40,15 @@ export async function getSessionStatus( ); if (searchStatuses.some((item) => item.status === SearchStatus.ERROR)) { - return SearchSessionStatus.ERROR; + const erroredSearches = searchStatuses.filter((s) => s.status === SearchStatus.ERROR); + const errors = erroredSearches.map((s) => s.error).filter((error) => !!error) as string[]; + return { status: SearchSessionStatus.ERROR, errors }; } else if ( searchStatuses.length > 0 && searchStatuses.every((item) => item.status === SearchStatus.COMPLETE) ) { - return SearchSessionStatus.COMPLETE; + return { status: SearchSessionStatus.COMPLETE }; } else { - return SearchSessionStatus.IN_PROGRESS; + return { status: SearchSessionStatus.IN_PROGRESS }; } } diff --git a/src/plugins/data/server/search/session/session_service.ts b/src/plugins/data/server/search/session/session_service.ts index d8426c03e91ed..45b0a31678402 100644 --- a/src/plugins/data/server/search/session/session_service.ts +++ b/src/plugins/data/server/search/session/session_service.ts @@ -208,8 +208,8 @@ export class SearchSessionService implements ISearchSessionService { return { ...findResponse, statuses: sessionStatuses.reduce>( - (res, status, index) => { - res[findResponse.saved_objects[index].id] = { status }; + (res, { status, errors }, index) => { + res[findResponse.saved_objects[index].id] = { status, errors }; return res; }, {} @@ -380,7 +380,7 @@ export class SearchSessionService implements ISearchSessionService { this.sessionConfig ); - return { status: sessionStatus }; + return { status: sessionStatus.status, errors: sessionStatus.errors }; } /** diff --git a/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts b/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts index 14b5c76c67f46..d6f5d948c784a 100644 --- a/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.ts @@ -86,7 +86,10 @@ export const eqlSearchStrategyProvider = ( } }; - return pollSearch(search, cancel, options).pipe(tap((response) => (id = response.id))); + return pollSearch(search, cancel, { + pollInterval: searchConfig.asyncSearch.pollInterval, + ...options, + }).pipe(tap((response) => (id = response.id))); }, extend: async (id, keepAlive, options, { esClient }) => { diff --git a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts index fb463bbcabad5..e5567b45f1e06 100644 --- a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts @@ -87,7 +87,10 @@ export const enhancedEsSearchStrategyProvider = ( } }; - return pollSearch(search, cancel, options).pipe( + return pollSearch(search, cancel, { + pollInterval: searchConfig.asyncSearch.pollInterval, + ...options, + }).pipe( tap((response) => (id = response.id)), tap(searchUsageObserver(logger, usage)), catchError((e) => { diff --git a/src/plugins/data/server/search/strategies/sql_search/sql_search_strategy.ts b/src/plugins/data/server/search/strategies/sql_search/sql_search_strategy.ts index 64c4d6fd5ee0f..c8928a343eec5 100644 --- a/src/plugins/data/server/search/strategies/sql_search/sql_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/sql_search/sql_search_strategy.ts @@ -88,7 +88,10 @@ export const sqlSearchStrategyProvider = ( } }; - return pollSearch(search, cancel, options).pipe( + return pollSearch(search, cancel, { + pollInterval: searchConfig.asyncSearch.pollInterval, + ...options, + }).pipe( tap((response) => (id = response.id)), catchError((e) => { throw getKbnServerError(e); diff --git a/src/plugins/guided_onboarding/README.md b/src/plugins/guided_onboarding/README.md index 1daa04d223e2b..d54926da3c971 100755 --- a/src/plugins/guided_onboarding/README.md +++ b/src/plugins/guided_onboarding/README.md @@ -10,11 +10,9 @@ The client-side code registers a button in the Kibana header that controls the g ## Development -1. To enable the UI, add `guidedOnboarding.ui: true` to the file `KIBANA_FOLDER/config/kibana.dev.yml`. +1. Start Kibana with examples `yarn start --run-examples` to be able to see the guidedOnboardingExample plugin. -2. Start Kibana with examples `yarn start --run-examples` to be able to see the guidedOnboardingExample plugin. - -3. Navigate to `/app/guidedOnboardingExample` to start a guide and check the button in the header. +2. Navigate to `/app/guidedOnboardingExample` to start a guide and check the button in the header. ## API service *Also see `KIBANA_FOLDER/examples/guided_onboarding_example` for code examples.* diff --git a/src/plugins/guided_onboarding/kibana.json b/src/plugins/guided_onboarding/kibana.json index 42f893adfd63d..22a54e8dd3278 100755 --- a/src/plugins/guided_onboarding/kibana.json +++ b/src/plugins/guided_onboarding/kibana.json @@ -10,6 +10,5 @@ "server": true, "ui": true, "requiredBundles": ["kibanaReact"], - "optionalPlugins": [], - "configPath": ["guidedOnboarding"] + "optionalPlugins": [] } diff --git a/src/plugins/guided_onboarding/public/components/guide_button.tsx b/src/plugins/guided_onboarding/public/components/guide_button.tsx index b4b50d78942ea..317f760f3a1e9 100644 --- a/src/plugins/guided_onboarding/public/components/guide_button.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_button.tsx @@ -9,7 +9,8 @@ import React from 'react'; import { EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { GuideState } from '../../common/types'; +import type { GuideState } from '@kbn/guided-onboarding'; + import { getStepConfig } from '../services/helpers'; import { GuideButtonPopover } from './guide_button_popover'; diff --git a/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx b/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx index 4761446f7969c..c2e1ccdc4e2f2 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx @@ -12,9 +12,9 @@ import React from 'react'; import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; import { httpServiceMock } from '@kbn/core/public/mocks'; import { HttpSetup } from '@kbn/core/public'; +import type { GuideState } from '@kbn/guided-onboarding'; import { guidesConfig } from '../constants/guides_config'; -import type { GuideState } from '../../common/types'; import { apiService } from '../services/api'; import { GuidePanel } from './guide_panel'; import { registerTestBed, TestBed } from '@kbn/test-jest-helpers'; @@ -109,7 +109,8 @@ describe('Guided setup', () => { }); describe('Button component', () => { - test('should be disabled in there is no active guide', async () => { + // TODO check for the correct button behavior once https://github.com/elastic/kibana/issues/141129 is implemented + test.skip('should be disabled in there is no active guide', async () => { const { exists } = testBed; expect(exists('disabledGuideButton')).toBe(true); expect(exists('guideButton')).toBe(false); @@ -280,9 +281,8 @@ describe('Guided setup', () => { component.update(); expect(exists('quitGuideModal')).toBe(false); - // For now, the guide button is disabled once a user quits a guide - // This behavior will change once https://github.com/elastic/kibana/issues/141129 is implemented - expect(exists('disabledGuideButton')).toBe(true); + + // TODO check for the correct button behavior once https://github.com/elastic/kibana/issues/141129 is implemented }); test('cancels out of the quit guide confirmation modal', async () => { diff --git a/src/plugins/guided_onboarding/public/components/guide_panel.tsx b/src/plugins/guided_onboarding/public/components/guide_panel.tsx index 75f1f07cad5bc..48fe3c5c663bc 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel.tsx @@ -30,8 +30,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { ApplicationStart } from '@kbn/core/public'; +import type { GuideState, GuideStep as GuideStepStatus } from '@kbn/guided-onboarding'; -import type { GuideState, GuideStep as GuideStepStatus } from '../../common/types'; import type { GuideConfig, StepConfig } from '../types'; import type { ApiService } from '../services/api'; @@ -140,20 +140,8 @@ export const GuidePanel = ({ api, application }: GuidePanelProps) => { // TODO handle loading, error state // https://github.com/elastic/kibana/issues/139799, https://github.com/elastic/kibana/issues/139798 if (!guideConfig) { - return ( - - {i18n.translate('guidedOnboarding.disabledGuidedSetupButtonLabel', { - defaultMessage: 'Setup guide', - })} - - ); + // TODO button show/hide logic https://github.com/elastic/kibana/issues/141129 + return null; } const stepsCompleted = getProgress(guideState); diff --git a/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts b/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts index 8d34d45b7a53c..14b8f7826bb1b 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts +++ b/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts @@ -8,7 +8,7 @@ import { EuiThemeComputed } from '@elastic/eui'; import { css } from '@emotion/react'; -import { StepStatus } from '../../common/types'; +import type { StepStatus } from '@kbn/guided-onboarding'; export const getGuidePanelStepStyles = (euiTheme: EuiThemeComputed, stepStatus: StepStatus) => ({ stepNumber: css` diff --git a/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx b/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx index 107babb6ac0d8..f79a26778c1a3 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx @@ -21,7 +21,7 @@ import { import { i18n } from '@kbn/i18n'; -import type { StepStatus } from '../../common/types'; +import type { StepStatus } from '@kbn/guided-onboarding'; import type { StepConfig } from '../types'; import { getGuidePanelStepStyles } from './guide_panel_step.styles'; diff --git a/src/plugins/guided_onboarding/public/components/quit_guide_modal.tsx b/src/plugins/guided_onboarding/public/components/quit_guide_modal.tsx index a7a7e34c311b4..171750cd83db5 100644 --- a/src/plugins/guided_onboarding/public/components/quit_guide_modal.tsx +++ b/src/plugins/guided_onboarding/public/components/quit_guide_modal.tsx @@ -9,7 +9,7 @@ import React, { useState } from 'react'; import { EuiText, EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { GuideState } from '../../common/types'; +import type { GuideState } from '@kbn/guided-onboarding'; import { apiService } from '../services/api'; interface QuitGuideModalProps { diff --git a/src/plugins/guided_onboarding/public/constants/guides_config/security.ts b/src/plugins/guided_onboarding/public/constants/guides_config/security.ts index 68ebc849f94c0..d2f9b352b9d81 100644 --- a/src/plugins/guided_onboarding/public/constants/guides_config/security.ts +++ b/src/plugins/guided_onboarding/public/constants/guides_config/security.ts @@ -45,6 +45,10 @@ export const securityConfig: GuideConfig = { description: 'Mark the step complete by opening the panel and clicking the button "Mark done"', }, + location: { + appID: 'securitySolutionUI', + path: '/rules', + }, }, { id: 'alertsCases', @@ -54,6 +58,10 @@ export const securityConfig: GuideConfig = { 'Nullam ligula enim, malesuada a finibus vel, cursus sed risus.', 'Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.', ], + location: { + appID: 'securitySolutionUI', + path: '/alerts', + }, }, ], }; diff --git a/src/plugins/guided_onboarding/public/index.ts b/src/plugins/guided_onboarding/public/index.ts index 08ae777bb360f..c9ea467231981 100755 --- a/src/plugins/guided_onboarding/public/index.ts +++ b/src/plugins/guided_onboarding/public/index.ts @@ -6,14 +6,15 @@ * Side Public License, v 1. */ -import { PluginInitializerContext } from '@kbn/core/public'; import { GuidedOnboardingPlugin } from './plugin'; -export function plugin(ctx: PluginInitializerContext) { - return new GuidedOnboardingPlugin(ctx); +export function plugin() { + return new GuidedOnboardingPlugin(); } -export type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types'; - -export type { GuideId, GuideStepIds, GuideState, GuideStep } from '../common/types'; +export type { + GuidedOnboardingPluginSetup, + GuidedOnboardingPluginStart, + GuidedOnboardingApi, +} from './types'; export { guidesConfig } from './constants/guides_config'; diff --git a/src/plugins/guided_onboarding/public/plugin.tsx b/src/plugins/guided_onboarding/public/plugin.tsx index f74e19a03300f..5d18eab0ad223 100755 --- a/src/plugins/guided_onboarding/public/plugin.tsx +++ b/src/plugins/guided_onboarding/public/plugin.tsx @@ -10,38 +10,22 @@ import ReactDOM from 'react-dom'; import React from 'react'; import * as Rx from 'rxjs'; import { I18nProvider } from '@kbn/i18n-react'; -import { - CoreSetup, - CoreStart, - Plugin, - CoreTheme, - ApplicationStart, - PluginInitializerContext, -} from '@kbn/core/public'; +import { CoreSetup, CoreStart, Plugin, CoreTheme, ApplicationStart } from '@kbn/core/public'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; -import type { - ClientConfigType, - GuidedOnboardingPluginSetup, - GuidedOnboardingPluginStart, -} from './types'; +import type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types'; import { GuidePanel } from './components'; import { ApiService, apiService } from './services/api'; export class GuidedOnboardingPlugin implements Plugin { - constructor(private ctx: PluginInitializerContext) {} + constructor() {} public setup(core: CoreSetup): GuidedOnboardingPluginSetup { return {}; } public start(core: CoreStart): GuidedOnboardingPluginStart { - const { ui: isGuidedOnboardingUiEnabled } = this.ctx.config.get(); - if (!isGuidedOnboardingUiEnabled) { - return {}; - } - const { chrome, http, theme, application } = core; // Initialize services diff --git a/src/plugins/guided_onboarding/public/services/api.mocks.ts b/src/plugins/guided_onboarding/public/services/api.mocks.ts index ed2985a1dd74a..21bb257cad68f 100644 --- a/src/plugins/guided_onboarding/public/services/api.mocks.ts +++ b/src/plugins/guided_onboarding/public/services/api.mocks.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { GuideState } from '../../common/types'; +import type { GuideState } from '@kbn/guided-onboarding'; export const searchAddDataActiveState: GuideState = { guideId: 'search', diff --git a/src/plugins/guided_onboarding/public/services/api.test.ts b/src/plugins/guided_onboarding/public/services/api.test.ts index 8765af0fb07f6..3503b68e5466c 100644 --- a/src/plugins/guided_onboarding/public/services/api.test.ts +++ b/src/plugins/guided_onboarding/public/services/api.test.ts @@ -8,11 +8,11 @@ import { HttpSetup } from '@kbn/core/public'; import { httpServiceMock } from '@kbn/core/public/mocks'; +import type { GuideState } from '@kbn/guided-onboarding'; import { firstValueFrom, Subscription } from 'rxjs'; import { API_BASE_PATH } from '../../common/constants'; import { guidesConfig } from '../constants/guides_config'; -import type { GuideState } from '../../common/types'; import { ApiService } from './api'; import { noGuideActiveState, @@ -57,7 +57,7 @@ describe('GuidedOnboarding ApiService', () => { }); it('broadcasts the updated state', async () => { - await apiService.activateGuide(searchGuide); + await apiService.activateGuide(searchGuide, searchAddDataActiveState); const state = await firstValueFrom(apiService.fetchActiveGuideState$()); expect(state).toEqual(searchAddDataActiveState); @@ -151,7 +151,7 @@ describe('GuidedOnboarding ApiService', () => { expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { body: JSON.stringify({ isActive: true, - status: 'in_progress', + status: 'not_started', steps: [ { id: 'add_data', diff --git a/src/plugins/guided_onboarding/public/services/api.ts b/src/plugins/guided_onboarding/public/services/api.ts index 63fe8c3b7cb04..688e72fa83243 100644 --- a/src/plugins/guided_onboarding/public/services/api.ts +++ b/src/plugins/guided_onboarding/public/services/api.ts @@ -8,6 +8,7 @@ import { HttpSetup } from '@kbn/core/public'; import { BehaviorSubject, map, from, concatMap, of, Observable, firstValueFrom } from 'rxjs'; +import type { GuideState, GuideId, GuideStep, GuideStepIds } from '@kbn/guided-onboarding'; import { GuidedOnboardingApi } from '../types'; import { @@ -21,7 +22,6 @@ import { isStepReadyToComplete, } from './helpers'; import { API_BASE_PATH } from '../../common/constants'; -import type { GuideState, GuideId, GuideStep, GuideStepIds } from '../../common/types'; export class ApiService implements GuidedOnboardingApi { private client: HttpSetup | undefined; @@ -148,7 +148,7 @@ export class ApiService implements GuidedOnboardingApi { const updatedGuide: GuideState = { isActive: true, - status: 'in_progress', + status: 'not_started', steps: updatedSteps, guideId, }; diff --git a/src/plugins/guided_onboarding/public/services/helpers.ts b/src/plugins/guided_onboarding/public/services/helpers.ts index 30fbd5051215b..c9bfc7dfb0404 100644 --- a/src/plugins/guided_onboarding/public/services/helpers.ts +++ b/src/plugins/guided_onboarding/public/services/helpers.ts @@ -6,10 +6,9 @@ * Side Public License, v 1. */ -import type { GuideId, GuideState, GuideStepIds } from '../../common/types'; +import type { GuideId, GuideStepIds, GuideState, GuideStep } from '@kbn/guided-onboarding'; import { guidesConfig } from '../constants/guides_config'; import { GuideConfig, StepConfig } from '../types'; -import { GuideStep } from '../../common/types'; export const getGuideConfig = (guideId?: GuideId): GuideConfig | undefined => { if (guideId && Object.keys(guidesConfig).includes(guideId)) { diff --git a/src/plugins/guided_onboarding/public/types.ts b/src/plugins/guided_onboarding/public/types.ts index 7ca5d59ce5d73..a6536e3caf114 100755 --- a/src/plugins/guided_onboarding/public/types.ts +++ b/src/plugins/guided_onboarding/public/types.ts @@ -7,9 +7,8 @@ */ import { Observable } from 'rxjs'; -import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; import { HttpSetup } from '@kbn/core/public'; -import { GuideId, GuideState, GuideStepIds, StepStatus } from '../common/types'; +import type { GuideState, GuideId, GuideStepIds, StepStatus } from '@kbn/guided-onboarding'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface GuidedOnboardingPluginSetup {} @@ -18,14 +17,6 @@ export interface GuidedOnboardingPluginStart { guidedOnboardingApi?: GuidedOnboardingApi; } -export interface AppPluginStartDependencies { - navigation: NavigationPublicPluginStart; -} - -export interface ClientConfigType { - ui: boolean; -} - export interface GuidedOnboardingApi { setup: (httpClient: HttpSetup) => void; fetchActiveGuideState$: () => Observable; diff --git a/src/plugins/guided_onboarding/server/config.ts b/src/plugins/guided_onboarding/server/config.ts deleted file mode 100644 index 61f45be14f4e9..0000000000000 --- a/src/plugins/guided_onboarding/server/config.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 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 { PluginConfigDescriptor } from '@kbn/core/server'; -import { schema, TypeOf } from '@kbn/config-schema'; - -// By default, hide any guided onboarding UI. Change it with guidedOnboarding.ui:true in kibana.dev.yml -const configSchema = schema.object({ - ui: schema.boolean({ defaultValue: false }), -}); - -export type GuidedOnboardingConfig = TypeOf; - -export const config: PluginConfigDescriptor = { - // define which config properties should be available in the client side plugin - exposeToBrowser: { - ui: true, - }, - schema: configSchema, -}; diff --git a/src/plugins/guided_onboarding/server/index.ts b/src/plugins/guided_onboarding/server/index.ts index c7a7fff53656d..12eb46043cf23 100755 --- a/src/plugins/guided_onboarding/server/index.ts +++ b/src/plugins/guided_onboarding/server/index.ts @@ -9,8 +9,6 @@ import { PluginInitializerContext } from '@kbn/core/server'; import { GuidedOnboardingPlugin } from './plugin'; -export { config } from './config'; - export function plugin(initializerContext: PluginInitializerContext) { return new GuidedOnboardingPlugin(initializerContext); } diff --git a/src/plugins/guided_onboarding/server/routes/index.ts b/src/plugins/guided_onboarding/server/routes/index.ts index adc65d0bf6866..1145715389488 100755 --- a/src/plugins/guided_onboarding/server/routes/index.ts +++ b/src/plugins/guided_onboarding/server/routes/index.ts @@ -8,8 +8,8 @@ import { schema } from '@kbn/config-schema'; import type { IRouter, SavedObjectsClient } from '@kbn/core/server'; +import type { GuideState } from '@kbn/guided-onboarding'; import { API_BASE_PATH } from '../../common/constants'; -import type { GuideState } from '../../common/types'; import { guidedSetupSavedObjectsType } from '../saved_objects'; const findGuideById = async (savedObjectsClient: SavedObjectsClient, guideId: string) => { diff --git a/src/plugins/guided_onboarding/tsconfig.json b/src/plugins/guided_onboarding/tsconfig.json index 153d0a2b85ee0..4a024443419ad 100644 --- a/src/plugins/guided_onboarding/tsconfig.json +++ b/src/plugins/guided_onboarding/tsconfig.json @@ -12,9 +12,6 @@ { "path": "../../core/tsconfig.json" }, - { - "path": "../navigation/tsconfig.json" - }, { "path": "../kibana_react/tsconfig.json" }, diff --git a/src/plugins/home/kibana.json b/src/plugins/home/kibana.json index 72b4d6cb8fd0b..9a57af5b70518 100644 --- a/src/plugins/home/kibana.json +++ b/src/plugins/home/kibana.json @@ -8,6 +8,6 @@ "server": true, "ui": true, "requiredPlugins": ["dataViews", "share", "urlForwarding"], - "optionalPlugins": ["usageCollection", "customIntegrations", "cloud"], + "optionalPlugins": ["usageCollection", "customIntegrations", "cloud", "guidedOnboarding"], "requiredBundles": ["kibanaReact"] } diff --git a/src/plugins/home/public/application/components/guided_onboarding/__snapshots__/getting_started.test.tsx.snap b/src/plugins/home/public/application/components/guided_onboarding/__snapshots__/getting_started.test.tsx.snap index 89105328eec7d..1cca5beaea251 100644 --- a/src/plugins/home/public/application/components/guided_onboarding/__snapshots__/getting_started.test.tsx.snap +++ b/src/plugins/home/public/application/components/guided_onboarding/__snapshots__/getting_started.test.tsx.snap @@ -35,12 +35,11 @@ exports[`getting started should render getting started component 1`] = ` size="s" />

    - Select a starting point for a quick tour of how Elastic can help you do even more with your data. + Select a guide to help you make the most of your data.

    - - - + + + @@ -79,7 +97,7 @@ exports[`getting started should render getting started component 1`] = ` data-test-subj="onboarding--skipUseCaseTourLink" onClick={[Function]} > - No thanks, I’ll explore on my own. + I’d like to do something else (skip)
    diff --git a/src/plugins/home/public/application/components/guided_onboarding/__snapshots__/use_case_card.test.tsx.snap b/src/plugins/home/public/application/components/guided_onboarding/__snapshots__/use_case_card.test.tsx.snap deleted file mode 100644 index 7ace627183237..0000000000000 --- a/src/plugins/home/public/application/components/guided_onboarding/__snapshots__/use_case_card.test.tsx.snap +++ /dev/null @@ -1,109 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`use case card should render use case card component for observability 1`] = ` - -

    - Get end-to-end observability into your environments by consolidating your logs, metrics, and traces. -

    - - } - display="subdued" - image={ - - } - onClick={[Function]} - textAlign="left" - title={ - -

    - - Monitor my environments - -

    -
    - } -/> -`; - -exports[`use case card should render use case card component for search 1`] = ` - -

    - Create a finely-tuned search experience for your websites, applications, workplace content, and more. -

    - - } - display="subdued" - image={ - - } - onClick={[Function]} - textAlign="left" - title={ - -

    - - Search my data - -

    -
    - } -/> -`; - -exports[`use case card should render use case card component for security 1`] = ` - -

    - Protect your environment against threats by unifying SIEM, endpoint security, and cloud security in one place. -

    - - } - display="subdued" - image={ - - } - onClick={[Function]} - textAlign="left" - title={ - -

    - - Protect my environment - -

    -
    - } -/> -`; diff --git a/src/plugins/home/public/application/components/guided_onboarding/getting_started.test.tsx b/src/plugins/home/public/application/components/guided_onboarding/getting_started.test.tsx index 6e0e01b73a460..8b2ca1de830a0 100644 --- a/src/plugins/home/public/application/components/guided_onboarding/getting_started.test.tsx +++ b/src/plugins/home/public/application/components/guided_onboarding/getting_started.test.tsx @@ -31,6 +31,9 @@ jest.mock('../../kibana_services', () => { prepend: jest.fn(), }, }, + guidedOnboardingService: { + fetchAllGuidesState: jest.fn(), + }, }), }; }); diff --git a/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx b/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx index f3131e63ad393..e63676ca3ca72 100644 --- a/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx +++ b/src/plugins/home/public/application/components/guided_onboarding/getting_started.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useEffect } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { EuiFlexGrid, EuiFlexItem, @@ -24,28 +24,30 @@ import { css } from '@emotion/react'; import { METRIC_TYPE } from '@kbn/analytics'; import { i18n } from '@kbn/i18n'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; +import type { GuideState, GuideId, UseCase } from '@kbn/guided-onboarding'; +import { GuideCard, ObservabilityLinkCard } from '@kbn/guided-onboarding'; import { getServices } from '../../kibana_services'; import { KEY_ENABLE_WELCOME } from '../home'; -import { UseCaseCard } from './use_case_card'; const homeBreadcrumb = i18n.translate('home.breadcrumbs.homeTitle', { defaultMessage: 'Home' }); const gettingStartedBreadcrumb = i18n.translate('home.breadcrumbs.gettingStartedTitle', { - defaultMessage: 'Getting Started', + defaultMessage: 'Guided setup', }); const title = i18n.translate('home.guidedOnboarding.gettingStarted.useCaseSelectionTitle', { defaultMessage: 'What would you like to do first?', }); const subtitle = i18n.translate('home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle', { - defaultMessage: - 'Select a starting point for a quick tour of how Elastic can help you do even more with your data.', + defaultMessage: 'Select a guide to help you make the most of your data.', }); const skipText = i18n.translate('home.guidedOnboarding.gettingStarted.skip.buttonLabel', { - defaultMessage: `No thanks, I’ll explore on my own.`, + defaultMessage: `I’d like to do something else (skip)`, }); export const GettingStarted = () => { - const { application, trackUiMetric, chrome } = getServices(); + const { application, trackUiMetric, chrome, guidedOnboardingService, http, uiSettings } = + getServices(); + const [guidesState, setGuidesState] = useState([]); useEffect(() => { chrome.setBreadcrumbs([ @@ -63,6 +65,17 @@ export const GettingStarted = () => { ]); }, [chrome, trackUiMetric]); + const fetchGuidesState = useCallback(async () => { + const allGuides = await guidedOnboardingService?.fetchAllGuidesState(); + if (allGuides) { + setGuidesState(allGuides.state); + } + }, [guidedOnboardingService]); + + useEffect(() => { + fetchGuidesState(); + }, [fetchGuidesState]); + const onSkip = () => { trackUiMetric(METRIC_TYPE.CLICK, 'guided_onboarding__skipped'); // disable welcome screen on the home page @@ -73,6 +86,12 @@ export const GettingStarted = () => { const paddingCss = css` padding: calc(${euiTheme.size.base}*3) calc(${euiTheme.size.base}*4); `; + + const isDarkTheme = uiSettings.get('theme:darkMode'); + const activateGuide = async (useCase: UseCase, guideState?: GuideState) => { + await guidedOnboardingService?.activateGuide(useCase as GuideId, guideState); + // TODO error handling https://github.com/elastic/kibana/issues/139798 + }; return ( @@ -81,21 +100,36 @@ export const GettingStarted = () => {

    {title}

    - +

    {subtitle}

    - - - - - - - - - - + + {['search', 'observability', 'observabilityLink', 'security'].map((useCase) => { + if (useCase === 'observabilityLink') { + return ( + + + + ); + } + return ( + + + + ); + })} diff --git a/src/plugins/home/public/application/components/guided_onboarding/use_case_card.test.tsx b/src/plugins/home/public/application/components/guided_onboarding/use_case_card.test.tsx deleted file mode 100644 index b899d533572c7..0000000000000 --- a/src/plugins/home/public/application/components/guided_onboarding/use_case_card.test.tsx +++ /dev/null @@ -1,42 +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 { shallow } from 'enzyme'; - -import { UseCaseCard } from './use_case_card'; - -jest.mock('../../kibana_services', () => { - const { applicationServiceMock, uiSettingsServiceMock, httpServiceMock } = - jest.requireActual('@kbn/core/public/mocks'); - return { - getServices: () => ({ - application: applicationServiceMock.createStartContract(), - trackUiMetric: jest.fn(), - uiSettings: uiSettingsServiceMock.createStartContract(), - http: httpServiceMock.createStartContract(), - }), - }; -}); -describe('use case card', () => { - test('should render use case card component for search', async () => { - const component = await shallow(); - - expect(component).toMatchSnapshot(); - }); - test('should render use case card component for observability', async () => { - const component = await shallow(); - - expect(component).toMatchSnapshot(); - }); - test('should render use case card component for security', async () => { - const component = await shallow(); - - expect(component).toMatchSnapshot(); - }); -}); diff --git a/src/plugins/home/public/application/components/guided_onboarding/use_case_card.tsx b/src/plugins/home/public/application/components/guided_onboarding/use_case_card.tsx deleted file mode 100644 index cb5d765fc66c6..0000000000000 --- a/src/plugins/home/public/application/components/guided_onboarding/use_case_card.tsx +++ /dev/null @@ -1,149 +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 { EuiCard, EuiText, EuiTitle, EuiImage } from '@elastic/eui'; - -import { METRIC_TYPE } from '@kbn/analytics'; -import { i18n } from '@kbn/i18n'; - -import { getServices } from '../../kibana_services'; - -type UseCaseConstants = { - [key in UseCase]: { - i18nTexts: { - title: string; - description: string; - }; - logo: { - altText: string; - }; - navigateOptions: { - appId: string; - path?: string; - }; - }; -}; -const constants: UseCaseConstants = { - search: { - i18nTexts: { - title: i18n.translate('home.guidedOnboarding.gettingStarted.search.cardTitle', { - defaultMessage: 'Search my data', - }), - description: i18n.translate('home.guidedOnboarding.gettingStarted.search.cardDescription', { - defaultMessage: - 'Create a finely-tuned search experience for your websites, applications, workplace content, and more.', - }), - }, - logo: { - altText: i18n.translate('home.guidedOnboarding.gettingStarted.search.iconName', { - defaultMessage: 'Enterprise Search logo', - }), - }, - navigateOptions: { - appId: 'enterpriseSearch', - // when navigating to ent search, do not provide path - }, - }, - observability: { - i18nTexts: { - title: i18n.translate('home.guidedOnboarding.gettingStarted.observability.cardTitle', { - defaultMessage: 'Monitor my environments', - }), - description: i18n.translate( - 'home.guidedOnboarding.gettingStarted.observability.cardDescription', - { - defaultMessage: - 'Get end-to-end observability into your environments by consolidating your logs, metrics, and traces.', - } - ), - }, - logo: { - altText: i18n.translate('home.guidedOnboarding.gettingStarted.observability.iconName', { - defaultMessage: 'Observability logo', - }), - }, - navigateOptions: { - appId: 'observability', - path: '/overview', - }, - }, - security: { - i18nTexts: { - title: i18n.translate('home.guidedOnboarding.gettingStarted.security.cardTitle', { - defaultMessage: 'Protect my environment', - }), - description: i18n.translate('home.guidedOnboarding.gettingStarted.security.cardDescription', { - defaultMessage: - 'Protect your environment against threats by unifying SIEM, endpoint security, and cloud security in one place.', - }), - }, - logo: { - altText: i18n.translate('home.guidedOnboarding.gettingStarted.security.iconName', { - defaultMessage: 'Security logo', - }), - }, - navigateOptions: { - appId: 'securitySolutionUI', - path: '/overview', - }, - }, -}; - -export type UseCase = 'search' | 'observability' | 'security'; -export interface UseCaseProps { - useCase: UseCase; -} - -export const UseCaseCard = ({ useCase }: UseCaseProps) => { - const { application, trackUiMetric, uiSettings, http } = getServices(); - - const isDarkTheme = uiSettings.get('theme:darkMode'); - - const getImageUrl = (imageName: UseCase) => { - const imagePath = `/plugins/home/assets/solution_logos/${imageName}${ - isDarkTheme ? '_dark' : '' - }.png`; - - return http.basePath.prepend(imagePath); - }; - - const onUseCaseSelection = () => { - trackUiMetric(METRIC_TYPE.CLICK, `guided_onboarding__use_case__${useCase}`); - - localStorage.setItem(`guidedOnboarding.${useCase}.tourActive`, JSON.stringify(true)); - application.navigateToApp(constants[useCase].navigateOptions.appId, { - path: constants[useCase].navigateOptions.path, - }); - }; - - const title = ( - -

    - {constants[useCase].i18nTexts.title} -

    -
    - ); - const description = ( - -

    {constants[useCase].i18nTexts.description}

    -
    - ); - return ( - } - title={title} - description={description} - // Used for FS tracking - data-test-subj={`onboarding--${useCase}UseCaseCard`} - onClick={onUseCaseSelection} - /> - ); -}; diff --git a/src/plugins/home/public/application/kibana_services.ts b/src/plugins/home/public/application/kibana_services.ts index af4591c8e7368..b622cf862f315 100644 --- a/src/plugins/home/public/application/kibana_services.ts +++ b/src/plugins/home/public/application/kibana_services.ts @@ -20,6 +20,7 @@ import { UiCounterMetricType } from '@kbn/analytics'; import { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; import { DataViewsContract } from '@kbn/data-views-plugin/public'; import { SharePluginSetup } from '@kbn/share-plugin/public'; +import { GuidedOnboardingApi } from '@kbn/guided-onboarding-plugin/public'; import { TutorialService } from '../services/tutorials'; import { AddDataService } from '../services/add_data'; import { FeatureCatalogueRegistry } from '../services/feature_catalogue'; @@ -49,6 +50,7 @@ export interface HomeKibanaServices { tutorialService: TutorialService; addDataService: AddDataService; welcomeService: WelcomeService; + guidedOnboardingService?: GuidedOnboardingApi; } let services: HomeKibanaServices | null = null; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index e27ddf107a5ee..c85f920fca6e1 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -18,6 +18,7 @@ import { i18n } from '@kbn/i18n'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; +import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public'; import { AppNavLinkStatus } from '@kbn/core/public'; import { SharePluginSetup } from '@kbn/share-plugin/public'; import type { CloudSetup } from '@kbn/cloud-plugin/public'; @@ -40,6 +41,7 @@ import { export interface HomePluginStartDependencies { dataViews: DataViewsPublicPluginStart; urlForwarding: UrlForwardingStart; + guidedOnboarding: GuidedOnboardingPluginStart; } export interface HomePluginSetupDependencies { @@ -78,7 +80,7 @@ export class HomePublicPlugin const trackUiMetric = usageCollection ? usageCollection.reportUiCounter.bind(usageCollection, 'Kibana_home') : () => {}; - const [coreStart, { dataViews, urlForwarding: urlForwardingStart }] = + const [coreStart, { dataViews, urlForwarding: urlForwardingStart, guidedOnboarding }] = await core.getStartServices(); setServices({ share, @@ -102,6 +104,7 @@ export class HomePublicPlugin addDataService: this.addDataService, featureCatalogue: this.featuresCatalogueRegistry, welcomeService: this.welcomeService, + guidedOnboardingService: guidedOnboarding.guidedOnboardingApi, }); coreStart.chrome.docTitle.change( i18n.translate('home.pageTitle', { defaultMessage: 'Home' }) diff --git a/src/plugins/home/tsconfig.json b/src/plugins/home/tsconfig.json index af121720eee0e..af12fb12f3381 100644 --- a/src/plugins/home/tsconfig.json +++ b/src/plugins/home/tsconfig.json @@ -16,6 +16,7 @@ { "path": "../share/tsconfig.json" }, { "path": "../url_forwarding/tsconfig.json" }, { "path": "../usage_collection/tsconfig.json" }, - { "path": "../../../x-pack/plugins/cloud/tsconfig.json" } + { "path": "../guided_onboarding/tsconfig.json" }, + { "path": "../../../x-pack/plugins/cloud/tsconfig.json" }, ] } diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx index 0780b05778ca0..26b5c1770ee8a 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -188,6 +188,7 @@ export const QueryBarTopRow = React.memo( notifications, docLinks, http, + dataViews, } = kibana.services; const isQueryLangSelected = props.query && !isOfQueryType(props.query); @@ -550,6 +551,7 @@ export const QueryBarTopRow = React.memo( docLinks, http, uiSettings, + dataViews, }} /> diff --git a/src/plugins/unified_search/public/query_string_input/query_string_input.tsx b/src/plugins/unified_search/public/query_string_input/query_string_input.tsx index 95749ec43ce47..cc4e934b1270e 100644 --- a/src/plugins/unified_search/public/query_string_input/query_string_input.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_string_input.tsx @@ -31,7 +31,11 @@ import { compact, debounce, isEmpty, isEqual, isFunction, partition } from 'loda import { CoreStart, DocLinksStart, Toast } from '@kbn/core/public'; import type { Query } from '@kbn/es-query'; import { DataPublicPluginStart, getQueryLog } from '@kbn/data-plugin/public'; -import { type DataView, DataView as KibanaDataView } from '@kbn/data-views-plugin/public'; +import { + type DataView, + DataView as KibanaDataView, + DataViewsPublicPluginStart, +} from '@kbn/data-views-plugin/public'; import type { PersistedLog } from '@kbn/data-plugin/public'; import { getFieldSubtypeNested, KIBANA_USER_QUERY_LANGUAGE_KEY } from '@kbn/data-plugin/common'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; @@ -61,6 +65,7 @@ export interface QueryStringInputDependencies { http: CoreStart['http']; docLinks: DocLinksStart; uiSettings: CoreStart['uiSettings']; + dataViews: DataViewsPublicPluginStart; } export interface QueryStringInputProps { @@ -196,7 +201,7 @@ export default class QueryStringInputUI extends PureComponent (); const { data, + dataViews, unifiedSearch, usageCollection, storage, @@ -118,6 +119,7 @@ function FilterRow({ size="s" deps={{ data, + dataViews, unifiedSearch, usageCollection, storage, diff --git a/src/plugins/vis_default_editor/public/types.ts b/src/plugins/vis_default_editor/public/types.ts index 3e3d0fbed29f1..2cef7977cd011 100644 --- a/src/plugins/vis_default_editor/public/types.ts +++ b/src/plugins/vis_default_editor/public/types.ts @@ -11,9 +11,11 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import type { AutocompleteStart } from '@kbn/unified-search-plugin/public'; import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; export interface VisDefaultEditorKibanaServices { data: DataPublicPluginStart; + dataViews: DataViewsPublicPluginStart; appName: string; unifiedSearch: { autocomplete: AutocompleteStart; diff --git a/src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx b/src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx index 05330329105de..c4b2a51afa27b 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx @@ -83,6 +83,7 @@ export function QueryBarWrapper({ docLinks, uiSettings, data, + dataViews, storage, usageCollection, }} diff --git a/src/plugins/vis_types/timeseries/public/application/components/render_counter.tsx b/src/plugins/vis_types/timeseries/public/application/components/render_counter.tsx index 8fc14b8d4827f..4dfb6e557084e 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/render_counter.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/render_counter.tsx @@ -8,9 +8,9 @@ import { useLayoutEffect, ReactNode } from 'react'; interface RenderCounterProps { - initialRender: Function; postponeExecution?: boolean; children?: ReactNode; + initialRender: Function | undefined; } /** HOC component to call "initialRender" method after finishing all DOM mutations. **/ @@ -21,7 +21,7 @@ export const RenderCounter = ({ }: RenderCounterProps) => { useLayoutEffect(() => { if (!postponeExecution) { - initialRender(); + initialRender?.(); } }, [initialRender, postponeExecution]); diff --git a/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts b/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts index 65f8dfa763093..8748904d61437 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts @@ -69,5 +69,5 @@ export interface TimeseriesVisProps { indexPattern?: FetchedIndexPattern['indexPattern']; /** @deprecated please use indexPattern.fieldFormatMap instead **/ fieldFormatMap?: FieldFormatMap; - initialRender: () => void; + initialRender: () => void | undefined; } diff --git a/src/plugins/vis_types/timeseries/public/application/components/vis_with_splits.js b/src/plugins/vis_types/timeseries/public/application/components/vis_with_splits.js index 73c65e785a27c..42649c9852e3b 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/vis_with_splits.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_with_splits.js @@ -89,7 +89,7 @@ export function visWithSplits(WrappedComponent) { ? findIndex(model.series, (s) => s.id === nonSplitSeries.id) : null; - const rows = Object.keys(splitsVisData).map((key) => { + const rows = Object.keys(splitsVisData).map((key, index, arrayRef) => { const splitData = splitsVisData[key]; const { series, label } = splitData; const additionalLabel = label; @@ -115,7 +115,7 @@ export function visWithSplits(WrappedComponent) { backgroundColor={props.backgroundColor} getConfig={props.getConfig} fieldFormatMap={props.fieldFormatMap} - initialRender={props.initialRender} + initialRender={arrayRef.length - 1 === index ? props.initialRender : undefined} />
    ); diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js index 1ca0f6d50efcc..7bfb0456b4a46 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js @@ -101,7 +101,7 @@ export const TimeSeries = ({ const onRenderChange = useCallback( (isRendered) => { if (isRendered) { - initialRender(); + initialRender?.(); } }, [initialRender] diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts index bd0a9d572f192..c06cc3e722279 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts @@ -27,6 +27,7 @@ interface ExtraColumnFields { isSplit?: boolean; reducedTimeRange?: string; timeShift?: string; + isAssignTimeScale?: boolean; } const isSupportedFormat = (format: string) => ['bytes', 'number', 'percent'].includes(format); @@ -56,7 +57,13 @@ export const createColumn = ( series: Series, metric: Metric, field?: DataViewField, - { isBucketed = false, isSplit = false, reducedTimeRange, timeShift }: ExtraColumnFields = {} + { + isBucketed = false, + isSplit = false, + reducedTimeRange, + timeShift, + isAssignTimeScale = true, + }: ExtraColumnFields = {} ): GeneralColumnWithMeta => ({ columnId: uuid(), dataType: (field?.type as DataType) ?? undefined, @@ -66,7 +73,7 @@ export const createColumn = ( reducedTimeRange, filter: series.filter, timeShift, - timeScale: getTimeScale(metric), + timeScale: isAssignTimeScale ? getTimeScale(metric) : undefined, meta: { metricId: metric.id }, }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts index 15b35fade92c2..91d887f6a6680 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts @@ -38,7 +38,7 @@ export const createFormulaColumn = ( return { operationType: 'formula', references: [], - ...createColumn(series, metric), + ...createColumn(series, metric, undefined, { isAssignTimeScale: false }), params: { ...params, ...getFormat(series) }, }; }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts index 8d970f2f7262d..4b679d0dd0d15 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts @@ -133,10 +133,13 @@ export const getFormulaEquivalent = ( }${addAdditionalArgs({ reducedTimeRange, timeShift })})`; } case 'positive_rate': { - return buildCounterRateFormula(aggFormula, currentMetric.field!, { + const counterRateFormula = buildCounterRateFormula(aggFormula, currentMetric.field!, { reducedTimeRange, timeShift, }); + return currentMetric.unit + ? `normalize_by_unit(${counterRateFormula}, unit='${getTimeScale(currentMetric)}')` + : counterRateFormula; } case 'filter_ratio': { return getFilterRatioFormula(currentMetric, { reducedTimeRange, timeShift }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts index d357d886ff5bd..bc4c8eea11baa 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts @@ -9,7 +9,7 @@ import { TSVB_METRIC_TYPES } from '../../../../common/enums'; import type { Metric } from '../../../../common/types'; import { getFormulaFromMetric, SUPPORTED_METRICS } from './supported_metrics'; -import { getFormulaEquivalent } from './metrics_helpers'; +import { getFormulaEquivalent, getTimeScale } from './metrics_helpers'; const getAdditionalArgs = (metric: Metric) => { if (metric.type === TSVB_METRIC_TYPES.POSITIVE_ONLY) { @@ -54,5 +54,6 @@ export const getPipelineSeriesFormula = ( } const additionalArgs = getAdditionalArgs(metric); - return `${aggFormula}(${subFormula}${additionalArgs})`; + const formula = `${aggFormula}(${subFormula}${additionalArgs})`; + return metric.unit ? `normalize_by_unit(${formula}, unit='${getTimeScale(metric)}')` : formula; }; diff --git a/test/api_integration/apis/saved_objects/bulk_create.ts b/test/api_integration/apis/saved_objects/bulk_create.ts index 5867b8125303a..43d7d9d8273bb 100644 --- a/test/api_integration/apis/saved_objects/bulk_create.ts +++ b/test/api_integration/apis/saved_objects/bulk_create.ts @@ -69,6 +69,7 @@ export default function ({ getService }: FtrProviderContext) { type: 'dashboard', id: 'a01b2f57-fcfd-4864-b735-09e28f0d815e', updated_at: resp.body.saved_objects[1].updated_at, + created_at: resp.body.saved_objects[1].created_at, version: resp.body.saved_objects[1].version, attributes: { title: 'A great new dashboard', diff --git a/test/api_integration/apis/saved_objects/bulk_get.ts b/test/api_integration/apis/saved_objects/bulk_get.ts index e349482960678..4bf9d6c6b3348 100644 --- a/test/api_integration/apis/saved_objects/bulk_get.ts +++ b/test/api_integration/apis/saved_objects/bulk_get.ts @@ -54,6 +54,8 @@ export default function ({ getService }: FtrProviderContext) { const mockDate = '2015-01-01T00:00:00.000Z'; resp.body.saved_objects[0].updated_at = mockDate; resp.body.saved_objects[2].updated_at = mockDate; + resp.body.saved_objects[0].created_at = mockDate; + resp.body.saved_objects[2].created_at = mockDate; expect(resp.body).to.eql({ saved_objects: [ @@ -61,6 +63,7 @@ export default function ({ getService }: FtrProviderContext) { id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', type: 'visualization', updated_at: '2015-01-01T00:00:00.000Z', + created_at: '2015-01-01T00:00:00.000Z', version: resp.body.saved_objects[0].version, attributes: { title: 'Count of requests', @@ -96,6 +99,7 @@ export default function ({ getService }: FtrProviderContext) { id: '7.0.0-alpha1', type: 'config', updated_at: '2015-01-01T00:00:00.000Z', + created_at: '2015-01-01T00:00:00.000Z', version: resp.body.saved_objects[2].version, attributes: { buildNum: 8467, diff --git a/test/api_integration/apis/saved_objects/create.ts b/test/api_integration/apis/saved_objects/create.ts index 00018e47c9dd3..df1e59bc51b23 100644 --- a/test/api_integration/apis/saved_objects/create.ts +++ b/test/api_integration/apis/saved_objects/create.ts @@ -56,6 +56,7 @@ export default function ({ getService }: FtrProviderContext) { migrationVersion: resp.body.migrationVersion, coreMigrationVersion: KIBANA_VERSION, updated_at: resp.body.updated_at, + created_at: resp.body.created_at, version: resp.body.version, attributes: { title: 'My favorite vis', diff --git a/test/api_integration/apis/saved_objects/export.ts b/test/api_integration/apis/saved_objects/export.ts index 6314fbbe675d0..4c06573d86e08 100644 --- a/test/api_integration/apis/saved_objects/export.ts +++ b/test/api_integration/apis/saved_objects/export.ts @@ -363,6 +363,7 @@ export default function ({ getService }: FtrProviderContext) { ], type: 'dashboard', updated_at: objects[0].updated_at, + created_at: objects[0].created_at, version: objects[0].version, }); expect(objects[0].migrationVersion).to.be.ok(); @@ -423,6 +424,7 @@ export default function ({ getService }: FtrProviderContext) { ], type: 'dashboard', updated_at: objects[0].updated_at, + created_at: objects[0].created_at, version: objects[0].version, }); expect(objects[0].migrationVersion).to.be.ok(); @@ -488,6 +490,7 @@ export default function ({ getService }: FtrProviderContext) { ], type: 'dashboard', updated_at: objects[0].updated_at, + created_at: objects[0].updated_at, version: objects[0].version, }); expect(objects[0].migrationVersion).to.be.ok(); diff --git a/test/api_integration/apis/saved_objects/get.ts b/test/api_integration/apis/saved_objects/get.ts index 8122308e44930..88c8884c7cdc6 100644 --- a/test/api_integration/apis/saved_objects/get.ts +++ b/test/api_integration/apis/saved_objects/get.ts @@ -38,6 +38,7 @@ export default function ({ getService }: FtrProviderContext) { id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', type: 'visualization', updated_at: resp.body.updated_at, + created_at: resp.body.created_at, version: resp.body.version, migrationVersion: resp.body.migrationVersion, coreMigrationVersion: KIBANA_VERSION, diff --git a/test/api_integration/apis/saved_objects/resolve.ts b/test/api_integration/apis/saved_objects/resolve.ts index a00a44f98223d..8ca1904ef8c88 100644 --- a/test/api_integration/apis/saved_objects/resolve.ts +++ b/test/api_integration/apis/saved_objects/resolve.ts @@ -39,12 +39,14 @@ export default function ({ getService }: FtrProviderContext) { .expect(200) .then((resp) => { resp.body.saved_object.updated_at = '2015-01-01T00:00:00.000Z'; + resp.body.saved_object.created_at = '2015-01-01T00:00:00.000Z'; expect(resp.body).to.eql({ saved_object: { id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', type: 'visualization', updated_at: '2015-01-01T00:00:00.000Z', + created_at: '2015-01-01T00:00:00.000Z', version: resp.body.saved_object.version, migrationVersion: resp.body.saved_object.migrationVersion, coreMigrationVersion: KIBANA_VERSION, diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index cb9b70808099d..c3106d19204f2 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -94,6 +94,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'data.search.asyncSearch.batchedReduceSize (number)', 'data.search.asyncSearch.keepAlive (duration)', 'data.search.asyncSearch.waitForCompletion (duration)', + 'data.search.asyncSearch.pollInterval (number)', 'data.search.sessions.defaultExpiration (duration)', 'data.search.sessions.enabled (boolean)', 'data.search.sessions.management.expiresSoonWarning (duration)', @@ -103,7 +104,6 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'data.search.sessions.maxUpdateRetries (number)', 'data.search.sessions.notTouchedTimeout (duration)', 'enterpriseSearch.host (string)', - 'guidedOnboarding.ui (boolean)', 'home.disableWelcomeScreen (boolean)', 'map.emsFileApiUrl (string)', 'map.emsFontLibraryUrl (string)', diff --git a/tsconfig.base.json b/tsconfig.base.json index 72b98c7af3c8c..6d42c567d3422 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -475,8 +475,6 @@ "@kbn/global-search-test-plugin/*": ["x-pack/test/plugin_functional/plugins/global_search_test/*"], "@kbn/resolver-test-plugin": ["x-pack/test/plugin_functional/plugins/resolver_test"], "@kbn/resolver-test-plugin/*": ["x-pack/test/plugin_functional/plugins/resolver_test/*"], - "@kbn/timelines-test-plugin": ["x-pack/test/plugin_functional/plugins/timelines_test"], - "@kbn/timelines-test-plugin/*": ["x-pack/test/plugin_functional/plugins/timelines_test/*"], "@kbn/security-test-endpoints-plugin": ["x-pack/test/security_functional/fixtures/common/test_endpoints"], "@kbn/security-test-endpoints-plugin/*": ["x-pack/test/security_functional/fixtures/common/test_endpoints/*"], "@kbn/application-usage-test-plugin": ["x-pack/test/usage_collection/plugins/application_usage_test"], diff --git a/x-pack/build_chromium/.chromium-commit b/x-pack/build_chromium/.chromium-commit deleted file mode 100644 index c68babc821f44..0000000000000 --- a/x-pack/build_chromium/.chromium-commit +++ /dev/null @@ -1 +0,0 @@ -ef768c94bcb42dca4c27048615d07efadbb1c1c2 diff --git a/x-pack/build_chromium/README.md b/x-pack/build_chromium/README.md index 94ebdf47d286f..df097e1cbef8b 100644 --- a/x-pack/build_chromium/README.md +++ b/x-pack/build_chromium/README.md @@ -24,6 +24,11 @@ location](https://commondatastorage.googleapis.com/chromium-browser-snapshots/in ## Build Script Usage +The system OS requires a few setup steps: +1. Required packages: `bzip2`, `git`, `lsb_release`, `python3` +2. The `python` command needs to launch Python 3. +3. Recommended: `tmux`, as your ssh session may get interrupted + These commands show how to set up an environment to build: ```sh # Allow our scripts to use depot_tools commands @@ -36,7 +41,7 @@ mkdir ~/chromium && cd ~/chromium gsutil cp -r gs://headless_shell_staging/build_chromium . # Install the OS packages, configure the environment, download the chromium source (25GB) -python ./build_chromium/init.py [arch_name] +python ./build_chromium/init.py # Run the build script with the path to the chromium src directory, the git commit hash python ./build_chromium/build.py 70f5d88ea95298a18a85c33c98ea00e02358ad75 x64 @@ -67,7 +72,7 @@ A good how-to on building Chromium from source is We have an `linux/args.gn` file that is automatically copied to the build target directory. To get a list of the build arguments that are enabled, install `depot_tools` and run -`gn args out/headless --list`. It prints out all of the flags and their +`gn args out/headless --list` from the `chromium/src` directory. It prints out all of the flags and their settings, including the defaults. Some build flags are documented [here](https://www.chromium.org/developers/gn-build-configuration). @@ -86,10 +91,6 @@ are created in x64 using cross-compiling. CentOS is not supported for building C - 8 CPU - 30GB memory - 80GB free space on disk (Try `ncdu /home` to see where space is used.) - - git - - python2 (`python` must link to `python2`) - - lsb_release - - tmux is recommended in case your ssh session is interrupted - "Cloud API access scopes": must have **read / write** scope for the Storage API 4. Install [Google Cloud SDK](https://cloud.google.com/sdk) locally to ssh into the GCP instance diff --git a/x-pack/build_chromium/build.py b/x-pack/build_chromium/build.py index fd5c1d3f16a65..ec8c1a57217e4 100644 --- a/x-pack/build_chromium/build.py +++ b/x-pack/build_chromium/build.py @@ -66,12 +66,8 @@ os.environ['PATH'] = full_path # configure environment: build dependencies -if platform.system() == 'Linux': - if arch_name: - print('Running sysroot install script...') - runcmd(src_path + '/build/linux/sysroot_scripts/install-sysroot.py --arch=' + arch_name) - print('Running install-build-deps...') - runcmd(src_path + '/build/install-build-deps.sh') +print('Running sysroot install script...') +runcmd(src_path + '/build/linux/sysroot_scripts/install-sysroot.py --arch=' + arch_name) print('Updating all modules') runcmd('gclient sync -D') @@ -95,14 +91,14 @@ # Optimize the output on Linux x64 by stripping inessentials from the binary # ARM must be cross-compiled from Linux and can not read the ARM binary in order to strip -if platform.system() != 'Windows' and arch_name != 'arm64': +if arch_name != 'arm64': print('Optimizing headless_shell') shutil.move('out/headless/headless_shell', 'out/headless/headless_shell_raw') runcmd('strip -o out/headless/headless_shell out/headless/headless_shell_raw') # Create the zip and generate the md5 hash using filenames like: # chromium-4747cc2-linux_x64.zip -base_filename = 'out/headless/chromium-' + base_version + '-' + platform.system().lower() + '_' + arch_name +base_filename = 'out/headless/chromium-' + base_version + '-locales-' + platform.system().lower() + '_' + arch_name zip_filename = base_filename + '.zip' md5_filename = base_filename + '.md5' @@ -115,6 +111,9 @@ archive.write('out/headless/headless_shell', path.join(path_prefix, 'headless_shell')) archive.write('out/headless/libEGL.so', path.join(path_prefix, 'libEGL.so')) archive.write('out/headless/libGLESv2.so', path.join(path_prefix, 'libGLESv2.so')) +archive.write('out/headless/libvk_swiftshader.so', path.join(path_prefix, 'libvk_swiftshader.so')) +archive.write('out/headless/libvulkan.so.1', path.join(path_prefix, 'libvulkan.so.1')) +archive.write('out/headless/vk_swiftshader_icd.json', path.join(path_prefix, 'vk_swiftshader_icd.json')) archive.write(en_us_locale_file_path, path.join(path_prefix, 'locales', en_us_locale_pak_file_name)) archive.close() diff --git a/x-pack/build_chromium/init.py b/x-pack/build_chromium/init.py index e5a8ea3a2b9d9..84d2a06b41734 100644 --- a/x-pack/build_chromium/init.py +++ b/x-pack/build_chromium/init.py @@ -6,13 +6,9 @@ # once per environment. # Set to "arm" to build for ARM -arch_name = sys.argv[1] if len(sys.argv) >= 2 else 'undefined' build_path = path.abspath(os.curdir) src_path = path.abspath(path.join(build_path, 'chromium', 'src')) -if arch_name != 'x64' and arch_name != 'arm64': - raise Exception('Unexpected architecture: ' + arch_name + '. `x64` and `arm64` are supported.') - # Configure git print('Configuring git globals...') runcmd('git config --global core.autocrlf false') @@ -29,8 +25,8 @@ print('Updating depot_tools...') original_dir = os.curdir os.chdir(path.join(build_path, 'depot_tools')) - runcmd('git checkout master') - runcmd('git pull origin master') + runcmd('git checkout main') + runcmd('git pull origin main') os.chdir(original_dir) # Fetch the Chromium source code diff --git a/x-pack/build_chromium/linux/args.gn b/x-pack/build_chromium/linux/args.gn index fa6d4e8bcd15b..29ec3207c8543 100644 --- a/x-pack/build_chromium/linux/args.gn +++ b/x-pack/build_chromium/linux/args.gn @@ -1,9 +1,27 @@ +# Build args reference: https://www.chromium.org/developers/gn-build-configuration/ import("//build/args/headless.gn") -is_debug = false -symbol_level = 0 + +is_official_build = true is_component_build = false +is_debug = false + enable_nacl = false +enable_stripping = true + +chrome_pgo_phase = 0 +dcheck_always_on = false +blink_symbol_level = 0 +symbol_level = 0 +v8_symbol_level = 0 + +enable_ink = false +rtc_build_examples = false +angle_build_tests = false +enable_screen_ai_service = false +enable_vr = false + # Please, consult @elastic/kibana-security before changing/removing this option. use_kerberos = false -# target_cpu is appended before build: "x64" or "arm64" +target_os = "linux" +# target_cpu is added at build timeure a minimal build diff --git a/x-pack/performance/journeys/data_stress_test_lens.ts b/x-pack/performance/journeys/data_stress_test_lens.ts index 6d65dc5e4a0d2..9d4a6439da49f 100644 --- a/x-pack/performance/journeys/data_stress_test_lens.ts +++ b/x-pack/performance/journeys/data_stress_test_lens.ts @@ -11,7 +11,8 @@ import { waitForVisualizations } from '../utils'; export const journey = new Journey({ kbnArchives: ['test/functional/fixtures/kbn_archiver/stress_test'], esArchives: ['test/functional/fixtures/es_archiver/stress_test'], -}).step('Go to dashboard', async ({ page, kbnUrl }) => { +}).step('Go to dashboard', async ({ page, kbnUrl, kibanaServer }) => { + await kibanaServer.uiSettings.update({ 'histogram:maxBars': 100 }); await page.goto(kbnUrl.get(`/app/dashboards#/view/92b143a0-2e9c-11ed-b1b6-a504560b392c`)); await waitForVisualizations(page, 1); diff --git a/x-pack/plugins/actions/server/action_type_registry.test.ts b/x-pack/plugins/actions/server/action_type_registry.test.ts index bad09ce70207d..54974b4754955 100644 --- a/x-pack/plugins/actions/server/action_type_registry.test.ts +++ b/x-pack/plugins/actions/server/action_type_registry.test.ts @@ -70,7 +70,7 @@ describe('register()', () => { "actions:my-action-type": Object { "createTaskRunner": [Function], "getRetry": [Function], - "maxAttempts": 1, + "maxAttempts": 3, "title": "My action type", }, }, diff --git a/x-pack/plugins/actions/server/action_type_registry.ts b/x-pack/plugins/actions/server/action_type_registry.ts index a1466d2d40408..b19929c390bf1 100644 --- a/x-pack/plugins/actions/server/action_type_registry.ts +++ b/x-pack/plugins/actions/server/action_type_registry.ts @@ -25,6 +25,8 @@ import { ActionTypeParams, } from './types'; +export const MAX_ATTEMPTS: number = 3; + export interface ActionTypeRegistryOpts { licensing: LicensingPluginSetup; taskManager: TaskManagerSetupContract; @@ -151,7 +153,7 @@ export class ActionTypeRegistry { this.taskManager.registerTaskDefinitions({ [`actions:${actionType.id}`]: { title: actionType.name, - maxAttempts: actionType.maxAttempts || 1, + maxAttempts: actionType.maxAttempts || MAX_ATTEMPTS, getRetry(attempts: number, error: unknown) { if (error instanceof ExecutorError) { return error.retry == null ? false : error.retry; diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 0bcb9cf527548..4fde645fb367e 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -781,7 +781,7 @@ test('logs a warning and error when alert executor throws an error', async () => executorMock.mockRejectedValue(err); await actionExecutor.execute(executeParams); expect(loggerMock.warn).toBeCalledWith( - 'action execution failure: test:1: action-1: an error occurred while running the action: this action execution is intended to fail' + 'action execution failure: test:1: action-1: an error occurred while running the action: this action execution is intended to fail; retry: true' ); expect(loggerMock.error).toBeCalledWith(err, { error: { stack_trace: 'foo error\n stack 1\n stack 2\n stack 3' }, diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 40f6b38f085f8..42e5c8c8e1a99 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -239,7 +239,7 @@ export class ActionExecutor { message: 'an error occurred while running the action', serviceMessage: err.message, error: err, - retry: false, + retry: true, }; } } diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 8248dee862394..934b6b45f80ac 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -43,7 +43,7 @@ import { import { ActionsConfig, getValidatedConfig } from './config'; import { resolveCustomHosts } from './lib/custom_host_settings'; import { ActionsClient } from './actions_client'; -import { ActionTypeRegistry } from './action_type_registry'; +import { ActionTypeRegistry, MAX_ATTEMPTS } from './action_type_registry'; import { createExecutionEnqueuerFunction, createEphemeralExecutionEnqueuerFunction, @@ -355,6 +355,7 @@ export class ActionsPlugin implements Plugin ) => { ensureSufficientLicense(actionType); + actionType.maxAttempts = actionType.maxAttempts ?? MAX_ATTEMPTS; actionTypeRegistry.register(actionType); }, registerSubActionConnectorType: < diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx index 74be1a0f048fc..ca7134f6f09fb 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx @@ -93,7 +93,7 @@ export const ExplainLogRateSpikesAnalysis: FC searchQuery: JSON.stringify(searchQuery), // TODO Handle data view without time fields. timeFieldName: dataView.timeFieldName ?? '', - index: dataView.title, + index: dataView.getIndexPattern(), grouping: true, flushFix: true, ...windowParameters, diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_app_state.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_app_state.tsx index 34460240d0134..ba69fdfa8a7b6 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_app_state.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_app_state.tsx @@ -5,11 +5,7 @@ * 2.0. */ -import React, { FC, useCallback } from 'react'; -import { parse, stringify } from 'query-string'; -import { isEqual } from 'lodash'; -import { encode } from 'rison-node'; -import { useHistory, useLocation } from 'react-router-dom'; +import React, { FC } from 'react'; import { EuiCallOut } from '@elastic/eui'; @@ -24,15 +20,7 @@ import { SearchQueryLanguage, SavedSearchSavedObject, } from '../../application/utils/search_utils'; -import { - Accessor, - Dictionary, - parseUrlState, - Provider as UrlStateContextProvider, - isRisonSerializationRequired, - getNestedProperty, - SetUrlState, -} from '../../hooks/use_url_state'; +import { UrlStateProvider } from '../../hooks/use_url_state'; import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context'; import { AiopsAppContext } from '../../hooks/use_aiops_app_context'; @@ -77,71 +65,6 @@ export const ExplainLogRateSpikesAppState: FC savedSearch, appDependencies, }) => { - const history = useHistory(); - const { search: urlSearchString } = useLocation(); - - const setUrlState: SetUrlState = useCallback( - ( - accessor: Accessor, - attribute: string | Dictionary, - value?: any, - replaceState?: boolean - ) => { - const prevSearchString = urlSearchString; - const urlState = parseUrlState(prevSearchString); - const parsedQueryString = parse(prevSearchString, { sort: false }); - - if (!Object.prototype.hasOwnProperty.call(urlState, accessor)) { - urlState[accessor] = {}; - } - - if (typeof attribute === 'string') { - if (isEqual(getNestedProperty(urlState, `${accessor}.${attribute}`), value)) { - return prevSearchString; - } - - urlState[accessor][attribute] = value; - } else { - const attributes = attribute; - Object.keys(attributes).forEach((a) => { - urlState[accessor][a] = attributes[a]; - }); - } - - try { - const oldLocationSearchString = stringify(parsedQueryString, { - sort: false, - encode: false, - }); - - Object.keys(urlState).forEach((a) => { - if (isRisonSerializationRequired(a)) { - parsedQueryString[a] = encode(urlState[a]); - } else { - parsedQueryString[a] = urlState[a]; - } - }); - const newLocationSearchString = stringify(parsedQueryString, { - sort: false, - encode: false, - }); - - if (oldLocationSearchString !== newLocationSearchString) { - const newSearchString = stringify(parsedQueryString, { sort: false }); - if (replaceState) { - history.replace({ search: newSearchString }); - } else { - history.push({ search: newSearchString }); - } - } - } catch (error) { - // eslint-disable-next-line no-console - console.error('Could not save url state', error); - } - }, - [history, urlSearchString] - ); - if (!dataView) return null; if (!dataView.isTimeBased()) { @@ -165,11 +88,11 @@ export const ExplainLogRateSpikesAppState: FC return ( - + - + ); }; diff --git a/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts b/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts index f6d6488567f10..a363692f29c70 100644 --- a/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts +++ b/x-pack/plugins/aiops/public/components/full_time_range_selector/full_time_range_selector_service.ts @@ -40,7 +40,7 @@ export async function setFullTimeRange( ): Promise { const runtimeMappings = dataView.getRuntimeMappings(); const resp = await getTimeFieldRange({ - index: dataView.title, + index: dataView.getIndexPattern(), timeFieldName: dataView.timeFieldName, query: excludeFrozenData ? addExcludeFrozenToQuery(query) : query, ...(isPopulatedObject(runtimeMappings) ? { runtimeMappings } : {}), diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx index 1a546f5ec60bf..bc67b0f32eda2 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx @@ -11,6 +11,7 @@ import { LogCategorizationPage } from './log_categorization_page'; import { SavedSearchSavedObject } from '../../application/utils/search_utils'; import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context'; import { AiopsAppContext } from '../../hooks/use_aiops_app_context'; +import { UrlStateProvider } from '../../hooks/use_url_state'; export interface LogCategorizationAppStateProps { dataView: DataView; @@ -25,7 +26,9 @@ export const LogCategorizationAppState: FC = ({ }) => { return ( - + + + ); }; diff --git a/x-pack/plugins/aiops/public/hooks/use_data.ts b/x-pack/plugins/aiops/public/hooks/use_data.ts index 9d8f889dd8476..11977c2543001 100644 --- a/x-pack/plugins/aiops/public/hooks/use_data.ts +++ b/x-pack/plugins/aiops/public/hooks/use_data.ts @@ -148,7 +148,7 @@ export const useData = ( earliest: timefilterActiveBounds.min?.valueOf(), latest: timefilterActiveBounds.max?.valueOf(), intervalMs: _timeBuckets.getInterval()?.asMilliseconds(), - index: currentDataView.title, + index: currentDataView.getIndexPattern(), searchQuery, timeFieldName: currentDataView.timeFieldName, runtimeFieldMap: currentDataView.getRuntimeMappings(), diff --git a/x-pack/plugins/aiops/public/hooks/use_url_state.ts b/x-pack/plugins/aiops/public/hooks/use_url_state.tsx similarity index 63% rename from x-pack/plugins/aiops/public/hooks/use_url_state.ts rename to x-pack/plugins/aiops/public/hooks/use_url_state.tsx index 21d58c5766c52..e6564ac72f9bf 100644 --- a/x-pack/plugins/aiops/public/hooks/use_url_state.ts +++ b/x-pack/plugins/aiops/public/hooks/use_url_state.tsx @@ -5,9 +5,12 @@ * 2.0. */ -import { parse } from 'query-string'; +import React, { FC } from 'react'; +import { parse, stringify } from 'query-string'; import { createContext, useCallback, useContext, useMemo } from 'react'; -import { decode } from 'rison-node'; +import { decode, encode } from 'rison-node'; +import { useHistory, useLocation } from 'react-router-dom'; +import { isEqual } from 'lodash'; export interface Dictionary { [id: string]: TValue; @@ -87,6 +90,79 @@ export const aiopsUrlStateStore = createContext({ export const { Provider } = aiopsUrlStateStore; +export const UrlStateProvider: FC = ({ children }) => { + const { Provider: StateProvider } = aiopsUrlStateStore; + + const history = useHistory(); + const { search: urlSearchString } = useLocation(); + + const setUrlState: SetUrlState = useCallback( + ( + accessor: Accessor, + attribute: string | Dictionary, + value?: any, + replaceState?: boolean + ) => { + const prevSearchString = urlSearchString; + const urlState = parseUrlState(prevSearchString); + const parsedQueryString = parse(prevSearchString, { sort: false }); + + if (!Object.prototype.hasOwnProperty.call(urlState, accessor)) { + urlState[accessor] = {}; + } + + if (typeof attribute === 'string') { + if (isEqual(getNestedProperty(urlState, `${accessor}.${attribute}`), value)) { + return prevSearchString; + } + + urlState[accessor][attribute] = value; + } else { + const attributes = attribute; + Object.keys(attributes).forEach((a) => { + urlState[accessor][a] = attributes[a]; + }); + } + + try { + const oldLocationSearchString = stringify(parsedQueryString, { + sort: false, + encode: false, + }); + + Object.keys(urlState).forEach((a) => { + if (isRisonSerializationRequired(a)) { + parsedQueryString[a] = encode(urlState[a]); + } else { + parsedQueryString[a] = urlState[a]; + } + }); + const newLocationSearchString = stringify(parsedQueryString, { + sort: false, + encode: false, + }); + + if (oldLocationSearchString !== newLocationSearchString) { + const newSearchString = stringify(parsedQueryString, { sort: false }); + if (replaceState) { + history.replace({ search: newSearchString }); + } else { + history.push({ search: newSearchString }); + } + } + } catch (error) { + // eslint-disable-next-line no-console + console.error('Could not save url state', error); + } + }, + [history, urlSearchString] + ); + + return ( + {children} + ); +}; + export const useUrlState = (accessor: Accessor) => { const { searchString, setUrlState: setUrlStateContext } = useContext(aiopsUrlStateStore); diff --git a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts index 67cbcce241401..c61e1915f68f7 100644 --- a/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts +++ b/x-pack/plugins/aiops/server/routes/explain_log_rate_spikes.ts @@ -157,524 +157,534 @@ export const defineExplainLogRateSpikesRoute = ( } async function runAnalysis() { - isRunning = true; - logDebugMessage('Reset.'); - push(resetAction()); - pushPingWithTimeout(); - logDebugMessage('Load field candidates.'); - push( - updateLoadingStateAction({ - ccsWarning: false, - loaded, - loadingState: i18n.translate( - 'xpack.aiops.explainLogRateSpikes.loadingState.loadingFieldCandidates', - { - defaultMessage: 'Loading field candidates.', - } - ), - }) - ); - - let fieldCandidates: Awaited>; try { - fieldCandidates = await fetchFieldCandidates(client, request.body); - } catch (e) { - logger.error(`Failed to fetch field candidates, got: \n${e.toString()}`); - pushError(`Failed to fetch field candidates.`); - end(); - return; - } - - loaded += LOADED_FIELD_CANDIDATES; - - push( - updateLoadingStateAction({ - ccsWarning: false, - loaded, - loadingState: i18n.translate( - 'xpack.aiops.explainLogRateSpikes.loadingState.identifiedFieldCandidates', - { - defaultMessage: - 'Identified {fieldCandidatesCount, plural, one {# field candidate} other {# field candidates}}.', - values: { - fieldCandidatesCount: fieldCandidates.length, - }, - } - ), - }) - ); - - if (fieldCandidates.length === 0) { - endWithUpdatedLoadingState(); - } else if (shouldStop) { - end(); - return; - } - - const changePoints: ChangePoint[] = []; - const fieldsToSample = new Set(); - const chunkSize = 10; - let chunkCount = 0; - - const fieldCandidatesChunks = chunk(fieldCandidates, chunkSize); - - logDebugMessage('Fetch p-values.'); + isRunning = true; + logDebugMessage('Reset.'); + push(resetAction()); + pushPingWithTimeout(); + logDebugMessage('Load field candidates.'); + push( + updateLoadingStateAction({ + ccsWarning: false, + loaded, + loadingState: i18n.translate( + 'xpack.aiops.explainLogRateSpikes.loadingState.loadingFieldCandidates', + { + defaultMessage: 'Loading field candidates.', + } + ), + }) + ); - for (const fieldCandidatesChunk of fieldCandidatesChunks) { - chunkCount++; - logDebugMessage(`Fetch p-values. Chunk ${chunkCount} of ${fieldCandidatesChunks.length}`); - let pValues: Awaited>; + let fieldCandidates: Awaited>; try { - pValues = await fetchChangePointPValues( - client, - request.body, - fieldCandidatesChunk, - logger, - pushError - ); + fieldCandidates = await fetchFieldCandidates(client, request.body); } catch (e) { - logger.error( - `Failed to fetch p-values for ${JSON.stringify( - fieldCandidatesChunk - )}, got: \n${e.toString()}` - ); - pushError(`Failed to fetch p-values for ${JSON.stringify(fieldCandidatesChunk)}.`); - // Still continue the analysis even if chunks of p-value queries fail. - continue; + logger.error(`Failed to fetch field candidates, got: \n${e.toString()}`); + pushError(`Failed to fetch field candidates.`); + end(); + return; } - if (pValues.length > 0) { - pValues.forEach((d) => { - fieldsToSample.add(d.fieldName); - }); - changePoints.push(...pValues); - } + loaded += LOADED_FIELD_CANDIDATES; - loaded += (1 / fieldCandidatesChunks.length) * PROGRESS_STEP_P_VALUES; - if (pValues.length > 0) { - push(addChangePointsAction(pValues)); - } push( updateLoadingStateAction({ ccsWarning: false, loaded, loadingState: i18n.translate( - 'xpack.aiops.explainLogRateSpikes.loadingState.identifiedFieldValuePairs', + 'xpack.aiops.explainLogRateSpikes.loadingState.identifiedFieldCandidates', { defaultMessage: - 'Identified {fieldValuePairsCount, plural, one {# significant field/value pair} other {# significant field/value pairs}}.', + 'Identified {fieldCandidatesCount, plural, one {# field candidate} other {# field candidates}}.', values: { - fieldValuePairsCount: changePoints?.length ?? 0, + fieldCandidatesCount: fieldCandidates.length, }, } ), }) ); - if (shouldStop) { - logDebugMessage('shouldStop fetching p-values.'); - + if (fieldCandidates.length === 0) { + endWithUpdatedLoadingState(); + } else if (shouldStop) { end(); return; } - } - if (changePoints?.length === 0) { - logDebugMessage('Stopping analysis, did not find change points.'); - endWithUpdatedLoadingState(); - return; - } + const changePoints: ChangePoint[] = []; + const fieldsToSample = new Set(); + const chunkSize = 10; + let chunkCount = 0; - const histogramFields: [NumericHistogramField] = [ - { fieldName: request.body.timeFieldName, type: KBN_FIELD_TYPES.DATE }, - ]; + const fieldCandidatesChunks = chunk(fieldCandidates, chunkSize); - logDebugMessage('Fetch overall histogram.'); + logDebugMessage('Fetch p-values.'); - let overallTimeSeries: NumericChartData | undefined; - try { - overallTimeSeries = ( - (await fetchHistogramsForFields( - client, - request.body.index, - { match_all: {} }, - // fields - histogramFields, - // samplerShardSize - -1, - undefined - )) as [NumericChartData] - )[0]; - } catch (e) { - logger.error(`Failed to fetch the overall histogram data, got: \n${e.toString()}`); - pushError(`Failed to fetch overall histogram data.`); - // Still continue the analysis even if loading the overall histogram fails. - } + for (const fieldCandidatesChunk of fieldCandidatesChunks) { + chunkCount++; + logDebugMessage( + `Fetch p-values. Chunk ${chunkCount} of ${fieldCandidatesChunks.length}` + ); + let pValues: Awaited>; + try { + pValues = await fetchChangePointPValues( + client, + request.body, + fieldCandidatesChunk, + logger, + pushError + ); + } catch (e) { + logger.error( + `Failed to fetch p-values for ${JSON.stringify( + fieldCandidatesChunk + )}, got: \n${e.toString()}` + ); + pushError(`Failed to fetch p-values for ${JSON.stringify(fieldCandidatesChunk)}.`); + // Still continue the analysis even if chunks of p-value queries fail. + continue; + } - function pushHistogramDataLoadingState() { - push( - updateLoadingStateAction({ - ccsWarning: false, - loaded, - loadingState: i18n.translate( - 'xpack.aiops.explainLogRateSpikes.loadingState.loadingHistogramData', - { - defaultMessage: 'Loading histogram data.', - } - ), - }) - ); - } + if (pValues.length > 0) { + pValues.forEach((d) => { + fieldsToSample.add(d.fieldName); + }); + changePoints.push(...pValues); + } - if (groupingEnabled) { - logDebugMessage('Group results.'); + loaded += (1 / fieldCandidatesChunks.length) * PROGRESS_STEP_P_VALUES; + if (pValues.length > 0) { + push(addChangePointsAction(pValues)); + } + push( + updateLoadingStateAction({ + ccsWarning: false, + loaded, + loadingState: i18n.translate( + 'xpack.aiops.explainLogRateSpikes.loadingState.identifiedFieldValuePairs', + { + defaultMessage: + 'Identified {fieldValuePairsCount, plural, one {# significant field/value pair} other {# significant field/value pairs}}.', + values: { + fieldValuePairsCount: changePoints?.length ?? 0, + }, + } + ), + }) + ); - push( - updateLoadingStateAction({ - ccsWarning: false, - loaded, - loadingState: i18n.translate( - 'xpack.aiops.explainLogRateSpikes.loadingState.groupingResults', - { - defaultMessage: 'Transforming significant field/value pairs into groups.', - } - ), - }) - ); + if (shouldStop) { + logDebugMessage('shouldStop fetching p-values.'); - // To optimize the `frequent_items` query, we identify duplicate change points by count attributes. - // Note this is a compromise and not 100% accurate because there could be change points that - // have the exact same counts but still don't co-occur. - const duplicateIdentifier: Array = [ - 'doc_count', - 'bg_count', - 'total_doc_count', - 'total_bg_count', - ]; + end(); + return; + } + } + + if (changePoints?.length === 0) { + logDebugMessage('Stopping analysis, did not find change points.'); + endWithUpdatedLoadingState(); + return; + } - // These are the deduplicated change points we pass to the `frequent_items` aggregation. - const deduplicatedChangePoints = dropDuplicates(changePoints, duplicateIdentifier); + const histogramFields: [NumericHistogramField] = [ + { fieldName: request.body.timeFieldName, type: KBN_FIELD_TYPES.DATE }, + ]; - // We use the grouped change points to later repopulate - // the `frequent_items` result with the missing duplicates. - const groupedChangePoints = groupDuplicates(changePoints, duplicateIdentifier).filter( - (g) => g.group.length > 1 - ); + logDebugMessage('Fetch overall histogram.'); + let overallTimeSeries: NumericChartData | undefined; try { - const { fields, df } = await fetchFrequentItems( - client, - request.body.index, - JSON.parse(request.body.searchQuery) as estypes.QueryDslQueryContainer, - deduplicatedChangePoints, - request.body.timeFieldName, - request.body.deviationMin, - request.body.deviationMax, - logger, - pushError + overallTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + { match_all: {} }, + // fields + histogramFields, + // samplerShardSize + -1, + undefined + )) as [NumericChartData] + )[0]; + } catch (e) { + logger.error(`Failed to fetch the overall histogram data, got: \n${e.toString()}`); + pushError(`Failed to fetch overall histogram data.`); + // Still continue the analysis even if loading the overall histogram fails. + } + + function pushHistogramDataLoadingState() { + push( + updateLoadingStateAction({ + ccsWarning: false, + loaded, + loadingState: i18n.translate( + 'xpack.aiops.explainLogRateSpikes.loadingState.loadingHistogramData', + { + defaultMessage: 'Loading histogram data.', + } + ), + }) ); + } - if (fields.length > 0 && df.length > 0) { - // The way the `frequent_items` aggregations works could return item sets that include - // field/value pairs that are not part of the original list of significant change points. - // This cleans up groups and removes those unrelated field/value pairs. - const filteredDf = df - .map((fi) => { - fi.set = Object.entries(fi.set).reduce( - (set, [field, value]) => { - if ( - changePoints.some((cp) => cp.fieldName === field && cp.fieldValue === value) - ) { - set[field] = value; - } - return set; - }, - {} - ); - fi.size = Object.keys(fi.set).length; - return fi; - }) - .filter((fi) => fi.size > 1); - - // `frequent_items` returns lot of different small groups of field/value pairs that co-occur. - // The following steps analyse these small groups, identify overlap between these groups, - // and then summarize them in larger groups where possible. - - // Get a tree structure based on `frequent_items`. - const { root } = getSimpleHierarchicalTree(filteredDf, true, false, fields); - - // Each leave of the tree will be a summarized group of co-occuring field/value pairs. - const treeLeaves = getSimpleHierarchicalTreeLeaves(root, []); - - // To be able to display a more cleaned up results table in the UI, we identify field/value pairs - // that occur in multiple groups. This will allow us to highlight field/value pairs that are - // unique to a group in a better way. This step will also re-add duplicates we identified in the - // beginning and didn't pass on to the `frequent_items` agg. - const fieldValuePairCounts = getFieldValuePairCounts(treeLeaves); - const changePointGroups = markDuplicates(treeLeaves, fieldValuePairCounts).map( - (g) => { - const group = [...g.group]; - - for (const groupItem of g.group) { - const { duplicate } = groupItem; - const duplicates = groupedChangePoints.find((d) => - d.group.some( - (dg) => - dg.fieldName === groupItem.fieldName && - dg.fieldValue === groupItem.fieldValue - ) - ); + if (groupingEnabled) { + logDebugMessage('Group results.'); - if (duplicates !== undefined) { - group.push( - ...duplicates.group.map((d) => { - return { - fieldName: d.fieldName, - fieldValue: d.fieldValue, - duplicate, - }; - }) - ); - } + push( + updateLoadingStateAction({ + ccsWarning: false, + loaded, + loadingState: i18n.translate( + 'xpack.aiops.explainLogRateSpikes.loadingState.groupingResults', + { + defaultMessage: 'Transforming significant field/value pairs into groups.', } + ), + }) + ); - return { - ...g, - group, - }; - } - ); + // To optimize the `frequent_items` query, we identify duplicate change points by count attributes. + // Note this is a compromise and not 100% accurate because there could be change points that + // have the exact same counts but still don't co-occur. + const duplicateIdentifier: Array = [ + 'doc_count', + 'bg_count', + 'total_doc_count', + 'total_bg_count', + ]; + + // These are the deduplicated change points we pass to the `frequent_items` aggregation. + const deduplicatedChangePoints = dropDuplicates(changePoints, duplicateIdentifier); + + // We use the grouped change points to later repopulate + // the `frequent_items` result with the missing duplicates. + const groupedChangePoints = groupDuplicates(changePoints, duplicateIdentifier).filter( + (g) => g.group.length > 1 + ); - // Some field/value pairs might not be part of the `frequent_items` result set, for example - // because they don't co-occur with other field/value pairs or because of the limits we set on the query. - // In this next part we identify those missing pairs and add them as individual groups. - const missingChangePoints = deduplicatedChangePoints.filter((cp) => { - return !changePointGroups.some((cpg) => { - return cpg.group.some( - (d) => d.fieldName === cp.fieldName && d.fieldValue === cp.fieldValue - ); - }); - }); + try { + const { fields, df } = await fetchFrequentItems( + client, + request.body.index, + JSON.parse(request.body.searchQuery) as estypes.QueryDslQueryContainer, + deduplicatedChangePoints, + request.body.timeFieldName, + request.body.deviationMin, + request.body.deviationMax, + logger, + pushError + ); - changePointGroups.push( - ...missingChangePoints.map( - ({ fieldName, fieldValue, doc_count: docCount, pValue }) => { - const duplicates = groupedChangePoints.find((d) => - d.group.some( - (dg) => dg.fieldName === fieldName && dg.fieldValue === fieldValue - ) + if (fields.length > 0 && df.length > 0) { + // The way the `frequent_items` aggregations works could return item sets that include + // field/value pairs that are not part of the original list of significant change points. + // This cleans up groups and removes those unrelated field/value pairs. + const filteredDf = df + .map((fi) => { + fi.set = Object.entries(fi.set).reduce( + (set, [field, value]) => { + if ( + changePoints.some( + (cp) => cp.fieldName === field && cp.fieldValue === value + ) + ) { + set[field] = value; + } + return set; + }, + {} ); - if (duplicates !== undefined) { - return { - id: `${stringHash( - JSON.stringify( - duplicates.group.map((d) => ({ + fi.size = Object.keys(fi.set).length; + return fi; + }) + .filter((fi) => fi.size > 1); + + // `frequent_items` returns lot of different small groups of field/value pairs that co-occur. + // The following steps analyse these small groups, identify overlap between these groups, + // and then summarize them in larger groups where possible. + + // Get a tree structure based on `frequent_items`. + const { root } = getSimpleHierarchicalTree(filteredDf, true, false, fields); + + // Each leave of the tree will be a summarized group of co-occuring field/value pairs. + const treeLeaves = getSimpleHierarchicalTreeLeaves(root, []); + + // To be able to display a more cleaned up results table in the UI, we identify field/value pairs + // that occur in multiple groups. This will allow us to highlight field/value pairs that are + // unique to a group in a better way. This step will also re-add duplicates we identified in the + // beginning and didn't pass on to the `frequent_items` agg. + const fieldValuePairCounts = getFieldValuePairCounts(treeLeaves); + const changePointGroups = markDuplicates(treeLeaves, fieldValuePairCounts).map( + (g) => { + const group = [...g.group]; + + for (const groupItem of g.group) { + const { duplicate } = groupItem; + const duplicates = groupedChangePoints.find((d) => + d.group.some( + (dg) => + dg.fieldName === groupItem.fieldName && + dg.fieldValue === groupItem.fieldValue + ) + ); + + if (duplicates !== undefined) { + group.push( + ...duplicates.group.map((d) => { + return { fieldName: d.fieldName, fieldValue: d.fieldValue, - })) - ) - )}`, - group: duplicates.group.map((d) => ({ - fieldName: d.fieldName, - fieldValue: d.fieldValue, - duplicate: false, - })), - docCount, - pValue, - }; - } else { - return { - id: `${stringHash(JSON.stringify({ fieldName, fieldValue }))}`, - group: [ - { - fieldName, - fieldValue, - duplicate: false, - }, - ], - docCount, - pValue, - }; + duplicate, + }; + }) + ); + } } + + return { + ...g, + group, + }; } - ) - ); + ); - // Finally, we'll find out if there's at least one group with at least two items, - // only then will we return the groups to the clients and make the grouping option available. - const maxItems = Math.max(...changePointGroups.map((g) => g.group.length)); + // Some field/value pairs might not be part of the `frequent_items` result set, for example + // because they don't co-occur with other field/value pairs or because of the limits we set on the query. + // In this next part we identify those missing pairs and add them as individual groups. + const missingChangePoints = deduplicatedChangePoints.filter((cp) => { + return !changePointGroups.some((cpg) => { + return cpg.group.some( + (d) => d.fieldName === cp.fieldName && d.fieldValue === cp.fieldValue + ); + }); + }); - if (maxItems > 1) { - push(addChangePointsGroupAction(changePointGroups)); - } + changePointGroups.push( + ...missingChangePoints.map( + ({ fieldName, fieldValue, doc_count: docCount, pValue }) => { + const duplicates = groupedChangePoints.find((d) => + d.group.some( + (dg) => dg.fieldName === fieldName && dg.fieldValue === fieldValue + ) + ); + if (duplicates !== undefined) { + return { + id: `${stringHash( + JSON.stringify( + duplicates.group.map((d) => ({ + fieldName: d.fieldName, + fieldValue: d.fieldValue, + })) + ) + )}`, + group: duplicates.group.map((d) => ({ + fieldName: d.fieldName, + fieldValue: d.fieldValue, + duplicate: false, + })), + docCount, + pValue, + }; + } else { + return { + id: `${stringHash(JSON.stringify({ fieldName, fieldValue }))}`, + group: [ + { + fieldName, + fieldValue, + duplicate: false, + }, + ], + docCount, + pValue, + }; + } + } + ) + ); - loaded += PROGRESS_STEP_GROUPING; + // Finally, we'll find out if there's at least one group with at least two items, + // only then will we return the groups to the clients and make the grouping option available. + const maxItems = Math.max(...changePointGroups.map((g) => g.group.length)); - pushHistogramDataLoadingState(); + if (maxItems > 1) { + push(addChangePointsGroupAction(changePointGroups)); + } - logDebugMessage('Fetch group histograms.'); + loaded += PROGRESS_STEP_GROUPING; - await asyncForEach(changePointGroups, async (cpg) => { - if (overallTimeSeries !== undefined) { - const histogramQuery = { - bool: { - filter: cpg.group.map((d) => ({ - term: { [d.fieldName]: d.fieldValue }, - })), - }, - }; - - let cpgTimeSeries: NumericChartData; - try { - cpgTimeSeries = ( - (await fetchHistogramsForFields( - client, - request.body.index, - histogramQuery, - // fields - [ - { - fieldName: request.body.timeFieldName, - type: KBN_FIELD_TYPES.DATE, - interval: overallTimeSeries.interval, - min: overallTimeSeries.stats[0], - max: overallTimeSeries.stats[1], - }, - ], - // samplerShardSize - -1, - undefined - )) as [NumericChartData] - )[0]; - } catch (e) { - logger.error( - `Failed to fetch the histogram data for group #${ - cpg.id - }, got: \n${e.toString()}` + pushHistogramDataLoadingState(); + + logDebugMessage('Fetch group histograms.'); + + await asyncForEach(changePointGroups, async (cpg) => { + if (overallTimeSeries !== undefined) { + const histogramQuery = { + bool: { + filter: cpg.group.map((d) => ({ + term: { [d.fieldName]: d.fieldValue }, + })), + }, + }; + + let cpgTimeSeries: NumericChartData; + try { + cpgTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + histogramQuery, + // fields + [ + { + fieldName: request.body.timeFieldName, + type: KBN_FIELD_TYPES.DATE, + interval: overallTimeSeries.interval, + min: overallTimeSeries.stats[0], + max: overallTimeSeries.stats[1], + }, + ], + // samplerShardSize + -1, + undefined + )) as [NumericChartData] + )[0]; + } catch (e) { + logger.error( + `Failed to fetch the histogram data for group #${ + cpg.id + }, got: \n${e.toString()}` + ); + pushError(`Failed to fetch the histogram data for group #${cpg.id}.`); + return; + } + const histogram = + overallTimeSeries.data.map((o, i) => { + const current = cpgTimeSeries.data.find( + (d1) => d1.key_as_string === o.key_as_string + ) ?? { + doc_count: 0, + }; + return { + key: o.key, + key_as_string: o.key_as_string ?? '', + doc_count_change_point: current.doc_count, + doc_count_overall: Math.max(0, o.doc_count - current.doc_count), + }; + }) ?? []; + + push( + addChangePointsGroupHistogramAction([ + { + id: cpg.id, + histogram, + }, + ]) ); - pushError(`Failed to fetch the histogram data for group #${cpg.id}.`); - return; } - const histogram = - overallTimeSeries.data.map((o, i) => { - const current = cpgTimeSeries.data.find( - (d1) => d1.key_as_string === o.key_as_string - ) ?? { - doc_count: 0, - }; - return { - key: o.key, - key_as_string: o.key_as_string ?? '', - doc_count_change_point: current.doc_count, - doc_count_overall: Math.max(0, o.doc_count - current.doc_count), - }; - }) ?? []; - - push( - addChangePointsGroupHistogramAction([ - { - id: cpg.id, - histogram, - }, - ]) - ); - } - }); + }); + } + } catch (e) { + logger.error( + `Failed to transform field/value pairs into groups, got: \n${e.toString()}` + ); + pushError(`Failed to transform field/value pairs into groups.`); } - } catch (e) { - logger.error( - `Failed to transform field/value pairs into groups, got: \n${e.toString()}` - ); - pushError(`Failed to transform field/value pairs into groups.`); } - } - loaded += PROGRESS_STEP_HISTOGRAMS_GROUPS; + loaded += PROGRESS_STEP_HISTOGRAMS_GROUPS; - logDebugMessage('Fetch field/value histograms.'); + logDebugMessage('Fetch field/value histograms.'); - // time series filtered by fields - if (changePoints && overallTimeSeries !== undefined) { - await asyncForEach(changePoints, async (cp) => { - if (overallTimeSeries !== undefined) { - const histogramQuery = { - bool: { - filter: [ - { - term: { [cp.fieldName]: cp.fieldValue }, - }, - ], - }, - }; - - let cpTimeSeries: NumericChartData; - - try { - cpTimeSeries = ( - (await fetchHistogramsForFields( - client, - request.body.index, - histogramQuery, - // fields - [ + // time series filtered by fields + if (changePoints && overallTimeSeries !== undefined) { + await asyncForEach(changePoints, async (cp) => { + if (overallTimeSeries !== undefined) { + const histogramQuery = { + bool: { + filter: [ { - fieldName: request.body.timeFieldName, - type: KBN_FIELD_TYPES.DATE, - interval: overallTimeSeries.interval, - min: overallTimeSeries.stats[0], - max: overallTimeSeries.stats[1], + term: { [cp.fieldName]: cp.fieldValue }, }, ], - // samplerShardSize - -1, - undefined - )) as [NumericChartData] - )[0]; - } catch (e) { - logger.error( - `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${ - cp.fieldValue - }", got: \n${e.toString()}` - ); - pushError( - `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${cp.fieldValue}".` + }, + }; + + let cpTimeSeries: NumericChartData; + + try { + cpTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + histogramQuery, + // fields + [ + { + fieldName: request.body.timeFieldName, + type: KBN_FIELD_TYPES.DATE, + interval: overallTimeSeries.interval, + min: overallTimeSeries.stats[0], + max: overallTimeSeries.stats[1], + }, + ], + // samplerShardSize + -1, + undefined + )) as [NumericChartData] + )[0]; + } catch (e) { + logger.error( + `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${ + cp.fieldValue + }", got: \n${e.toString()}` + ); + pushError( + `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${cp.fieldValue}".` + ); + return; + } + + const histogram = + overallTimeSeries.data.map((o, i) => { + const current = cpTimeSeries.data.find( + (d1) => d1.key_as_string === o.key_as_string + ) ?? { + doc_count: 0, + }; + return { + key: o.key, + key_as_string: o.key_as_string ?? '', + doc_count_change_point: current.doc_count, + doc_count_overall: Math.max(0, o.doc_count - current.doc_count), + }; + }) ?? []; + + const { fieldName, fieldValue } = cp; + + loaded += (1 / changePoints.length) * PROGRESS_STEP_HISTOGRAMS; + pushHistogramDataLoadingState(); + push( + addChangePointsHistogramAction([ + { + fieldName, + fieldValue, + histogram, + }, + ]) ); - return; } + }); + } - const histogram = - overallTimeSeries.data.map((o, i) => { - const current = cpTimeSeries.data.find( - (d1) => d1.key_as_string === o.key_as_string - ) ?? { - doc_count: 0, - }; - return { - key: o.key, - key_as_string: o.key_as_string ?? '', - doc_count_change_point: current.doc_count, - doc_count_overall: Math.max(0, o.doc_count - current.doc_count), - }; - }) ?? []; - - const { fieldName, fieldValue } = cp; - - loaded += (1 / changePoints.length) * PROGRESS_STEP_HISTOGRAMS; - pushHistogramDataLoadingState(); - push( - addChangePointsHistogramAction([ - { - fieldName, - fieldValue, - histogram, - }, - ]) - ); - } - }); + endWithUpdatedLoadingState(); + } catch (e) { + logger.error(`Explain log rate spikes analysis failed to finish, got: \n${e.toString()}`); + pushError(`Explain log rate spikes analysis failed to finish.`); + end(); } - - endWithUpdatedLoadingState(); } // Do not call this using `await` so it will run asynchronously while we return the stream already. diff --git a/x-pack/plugins/apm/common/alert_types.ts b/x-pack/plugins/apm/common/rules/apm_rule_types.ts similarity index 96% rename from x-pack/plugins/apm/common/alert_types.ts rename to x-pack/plugins/apm/common/rules/apm_rule_types.ts index 1148854832a5c..b5a640b2d72af 100644 --- a/x-pack/plugins/apm/common/alert_types.ts +++ b/x-pack/plugins/apm/common/rules/apm_rule_types.ts @@ -14,11 +14,11 @@ import type { } from '@kbn/observability-plugin/common'; import type { ActionGroup } from '@kbn/alerting-plugin/common'; import { formatDurationFromTimeUnitChar } from '@kbn/observability-plugin/common'; -import { ANOMALY_SEVERITY, ANOMALY_THRESHOLD } from './ml_constants'; +import { ANOMALY_SEVERITY, ANOMALY_THRESHOLD } from '../ml_constants'; export const APM_SERVER_FEATURE_ID = 'apm'; -export enum AlertType { +export enum ApmRuleType { ErrorCount = 'apm.error_rate', // ErrorRate was renamed to ErrorCount but the key is kept as `error_rate` for backwards-compat. TransactionErrorRate = 'apm.transaction_error_rate', TransactionDuration = 'apm.transaction_duration', @@ -163,8 +163,8 @@ export function formatAnomalyReason({ ); } -export const ALERT_TYPES_CONFIG: Record< - AlertType, +export const RULE_TYPES_CONFIG: Record< + ApmRuleType, { name: string; actionGroups: Array>; @@ -174,7 +174,7 @@ export const ALERT_TYPES_CONFIG: Record< producer: string; } > = { - [AlertType.ErrorCount]: { + [ApmRuleType.ErrorCount]: { name: i18n.translate('xpack.apm.errorCountAlert.name', { defaultMessage: 'Error count threshold', }), @@ -184,7 +184,7 @@ export const ALERT_TYPES_CONFIG: Record< producer: APM_SERVER_FEATURE_ID, isExportable: true, }, - [AlertType.TransactionDuration]: { + [ApmRuleType.TransactionDuration]: { name: i18n.translate('xpack.apm.transactionDurationAlert.name', { defaultMessage: 'Latency threshold', }), @@ -194,7 +194,7 @@ export const ALERT_TYPES_CONFIG: Record< producer: APM_SERVER_FEATURE_ID, isExportable: true, }, - [AlertType.Anomaly]: { + [ApmRuleType.Anomaly]: { name: i18n.translate('xpack.apm.anomalyAlert.name', { defaultMessage: 'Anomaly', }), @@ -204,7 +204,7 @@ export const ALERT_TYPES_CONFIG: Record< producer: APM_SERVER_FEATURE_ID, isExportable: true, }, - [AlertType.TransactionErrorRate]: { + [ApmRuleType.TransactionErrorRate]: { name: i18n.translate('xpack.apm.transactionErrorRateAlert.name', { defaultMessage: 'Failed transaction rate threshold', }), diff --git a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/error_count_alert_trigger.stories.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.stories.tsx similarity index 88% rename from x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/error_count_alert_trigger.stories.tsx rename to x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.stories.tsx index fb4f777c1f19e..9c422df230e20 100644 --- a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/error_count_alert_trigger.stories.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.stories.tsx @@ -9,11 +9,10 @@ import { Meta, Story } from '@storybook/react'; import React, { useState } from 'react'; import { CoreStart } from '@kbn/core/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; -import { RuleParams, ErrorCountAlertTrigger } from '.'; -import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; - -import { AlertMetadata } from '../helper'; +import { RuleParams, ErrorCountRuleType } from '.'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; +import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; +import { AlertMetadata } from '../../utils/helper'; const coreMock = { http: { get: async () => ({}) }, @@ -29,8 +28,8 @@ interface Args { } const stories: Meta<{}> = { - title: 'alerting/ErrorCountAlertTrigger', - component: ErrorCountAlertTrigger, + title: 'alerting/ErrorCountRuleType', + component: ErrorCountRuleType, decorators: [ (StoryComponent) => { createCallApmApi(coreMock); @@ -58,7 +57,7 @@ export const CreatingInApmFromInventory: Story = ({ } return ( - = ({ } return ( - = ({ } return ( - = ({ } return ( - { +describe('ErrorCountRuleType', () => { it('renders', async () => { render(); diff --git a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx similarity index 79% rename from x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx rename to x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx index 053245a2b984e..218f35c85400f 100644 --- a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx @@ -11,14 +11,22 @@ import React, { useEffect } from 'react'; import { CoreStart } from '@kbn/core/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { ForLastExpression } from '@kbn/triggers-actions-ui-plugin/public'; -import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import { asInteger } from '../../../../common/utils/formatters'; -import { useFetcher } from '../../../hooks/use_fetcher'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; -import { ChartPreview } from '../chart_preview'; -import { EnvironmentField, IsAboveField, ServiceField } from '../fields'; -import { AlertMetadata, getIntervalAndTimeRange, TimeUnit } from '../helper'; -import { ServiceAlertTrigger } from '../service_alert_trigger'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; +import { asInteger } from '../../../../../common/utils/formatters'; +import { useFetcher } from '../../../../hooks/use_fetcher'; +import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; +import { ChartPreview } from '../../ui_components/chart_preview'; +import { + EnvironmentField, + IsAboveField, + ServiceField, +} from '../../utils/fields'; +import { + AlertMetadata, + getIntervalAndTimeRange, + TimeUnit, +} from '../../utils/helper'; +import { ApmRuleParamsContainer } from '../../ui_components/apm_rule_params_container'; export interface RuleParams { windowSize?: number; @@ -35,7 +43,7 @@ interface Props { setRuleProperty: (key: string, value: any) => void; } -export function ErrorCountAlertTrigger(props: Props) { +export function ErrorCountRuleType(props: Props) { const { services } = useKibana(); const { ruleParams, metadata, setRuleParams, setRuleProperty } = props; @@ -61,7 +69,7 @@ export function ErrorCountAlertTrigger(props: Props) { }); if (interval && start && end) { return callApmApi( - 'GET /internal/apm/alerts/chart_preview/transaction_error_count', + 'GET /internal/apm/rule_types/error_count/chart_preview', { params: { query: { @@ -95,7 +103,7 @@ export function ErrorCountAlertTrigger(props: Props) { />, setRuleParams('threshold', value || 0)} @@ -126,7 +134,7 @@ export function ErrorCountAlertTrigger(props: Props) { ); return ( - import('./error_count_alert_trigger')), + ruleParamsExpression: lazy(() => import('./error_count_rule_type')), validate: () => ({ errors: [], }), @@ -61,7 +61,7 @@ export function registerApmAlerts( }); observabilityRuleTypeRegistry.register({ - id: AlertType.TransactionDuration, + id: ApmRuleType.TransactionDuration, description: i18n.translate( 'xpack.apm.alertTypes.transactionDuration.description', { @@ -84,7 +84,7 @@ export function registerApmAlerts( return `${docLinks.links.alerting.apmRules}`; }, ruleParamsExpression: lazy( - () => import('./transaction_duration_alert_trigger') + () => import('./transaction_duration_rule_type') ), validate: () => ({ errors: [], @@ -105,7 +105,7 @@ export function registerApmAlerts( }); observabilityRuleTypeRegistry.register({ - id: AlertType.TransactionErrorRate, + id: ApmRuleType.TransactionErrorRate, description: i18n.translate( 'xpack.apm.alertTypes.transactionErrorRate.description', { @@ -126,7 +126,7 @@ export function registerApmAlerts( return `${docLinks.links.alerting.apmRules}`; }, ruleParamsExpression: lazy( - () => import('./transaction_error_rate_alert_trigger') + () => import('./transaction_error_rate_rule_type') ), validate: () => ({ errors: [], @@ -147,7 +147,7 @@ export function registerApmAlerts( }); observabilityRuleTypeRegistry.register({ - id: AlertType.Anomaly, + id: ApmRuleType.Anomaly, description: i18n.translate('xpack.apm.alertTypes.anomaly.description', { defaultMessage: 'Alert when either the latency, throughput, or failed transaction rate of a service is anomalous.', @@ -165,7 +165,7 @@ export function registerApmAlerts( return `${docLinks.links.alerting.apmRules}`; }, ruleParamsExpression: lazy( - () => import('./transaction_duration_anomaly_alert_trigger') + () => import('./transaction_duration_anomaly_rule_type') ), validate: () => ({ errors: [], diff --git a/x-pack/plugins/apm/public/components/alerting/transaction_duration_anomaly_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_anomaly_rule_type/index.tsx similarity index 79% rename from x-pack/plugins/apm/public/components/alerting/transaction_duration_anomaly_alert_trigger/index.tsx rename to x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_anomaly_rule_type/index.tsx index 6a580339e0268..85c1e5ddcde20 100644 --- a/x-pack/plugins/apm/public/components/alerting/transaction_duration_anomaly_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_anomaly_rule_type/index.tsx @@ -10,17 +10,17 @@ import { defaults, omit } from 'lodash'; import React, { useEffect } from 'react'; import { CoreStart } from '@kbn/core/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import { ANOMALY_SEVERITY } from '../../../../common/ml_constants'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; +import { ANOMALY_SEVERITY } from '../../../../../common/ml_constants'; +import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; import { EnvironmentField, ServiceField, TransactionTypeField, -} from '../fields'; -import { AlertMetadata } from '../helper'; -import { ServiceAlertTrigger } from '../service_alert_trigger'; -import { PopoverExpression } from '../service_alert_trigger/popover_expression'; +} from '../../utils/fields'; +import { AlertMetadata } from '../../utils/helper'; +import { ApmRuleParamsContainer } from '../../ui_components/apm_rule_params_container'; +import { PopoverExpression } from '../../ui_components/popover_expression'; import { AnomalySeverity, SelectAnomalySeverity, @@ -46,7 +46,7 @@ interface Props { setRuleProperty: (key: string, value: any) => void; } -export function TransactionDurationAnomalyAlertTrigger(props: Props) { +export function TransactionDurationAnomalyRuleType(props: Props) { const { services } = useKibana(); const { ruleParams, metadata, setRuleParams, setRuleProperty } = props; @@ -83,7 +83,7 @@ export function TransactionDurationAnomalyAlertTrigger(props: Props) { } title={i18n.translate( - 'xpack.apm.transactionDurationAnomalyAlertTrigger.anomalySeverity', + 'xpack.apm.transactionDurationAnomalyRuleType.anomalySeverity', { defaultMessage: 'Has anomaly with severity', } @@ -99,7 +99,7 @@ export function TransactionDurationAnomalyAlertTrigger(props: Props) { ]; return ( - {} } }, } as unknown as Partial); export default { - title: 'alerting/TransactionDurationAlertTrigger', - component: TransactionDurationAlertTrigger, + title: 'alerting/TransactionDurationRuleType', + component: TransactionDurationRuleType, decorators: [ (StoryComponent: ComponentType) => { return ( @@ -48,7 +48,7 @@ export const Example: Story = () => { } return ( - {}} diff --git a/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx similarity index 82% rename from x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx rename to x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx index 223437b8d5280..e211fea900522 100644 --- a/x-pack/plugins/apm/public/components/alerting/transaction_duration_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx @@ -12,25 +12,29 @@ import React, { useEffect } from 'react'; import { CoreStart } from '@kbn/core/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { ForLastExpression } from '@kbn/triggers-actions-ui-plugin/public'; -import { AggregationType } from '../../../../common/alert_types'; -import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import { getDurationFormatter } from '../../../../common/utils/formatters'; -import { useFetcher } from '../../../hooks/use_fetcher'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; +import { AggregationType } from '../../../../../common/rules/apm_rule_types'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; +import { getDurationFormatter } from '../../../../../common/utils/formatters'; +import { useFetcher } from '../../../../hooks/use_fetcher'; +import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; import { getMaxY, getResponseTimeTickFormatter, -} from '../../shared/charts/transaction_charts/helper'; -import { ChartPreview } from '../chart_preview'; +} from '../../../shared/charts/transaction_charts/helper'; +import { ChartPreview } from '../../ui_components/chart_preview'; import { EnvironmentField, IsAboveField, ServiceField, TransactionTypeField, -} from '../fields'; -import { AlertMetadata, getIntervalAndTimeRange, TimeUnit } from '../helper'; -import { ServiceAlertTrigger } from '../service_alert_trigger'; -import { PopoverExpression } from '../service_alert_trigger/popover_expression'; +} from '../../utils/fields'; +import { + AlertMetadata, + getIntervalAndTimeRange, + TimeUnit, +} from '../../utils/helper'; +import { ApmRuleParamsContainer } from '../../ui_components/apm_rule_params_container'; +import { PopoverExpression } from '../../ui_components/popover_expression'; export interface RuleParams { aggregationType: AggregationType; @@ -64,7 +68,7 @@ interface Props { setRuleProperty: (key: string, value: any) => void; } -export function TransactionDurationAlertTrigger(props: Props) { +export function TransactionDurationRuleType(props: Props) { const { services } = useKibana(); const { ruleParams, metadata, setRuleParams, setRuleProperty } = props; @@ -94,7 +98,7 @@ export function TransactionDurationAlertTrigger(props: Props) { }); if (interval && start && end) { return callApmApi( - 'GET /internal/apm/alerts/chart_preview/transaction_duration', + 'GET /internal/apm/rule_types/transaction_duration/chart_preview', { params: { query: { @@ -155,7 +159,7 @@ export function TransactionDurationAlertTrigger(props: Props) { />, @@ -173,7 +177,7 @@ export function TransactionDurationAlertTrigger(props: Props) { , setRuleParams('threshold', value || 0)} @@ -195,7 +199,7 @@ export function TransactionDurationAlertTrigger(props: Props) { ]; return ( - void; } -export function TransactionErrorRateAlertTrigger(props: Props) { +export function TransactionErrorRateRuleType(props: Props) { const { services } = useKibana(); const { ruleParams, metadata, setRuleParams, setRuleProperty } = props; @@ -68,7 +72,7 @@ export function TransactionErrorRateAlertTrigger(props: Props) { }); if (interval && start && end) { return callApmApi( - 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', + 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', { params: { query: { @@ -137,7 +141,7 @@ export function TransactionErrorRateAlertTrigger(props: Props) { ); return ( - >; - alertType: AlertType | null; + ruleType: ApmRuleType | null; } export function AlertingFlyout(props: Props) { - const { addFlyoutVisible, setAddFlyoutVisibility, alertType } = props; + const { addFlyoutVisible, setAddFlyoutVisibility, ruleType } = props; const serviceName = useServiceName(); const { query } = useApmParams('/*'); @@ -42,7 +42,7 @@ export function AlertingFlyout(props: Props) { 'transactionType' in query ? query.transactionType : undefined; const { services } = useKibana(); - const initialValues = getInitialAlertValues(alertType, serviceName); + const initialValues = getInitialAlertValues(ruleType, serviceName); const onCloseAddFlyout = useCallback( () => setAddFlyoutVisibility(false), @@ -51,24 +51,24 @@ export function AlertingFlyout(props: Props) { const addAlertFlyout = useMemo( () => - alertType && + ruleType && services.triggersActionsUi.getAddAlertFlyout({ consumer: APM_SERVER_FEATURE_ID, onClose: onCloseAddFlyout, - ruleTypeId: alertType, + ruleTypeId: ruleType, canChangeTrigger: false, initialValues, metadata: { environment, serviceName, - ...(alertType === AlertType.ErrorCount ? {} : { transactionType }), + ...(ruleType === ApmRuleType.ErrorCount ? {} : { transactionType }), start, end, } as AlertMetadata, }), /* eslint-disable-next-line react-hooks/exhaustive-deps */ [ - alertType, + ruleType, environment, onCloseAddFlyout, services.triggersActionsUi, diff --git a/x-pack/plugins/apm/public/components/alerting/service_alert_trigger/service_alert_trigger.test.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.test.tsx similarity index 86% rename from x-pack/plugins/apm/public/components/alerting/service_alert_trigger/service_alert_trigger.test.tsx rename to x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.test.tsx index a5c516f17546b..65dcc8a534241 100644 --- a/x-pack/plugins/apm/public/components/alerting/service_alert_trigger/service_alert_trigger.test.tsx +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.test.tsx @@ -8,17 +8,17 @@ import { render } from '@testing-library/react'; import React, { ReactNode } from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { ServiceAlertTrigger } from '.'; +import { ApmRuleParamsContainer } from '.'; function Wrapper({ children }: { children?: ReactNode }) { return {children}; } -describe('ServiceAlertTrigger', () => { +describe('ApmRuleParamsContainer', () => { it('renders', () => { expect(() => render( - {}} diff --git a/x-pack/plugins/apm/public/components/alerting/service_alert_trigger/index.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.tsx similarity index 95% rename from x-pack/plugins/apm/public/components/alerting/service_alert_trigger/index.tsx rename to x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.tsx index 48f97fc0f3fed..df252658e32c9 100644 --- a/x-pack/plugins/apm/public/components/alerting/service_alert_trigger/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.tsx @@ -16,7 +16,7 @@ interface Props { chartPreview?: React.ReactNode; } -export function ServiceAlertTrigger(props: Props) { +export function ApmRuleParamsContainer(props: Props) { const { fields, setRuleParams, defaults, chartPreview } = props; const params: Record = { diff --git a/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/index.tsx similarity index 94% rename from x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx rename to x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/index.tsx index 7f408d2e03986..21cee514fc363 100644 --- a/x-pack/plugins/apm/public/components/alerting/chart_preview/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/index.tsx @@ -22,9 +22,9 @@ import { import { EuiSpacer } from '@elastic/eui'; import React from 'react'; import { IUiSettingsClient } from '@kbn/core/public'; -import { Coordinate } from '../../../../typings/timeseries'; -import { useTheme } from '../../../hooks/use_theme'; -import { getTimeZone } from '../../shared/charts/helper/timezone'; +import { Coordinate } from '../../../../../typings/timeseries'; +import { useTheme } from '../../../../hooks/use_theme'; +import { getTimeZone } from '../../../shared/charts/helper/timezone'; interface ChartPreviewProps { yTickFormat?: TickFormatter; diff --git a/x-pack/plugins/apm/public/components/alerting/service_alert_trigger/popover_expression/index.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/popover_expression.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/alerting/service_alert_trigger/popover_expression/index.tsx rename to x-pack/plugins/apm/public/components/alerting/ui_components/popover_expression.tsx diff --git a/x-pack/plugins/apm/public/components/alerting/fields.test.tsx b/x-pack/plugins/apm/public/components/alerting/utils/fields.test.tsx similarity index 95% rename from x-pack/plugins/apm/public/components/alerting/fields.test.tsx rename to x-pack/plugins/apm/public/components/alerting/utils/fields.test.tsx index c8b0f1a348ff8..20b1d30f07891 100644 --- a/x-pack/plugins/apm/public/components/alerting/fields.test.tsx +++ b/x-pack/plugins/apm/public/components/alerting/utils/fields.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ServiceField, TransactionTypeField } from './fields'; import { render } from '@testing-library/react'; -import { expectTextsInDocument } from '../../utils/test_helpers'; +import { expectTextsInDocument } from '../../../utils/test_helpers'; describe('alerting fields', () => { describe('Service Field', () => { diff --git a/x-pack/plugins/apm/public/components/alerting/fields.tsx b/x-pack/plugins/apm/public/components/alerting/utils/fields.tsx similarity index 91% rename from x-pack/plugins/apm/public/components/alerting/fields.tsx rename to x-pack/plugins/apm/public/components/alerting/utils/fields.tsx index 4468cb2c40b0e..129c36e14102c 100644 --- a/x-pack/plugins/apm/public/components/alerting/fields.tsx +++ b/x-pack/plugins/apm/public/components/alerting/utils/fields.tsx @@ -12,14 +12,14 @@ import { SERVICE_ENVIRONMENT, SERVICE_NAME, TRANSACTION_TYPE, -} from '../../../common/elasticsearch_fieldnames'; +} from '../../../../common/elasticsearch_fieldnames'; import { ENVIRONMENT_ALL, getEnvironmentLabel, allOptionText, -} from '../../../common/environment_filter_values'; -import { SuggestionsSelect } from '../shared/suggestions_select'; -import { PopoverExpression } from './service_alert_trigger/popover_expression'; +} from '../../../../common/environment_filter_values'; +import { SuggestionsSelect } from '../../shared/suggestions_select'; +import { PopoverExpression } from '../ui_components/popover_expression'; export function ServiceField({ allowAll = true, @@ -143,10 +143,9 @@ export function IsAboveField({ return ( { diff --git a/x-pack/plugins/apm/public/components/alerting/get_alerting_capabilities.ts b/x-pack/plugins/apm/public/components/alerting/utils/get_alerting_capabilities.ts similarity index 93% rename from x-pack/plugins/apm/public/components/alerting/get_alerting_capabilities.ts rename to x-pack/plugins/apm/public/components/alerting/utils/get_alerting_capabilities.ts index 5af4d1b81a0d6..88492bba4ac6b 100644 --- a/x-pack/plugins/apm/public/components/alerting/get_alerting_capabilities.ts +++ b/x-pack/plugins/apm/public/components/alerting/utils/get_alerting_capabilities.ts @@ -6,7 +6,7 @@ */ import { Capabilities } from '@kbn/core/public'; -import { ApmPluginSetupDeps } from '../../plugin'; +import { ApmPluginSetupDeps } from '../../../plugin'; export const getAlertingCapabilities = ( plugins: ApmPluginSetupDeps, diff --git a/x-pack/plugins/apm/public/components/alerting/get_initial_alert_values.test.ts b/x-pack/plugins/apm/public/components/alerting/utils/get_initial_alert_values.test.ts similarity index 50% rename from x-pack/plugins/apm/public/components/alerting/get_initial_alert_values.test.ts rename to x-pack/plugins/apm/public/components/alerting/utils/get_initial_alert_values.test.ts index c6d4365c0690c..e590e66c2c7ee 100644 --- a/x-pack/plugins/apm/public/components/alerting/get_initial_alert_values.test.ts +++ b/x-pack/plugins/apm/public/components/alerting/utils/get_initial_alert_values.test.ts @@ -6,21 +6,24 @@ */ import { getInitialAlertValues } from './get_initial_alert_values'; -import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; +import { + ApmRuleType, + RULE_TYPES_CONFIG, +} from '../../../../common/rules/apm_rule_types'; -test('handles null alert type and undefined service name', () => { +test('handles null rule type and undefined service name', () => { expect(getInitialAlertValues(null, undefined)).toEqual({ tags: ['apm'] }); }); -test('handles valid alert type', () => { - const alertType = AlertType.ErrorCount; - expect(getInitialAlertValues(alertType, undefined)).toEqual({ - name: ALERT_TYPES_CONFIG[alertType].name, +test('handles valid rule type', () => { + const ruleType = ApmRuleType.ErrorCount; + expect(getInitialAlertValues(ruleType, undefined)).toEqual({ + name: RULE_TYPES_CONFIG[ruleType].name, tags: ['apm'], }); - expect(getInitialAlertValues(alertType, 'Service Name')).toEqual({ - name: `${ALERT_TYPES_CONFIG[alertType].name} | Service Name`, + expect(getInitialAlertValues(ruleType, 'Service Name')).toEqual({ + name: `${RULE_TYPES_CONFIG[ruleType].name} | Service Name`, tags: ['apm', `service.name:service name`], }); }); diff --git a/x-pack/plugins/apm/public/components/alerting/get_initial_alert_values.ts b/x-pack/plugins/apm/public/components/alerting/utils/get_initial_alert_values.ts similarity index 64% rename from x-pack/plugins/apm/public/components/alerting/get_initial_alert_values.ts rename to x-pack/plugins/apm/public/components/alerting/utils/get_initial_alert_values.ts index bd878b2bcb288..452a4561f34e1 100644 --- a/x-pack/plugins/apm/public/components/alerting/get_initial_alert_values.ts +++ b/x-pack/plugins/apm/public/components/alerting/utils/get_initial_alert_values.ts @@ -5,19 +5,20 @@ * 2.0. */ -import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; +import { + ApmRuleType, + RULE_TYPES_CONFIG, +} from '../../../../common/rules/apm_rule_types'; export function getInitialAlertValues( - alertType: AlertType | null, + ruleType: ApmRuleType | null, serviceName: string | undefined ) { - const alertTypeName = alertType - ? ALERT_TYPES_CONFIG[alertType].name - : undefined; - const alertName = alertTypeName + const ruleTypeName = ruleType ? RULE_TYPES_CONFIG[ruleType].name : undefined; + const alertName = ruleTypeName ? serviceName - ? `${alertTypeName} | ${serviceName}` - : alertTypeName + ? `${ruleTypeName} | ${serviceName}` + : ruleTypeName : undefined; const tags = ['apm']; if (serviceName) { diff --git a/x-pack/plugins/apm/public/components/alerting/helper.ts b/x-pack/plugins/apm/public/components/alerting/utils/helper.ts similarity index 100% rename from x-pack/plugins/apm/public/components/alerting/helper.ts rename to x-pack/plugins/apm/public/components/alerting/utils/helper.ts diff --git a/x-pack/plugins/apm/public/components/alerting/service_overview_alerts/alerts_table_status_filter.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/alerts_table_status_filter.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/alerting/service_overview_alerts/alerts_table_status_filter.tsx rename to x-pack/plugins/apm/public/components/app/alerts_overview/alerts_table_status_filter.tsx diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/alerts_overview_table.test.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/index.test.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/app/alerts_overview/alerts_overview_table.test.tsx rename to x-pack/plugins/apm/public/components/app/alerts_overview/index.test.tsx diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx index 5c9eeca45bee8..01a5ed8ada073 100644 --- a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx @@ -18,7 +18,7 @@ import { AlertsTableStatusFilter, ALL_ALERTS_FILTER, AlertStatusFilterButton, -} from '../../alerting/service_overview_alerts/alerts_table_status_filter'; +} from './alerts_table_status_filter'; export function AlertsOverview() { const { diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx index 94c0e90c1b44c..bfd5b0c21ee8b 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx @@ -5,31 +5,17 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiPanel } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import React from 'react'; -import { - isRumAgentName, - isMobileAgentName, - isServerlessAgent, -} from '../../../../common/agent_name'; +import { EuiFlexGroupProps } from '@elastic/eui'; +import { isMobileAgentName } from '../../../../common/agent_name'; import { AnnotationsContextProvider } from '../../../context/annotations/annotations_context'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context'; import { useBreakpoints } from '../../../hooks/use_breakpoints'; -import { LatencyChart } from '../../shared/charts/latency_chart'; -import { TransactionBreakdownChart } from '../../shared/charts/transaction_breakdown_chart'; -import { TransactionColdstartRateChart } from '../../shared/charts/transaction_coldstart_rate_chart'; -import { FailedTransactionRateChart } from '../../shared/charts/failed_transaction_rate_chart'; -import { ServiceOverviewDependenciesTable } from './service_overview_dependencies_table'; -import { ServiceOverviewErrorsTable } from './service_overview_errors_table'; -import { ServiceOverviewInstancesChartAndTable } from './service_overview_instances_chart_and_table'; -import { ServiceOverviewThroughputChart } from './service_overview_throughput_chart'; -import { TransactionsTable } from '../../shared/transactions_table'; import { useApmParams } from '../../../hooks/use_apm_params'; -import { AggregatedTransactionsBadge } from '../../shared/aggregated_transactions_badge'; -import { useApmRouter } from '../../../hooks/use_apm_router'; import { useTimeRange } from '../../../hooks/use_time_range'; +import { ServiceOverviewCharts } from './service_overview_charts/service_overview_charts'; +import { ServiceOverviewMobileCharts } from './service_overview_charts/service_oveview_mobile_charts'; /** * The height a chart should be if it's next to a table with 5 rows and a title. @@ -38,36 +24,35 @@ import { useTimeRange } from '../../../hooks/use_time_range'; export const chartHeight = 288; export function ServiceOverview() { - const { agentName, serviceName, fallbackToTransactions, runtimeName } = - useApmServiceContext(); + const { agentName, serviceName } = useApmServiceContext(); const { - query, - query: { environment, kuery, rangeFrom, rangeTo }, + query: { environment, rangeFrom, rangeTo }, } = useApmParams('/services/{serviceName}/overview'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - const latencyChartHeight = 200; - // The default EuiFlexGroup breaks at 768, but we want to break at 1200, so we // observe the window width and set the flex directions of rows accordingly const { isLarge } = useBreakpoints(); const isSingleColumn = isLarge; + + const latencyChartHeight = 200; const nonLatencyChartHeight = isSingleColumn ? latencyChartHeight : chartHeight; - const rowDirection = isSingleColumn ? 'column' : 'row'; - const isRumAgent = isRumAgentName(agentName); + const rowDirection: EuiFlexGroupProps['direction'] = isSingleColumn + ? 'column' + : 'row'; + const isMobileAgent = isMobileAgentName(agentName); - const isServerless = isServerlessAgent(runtimeName); - const router = useApmRouter(); - const dependenciesLink = router.link('/services/{serviceName}/dependencies', { - path: { - serviceName, - }, - query, - }); + + const serviceOverviewProps = { + latencyChartHeight, + rowDirection, + nonLatencyChartHeight, + isSingleColumn, + }; return ( - - {fallbackToTransactions && ( - - - - )} - - - - - - - - - - - - - - - - - - - - {!isRumAgent && ( - - - - )} - - - - - - - - - - {isServerless ? ( - - - - ) : ( - - - - )} - {!isRumAgent && ( - - - - {i18n.translate( - 'xpack.apm.serviceOverview.dependenciesTableTabLink', - { defaultMessage: 'View dependencies' } - )} - - } - /> - - - )} - - - {!isRumAgent && !isMobileAgent && !isServerless && ( - - - - - - )} - + {isMobileAgent ? ( + + ) : ( + + )} ); diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_charts/service_overview_charts.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_charts/service_overview_charts.tsx new file mode 100644 index 0000000000000..802fc161cefd8 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_charts/service_overview_charts.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useApmRouter } from '../../../../hooks/use_apm_router'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { LatencyChart } from '../../../shared/charts/latency_chart'; +import { TransactionBreakdownChart } from '../../../shared/charts/transaction_breakdown_chart'; +import { TransactionColdstartRateChart } from '../../../shared/charts/transaction_coldstart_rate_chart'; +import { FailedTransactionRateChart } from '../../../shared/charts/failed_transaction_rate_chart'; +import { ServiceOverviewDependenciesTable } from '../service_overview_dependencies_table'; +import { ServiceOverviewErrorsTable } from '../service_overview_errors_table'; +import { ServiceOverviewInstancesChartAndTable } from '../service_overview_instances_chart_and_table'; +import { ServiceOverviewThroughputChart } from '../service_overview_throughput_chart'; +import { TransactionsTable } from '../../../shared/transactions_table'; +import { AggregatedTransactionsBadge } from '../../../shared/aggregated_transactions_badge'; +import { + isRumAgentName, + isServerlessAgent, +} from '../../../../../common/agent_name'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useTimeRange } from '../../../../hooks/use_time_range'; + +interface Props { + latencyChartHeight: number; + rowDirection: 'column' | 'row'; + nonLatencyChartHeight: number; + isSingleColumn: boolean; +} + +export function ServiceOverviewCharts({ + latencyChartHeight, + rowDirection, + nonLatencyChartHeight, + isSingleColumn, +}: Props) { + const router = useApmRouter(); + const { agentName, serviceName, fallbackToTransactions, runtimeName } = + useApmServiceContext(); + + const { + query, + query: { environment, kuery, rangeFrom, rangeTo }, + } = useApmParams('/services/{serviceName}/overview'); + + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + const isRumAgent = isRumAgentName(agentName); + const isServerless = isServerlessAgent(runtimeName); + + const dependenciesLink = router.link('/services/{serviceName}/dependencies', { + path: { + serviceName, + }, + query, + }); + + return ( + + {fallbackToTransactions && ( + + + + )} + + + + + + + + + + + + + + + + + + + + {!isRumAgent && ( + + + + )} + + + + + + + + + + {isServerless ? ( + + + + ) : ( + + + + )} + {!isRumAgent && ( + + + + {i18n.translate( + 'xpack.apm.serviceOverview.dependenciesTableTabLink', + { defaultMessage: 'View dependencies' } + )} + + } + /> + + + )} + + + {!isRumAgent && !isServerless && ( + + + + + + )} + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_charts/service_oveview_mobile_charts.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_charts/service_oveview_mobile_charts.tsx new file mode 100644 index 0000000000000..4dd20ca8a0d94 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_charts/service_oveview_mobile_charts.tsx @@ -0,0 +1,126 @@ +/* + * 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 React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useApmRouter } from '../../../../hooks/use_apm_router'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { LatencyChart } from '../../../shared/charts/latency_chart'; +import { FailedTransactionRateChart } from '../../../shared/charts/failed_transaction_rate_chart'; +import { ServiceOverviewDependenciesTable } from '../service_overview_dependencies_table'; +import { ServiceOverviewThroughputChart } from '../service_overview_throughput_chart'; +import { TransactionsTable } from '../../../shared/transactions_table'; +import { AggregatedTransactionsBadge } from '../../../shared/aggregated_transactions_badge'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useTimeRange } from '../../../../hooks/use_time_range'; + +interface Props { + latencyChartHeight: number; + rowDirection: 'column' | 'row'; + nonLatencyChartHeight: number; + isSingleColumn: boolean; +} + +export function ServiceOverviewMobileCharts({ + latencyChartHeight, + rowDirection, + nonLatencyChartHeight, + isSingleColumn, +}: Props) { + const { fallbackToTransactions, serviceName } = useApmServiceContext(); + const router = useApmRouter(); + + const { + query, + query: { environment, kuery, rangeFrom, rangeTo }, + } = useApmParams('/services/{serviceName}/overview'); + + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + const dependenciesLink = router.link('/services/{serviceName}/dependencies', { + path: { + serviceName, + }, + query, + }); + + return ( + + {fallbackToTransactions && ( + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + {i18n.translate( + 'xpack.apm.serviceOverview.dependenciesTableTabLink', + { defaultMessage: 'View dependencies' } + )} + + } + /> + + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx b/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx index 9b62ae8e6da89..782197828b098 100644 --- a/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx +++ b/x-pack/plugins/apm/public/components/app/trace_explorer/trace_search_box/index.tsx @@ -58,7 +58,7 @@ export function TraceSearchBox({ error, loading, }: Props) { - const { unifiedSearch, core, data } = useApmPluginContext(); + const { unifiedSearch, core, data, dataViews } = useApmPluginContext(); const { notifications, http, docLinks, uiSettings } = core; const { services: { storage }, @@ -153,6 +153,7 @@ export function TraceSearchBox({ docLinks, uiSettings, data, + dataViews, storage, }} /> diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx index 255cacd0ce2c5..41d6b2c7bf96a 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx @@ -18,7 +18,11 @@ import { AggregatedTransactionsBadge } from '../../shared/aggregated_transaction import { TransactionCharts } from '../../shared/charts/transaction_charts'; import { replace } from '../../shared/links/url_helpers'; import { TransactionDetailsTabs } from './transaction_details_tabs'; -import { isServerlessAgent } from '../../../../common/agent_name'; +import { + isMobileAgentName, + isServerlessAgent, +} from '../../../../common/agent_name'; +import { MobileTransactionCharts } from '../../shared/charts/transaction_charts/mobile_transaction_charts'; export function TransactionDetails() { const { path, query } = useApmParams( @@ -34,7 +38,7 @@ export function TransactionDetails() { } = query; const { start, end } = useTimeRange({ rangeFrom, rangeTo }); const apmRouter = useApmRouter(); - const { transactionType, fallbackToTransactions, runtimeName } = + const { transactionType, fallbackToTransactions, runtimeName, agentName } = useApmServiceContext(); const history = useHistory(); @@ -56,6 +60,7 @@ export function TransactionDetails() { ); const isServerless = isServerlessAgent(runtimeName); + const isMobileAgent = isMobileAgentName(agentName); return ( <> @@ -69,16 +74,25 @@ export function TransactionDetails() { - + {isMobileAgent ? ( + + ) : ( + + )} diff --git a/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx index adb89867d743e..d0355b201e858 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx @@ -15,7 +15,11 @@ import { AggregatedTransactionsBadge } from '../../shared/aggregated_transaction import { TransactionCharts } from '../../shared/charts/transaction_charts'; import { replace } from '../../shared/links/url_helpers'; import { TransactionsTable } from '../../shared/transactions_table'; -import { isServerlessAgent } from '../../../../common/agent_name'; +import { + isMobileAgentName, + isServerlessAgent, +} from '../../../../common/agent_name'; +import { MobileTransactionCharts } from '../../shared/charts/transaction_charts/mobile_transaction_charts'; export function TransactionOverview() { const { @@ -32,8 +36,13 @@ export function TransactionOverview() { const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - const { transactionType, serviceName, fallbackToTransactions, runtimeName } = - useApmServiceContext(); + const { + transactionType, + serviceName, + fallbackToTransactions, + runtimeName, + agentName, + } = useApmServiceContext(); const history = useHistory(); @@ -49,6 +58,7 @@ export function TransactionOverview() { } const isServerless = isServerlessAgent(runtimeName); + const isMobileAgent = isMobileAgentName(agentName); return ( <> @@ -62,15 +72,24 @@ export function TransactionOverview() { )} - + {isMobileAgent ? ( + + ) : ( + + )} (null); + const [ruleType, setRuleType] = useState(null); const { plugins: { observability }, } = useApmPluginContext(); @@ -92,7 +92,7 @@ export function AlertingPopoverAndFlyout({ { name: createAnomalyAlertAlertLabel, onClick: () => { - setAlertType(AlertType.Anomaly); + setRuleType(ApmRuleType.Anomaly); setPopoverOpen(false); }, 'data-test-subj': 'apmAlertsMenuItemCreateAnomaly', @@ -102,7 +102,7 @@ export function AlertingPopoverAndFlyout({ { name: errorCountLabel, onClick: () => { - setAlertType(AlertType.ErrorCount); + setRuleType(ApmRuleType.ErrorCount); setPopoverOpen(false); }, 'data-test-subj': 'apmAlertsMenuItemErrorCount', @@ -136,7 +136,7 @@ export function AlertingPopoverAndFlyout({ { name: transactionDurationLabel, onClick: () => { - setAlertType(AlertType.TransactionDuration); + setRuleType(ApmRuleType.TransactionDuration); setPopoverOpen(false); }, }, @@ -147,7 +147,7 @@ export function AlertingPopoverAndFlyout({ { name: transactionErrorRateLabel, onClick: () => { - setAlertType(AlertType.TransactionErrorRate); + setRuleType(ApmRuleType.TransactionErrorRate); setPopoverOpen(false); }, }, @@ -168,11 +168,11 @@ export function AlertingPopoverAndFlyout({ { if (!visible) { - setAlertType(null); + setRuleType(null); } }} /> diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx index c41e1f30df470..db5ab8786c23b 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx @@ -14,7 +14,7 @@ import { import { apmLabsButton } from '@kbn/observability-plugin/common'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { getAlertingCapabilities } from '../../alerting/get_alerting_capabilities'; +import { getAlertingCapabilities } from '../../alerting/utils/get_alerting_capabilities'; import { getLegacyApmHref } from '../links/apm/apm_link'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { AlertingPopoverAndFlyout } from './alerting_popover_flyout'; diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/mobile_transaction_charts.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/mobile_transaction_charts.tsx new file mode 100644 index 0000000000000..67d713eea2b0a --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/mobile_transaction_charts.tsx @@ -0,0 +1,55 @@ +/* + * 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 { EuiFlexGrid, EuiFlexItem, EuiPanel } from '@elastic/eui'; +import React from 'react'; +import { AnnotationsContextProvider } from '../../../../context/annotations/annotations_context'; +import { ChartPointerEventContextProvider } from '../../../../context/chart_pointer_event/chart_pointer_event_context'; +import { ServiceOverviewThroughputChart } from '../../../app/service_overview/service_overview_throughput_chart'; +import { LatencyChart } from '../latency_chart'; +import { FailedTransactionRateChart } from '../failed_transaction_rate_chart'; + +export function MobileTransactionCharts({ + kuery, + environment, + start, + end, + transactionName, +}: { + kuery: string; + environment: string; + start: string; + end: string; + transactionName?: string; +}) { + return ( + + + + + + + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index 0ae44172f7ebb..18dcba1468780 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -51,7 +51,7 @@ import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { enableServiceGroups } from '@kbn/observability-plugin/public'; import { InfraClientStartExports } from '@kbn/infra-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { registerApmAlerts } from './components/alerting/register_apm_alerts'; +import { registerApmRuleTypes } from './components/alerting/rule_types/register_apm_rule_types'; import { getApmEnrollmentFlyoutData, LazyApmCustomAssetsExtension, @@ -345,7 +345,7 @@ export class ApmPlugin implements Plugin { }, }); - registerApmAlerts(observabilityRuleTypeRegistry); + registerApmRuleTypes(observabilityRuleTypeRegistry); const locator = plugins.share.url.locators.create( new APMServiceDetailLocator(core.uiSettings) diff --git a/x-pack/plugins/apm/server/feature.ts b/x-pack/plugins/apm/server/feature.ts index adf1759312449..d2197df318571 100644 --- a/x-pack/plugins/apm/server/feature.ts +++ b/x-pack/plugins/apm/server/feature.ts @@ -12,7 +12,10 @@ import { LicensingPluginSetup, LicensingApiRequestHandlerContext, } from '@kbn/licensing-plugin/server'; -import { AlertType, APM_SERVER_FEATURE_ID } from '../common/alert_types'; +import { + ApmRuleType, + APM_SERVER_FEATURE_ID, +} from '../common/rules/apm_rule_types'; export const APM_FEATURE = { id: APM_SERVER_FEATURE_ID, @@ -26,7 +29,7 @@ export const APM_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: Object.values(AlertType), + alerting: Object.values(ApmRuleType), // see x-pack/plugins/features/common/feature_kibana_privileges.ts privileges: { all: { @@ -39,10 +42,10 @@ export const APM_FEATURE = { }, alerting: { alert: { - all: Object.values(AlertType), + all: Object.values(ApmRuleType), }, rule: { - all: Object.values(AlertType), + all: Object.values(ApmRuleType), }, }, management: { @@ -60,10 +63,10 @@ export const APM_FEATURE = { }, alerting: { alert: { - read: Object.values(AlertType), + read: Object.values(ApmRuleType), }, rule: { - read: Object.values(AlertType), + read: Object.values(ApmRuleType), }, }, management: { diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index 6071c455ad84e..85fb7efc53702 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -116,7 +116,7 @@ export type ApmIndicesConfigName = keyof APMConfig['indices']; export const plugin = (initContext: PluginInitializerContext) => new APMPlugin(initContext); -export { APM_SERVER_FEATURE_ID } from '../common/alert_types'; +export { APM_SERVER_FEATURE_ID } from '../common/rules/apm_rule_types'; export { APMPlugin } from './plugin'; export type { APMPluginSetup } from './types'; export type { diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 37a0d0e69a782..de49cc793ede4 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -21,7 +21,7 @@ import { Dataset } from '@kbn/rule-registry-plugin/server'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { APMConfig, APM_SERVER_FEATURE_ID } from '.'; import { APM_FEATURE, registerFeaturesUsage } from './feature'; -import { registerApmAlerts } from './routes/alerts/register_apm_alerts'; +import { registerApmRuleTypes } from './routes/alerts/register_apm_rule_types'; import { registerFleetPolicyCallbacks } from './routes/fleet/register_fleet_policy_callbacks'; import { createApmTelemetry } from './lib/apm_telemetry'; import { APMEventClient } from './lib/helpers/create_es_client/create_apm_event_client'; @@ -189,7 +189,7 @@ export class APMPlugin }); if (plugins.alerting) { - registerApmAlerts({ + registerApmRuleTypes({ ruleDataClient, alerting: plugins.alerting, ml: plugins.ml, diff --git a/x-pack/plugins/apm/server/routes/alerts/average_or_percentile_agg.ts b/x-pack/plugins/apm/server/routes/alerts/average_or_percentile_agg.ts index 7c018f8ff37c6..0a7b9e29229bb 100644 --- a/x-pack/plugins/apm/server/routes/alerts/average_or_percentile_agg.ts +++ b/x-pack/plugins/apm/server/routes/alerts/average_or_percentile_agg.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { AggregationType } from '../../../common/alert_types'; +import { AggregationType } from '../../../common/rules/apm_rule_types'; import { getDurationFieldForTransactions } from '../../lib/helpers/transactions'; type TransactionDurationField = ReturnType< diff --git a/x-pack/plugins/apm/server/routes/alerts/register_apm_alerts.ts b/x-pack/plugins/apm/server/routes/alerts/register_apm_rule_types.ts similarity index 53% rename from x-pack/plugins/apm/server/routes/alerts/register_apm_alerts.ts rename to x-pack/plugins/apm/server/routes/alerts/register_apm_rule_types.ts index e6fcba2555ada..e327970198f80 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_apm_alerts.ts +++ b/x-pack/plugins/apm/server/routes/alerts/register_apm_rule_types.ts @@ -10,11 +10,11 @@ import { IBasePath, Logger } from '@kbn/core/server'; import { PluginSetupContract as AlertingPluginSetupContract } from '@kbn/alerting-plugin/server'; import { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; -import { registerTransactionDurationAlertType } from './register_transaction_duration_alert_type'; -import { registerAnomalyAlertType } from './register_anomaly_alert_type'; -import { registerErrorCountAlertType } from './register_error_count_alert_type'; +import { registerTransactionDurationRuleType } from './rule_types/transaction_duration/register_transaction_duration_rule_type'; +import { registerAnomalyRuleType } from './rule_types/anomaly/register_anomaly_rule_type'; +import { registerErrorCountRuleType } from './rule_types/error_count/register_error_count_rule_type'; import { APMConfig } from '../..'; -import { registerTransactionErrorRateAlertType } from './register_transaction_error_rate_alert_type'; +import { registerTransactionErrorRateRuleType } from './rule_types/transaction_error_rate/register_transaction_error_rate_rule_type'; export interface RegisterRuleDependencies { ruleDataClient: IRuleDataClient; @@ -25,9 +25,9 @@ export interface RegisterRuleDependencies { basePath: IBasePath; } -export function registerApmAlerts(dependencies: RegisterRuleDependencies) { - registerTransactionDurationAlertType(dependencies); - registerAnomalyAlertType(dependencies); - registerErrorCountAlertType(dependencies); - registerTransactionErrorRateAlertType(dependencies); +export function registerApmRuleTypes(dependencies: RegisterRuleDependencies) { + registerTransactionDurationRuleType(dependencies); + registerAnomalyRuleType(dependencies); + registerErrorCountRuleType(dependencies); + registerTransactionErrorRateRuleType(dependencies); } diff --git a/x-pack/plugins/apm/server/routes/alerts/route.ts b/x-pack/plugins/apm/server/routes/alerts/route.ts index 2ba7913067400..56e23d2712868 100644 --- a/x-pack/plugins/apm/server/routes/alerts/route.ts +++ b/x-pack/plugins/apm/server/routes/alerts/route.ts @@ -6,13 +6,13 @@ */ import * as t from 'io-ts'; -import { getTransactionDurationChartPreview } from './chart_preview/get_transaction_duration'; -import { getTransactionErrorCountChartPreview } from './chart_preview/get_transaction_error_count'; -import { getTransactionErrorRateChartPreview } from './chart_preview/get_transaction_error_rate'; +import { getTransactionDurationChartPreview } from './rule_types/transaction_duration/get_transaction_duration_chart_preview'; +import { getTransactionErrorCountChartPreview } from './rule_types/error_count/get_error_count_chart_preview'; +import { getTransactionErrorRateChartPreview } from './rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview'; import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, rangeRt } from '../default_api_types'; -import { AggregationType } from '../../../common/alert_types'; +import { AggregationType } from '../../../common/rules/apm_rule_types'; const alertParamsRt = t.intersection([ t.partial({ @@ -34,7 +34,7 @@ const alertParamsRt = t.intersection([ export type AlertParams = t.TypeOf; const transactionErrorRateChartPreview = createApmServerRoute({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', params: t.type({ query: alertParamsRt }), options: { tags: ['access:apm'] }, handler: async ( @@ -54,7 +54,7 @@ const transactionErrorRateChartPreview = createApmServerRoute({ }); const transactionErrorCountChartPreview = createApmServerRoute({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_count', + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', params: t.type({ query: alertParamsRt }), options: { tags: ['access:apm'] }, handler: async ( @@ -75,7 +75,7 @@ const transactionErrorCountChartPreview = createApmServerRoute({ }); const transactionDurationChartPreview = createApmServerRoute({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_duration', + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', params: t.type({ query: alertParamsRt }), options: { tags: ['access:apm'] }, handler: async ( diff --git a/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.test.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/anomaly/register_anomaly_rule_type.test.ts similarity index 92% rename from x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.test.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/anomaly/register_anomaly_rule_type.test.ts index 9aa99572141d5..875dce26c40fc 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.test.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/anomaly/register_anomaly_rule_type.test.ts @@ -4,12 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { registerAnomalyAlertType } from './register_anomaly_alert_type'; -import { ANOMALY_SEVERITY } from '../../../common/ml_constants'; +import { registerAnomalyRuleType } from './register_anomaly_rule_type'; +import { ANOMALY_SEVERITY } from '../../../../../common/ml_constants'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; -import * as GetServiceAnomalies from '../service_map/get_service_anomalies'; -import { createRuleTypeMocks } from './test_utils'; -import { ApmMlJob } from '../../../common/anomaly_detection/apm_ml_job'; +import * as GetServiceAnomalies from '../../../service_map/get_service_anomalies'; +import { createRuleTypeMocks } from '../../test_utils'; +import { ApmMlJob } from '../../../../../common/anomaly_detection/apm_ml_job'; describe('Transaction duration anomaly alert', () => { afterEach(() => { @@ -19,7 +19,7 @@ describe('Transaction duration anomaly alert', () => { it('ml is not defined', async () => { const { services, dependencies, executor } = createRuleTypeMocks(); - registerAnomalyAlertType({ + registerAnomalyRuleType({ ...dependencies, ml: undefined, }); @@ -47,7 +47,7 @@ describe('Transaction duration anomaly alert', () => { anomalyDetectorsProvider: jest.fn(), } as unknown as MlPluginSetup; - registerAnomalyAlertType({ + registerAnomalyRuleType({ ...dependencies, ml, }); @@ -98,7 +98,7 @@ describe('Transaction duration anomaly alert', () => { anomalyDetectorsProvider: jest.fn(), } as unknown as MlPluginSetup; - registerAnomalyAlertType({ + registerAnomalyRuleType({ ...dependencies, ml, }); @@ -174,7 +174,7 @@ describe('Transaction duration anomaly alert', () => { anomalyDetectorsProvider: jest.fn(), } as unknown as MlPluginSetup; - registerAnomalyAlertType({ + registerAnomalyRuleType({ ...dependencies, ml, }); diff --git a/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/anomaly/register_anomaly_rule_type.ts similarity index 86% rename from x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/anomaly/register_anomaly_rule_type.ts index 9a00a8f3712b6..13d0f3311f186 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_anomaly_alert_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/anomaly/register_anomaly_rule_type.ts @@ -20,32 +20,32 @@ import { termQuery } from '@kbn/observability-plugin/server'; import { createLifecycleRuleTypeFactory } from '@kbn/rule-registry-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { - AlertType, - ALERT_TYPES_CONFIG, + ApmRuleType, + RULE_TYPES_CONFIG, ANOMALY_ALERT_SEVERITY_TYPES, formatAnomalyReason, -} from '../../../common/alert_types'; -import { getSeverity } from '../../../common/anomaly_detection'; +} from '../../../../../common/rules/apm_rule_types'; +import { getSeverity } from '../../../../../common/anomaly_detection'; import { ApmMlDetectorType, getApmMlDetectorIndex, -} from '../../../common/anomaly_detection/apm_ml_detectors'; +} from '../../../../../common/anomaly_detection/apm_ml_detectors'; import { PROCESSOR_EVENT, SERVICE_ENVIRONMENT, SERVICE_NAME, TRANSACTION_TYPE, -} from '../../../common/elasticsearch_fieldnames'; +} from '../../../../../common/elasticsearch_fieldnames'; import { getEnvironmentEsField, getEnvironmentLabel, -} from '../../../common/environment_filter_values'; -import { ANOMALY_SEVERITY } from '../../../common/ml_constants'; -import { asMutableArray } from '../../../common/utils/as_mutable_array'; -import { getAlertUrlTransaction } from '../../../common/utils/formatters'; -import { getMLJobs } from '../service_map/get_service_anomalies'; -import { apmActionVariables } from './action_variables'; -import { RegisterRuleDependencies } from './register_apm_alerts'; +} from '../../../../../common/environment_filter_values'; +import { ANOMALY_SEVERITY } from '../../../../../common/ml_constants'; +import { asMutableArray } from '../../../../../common/utils/as_mutable_array'; +import { getAlertUrlTransaction } from '../../../../../common/utils/formatters'; +import { getMLJobs } from '../../../service_map/get_service_anomalies'; +import { apmActionVariables } from '../../action_variables'; +import { RegisterRuleDependencies } from '../../register_apm_rule_types'; const paramsSchema = schema.object({ serviceName: schema.maybe(schema.string()), @@ -61,9 +61,9 @@ const paramsSchema = schema.object({ ]), }); -const alertTypeConfig = ALERT_TYPES_CONFIG[AlertType.Anomaly]; +const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.Anomaly]; -export function registerAnomalyAlertType({ +export function registerAnomalyRuleType({ logger, ruleDataClient, alerting, @@ -77,10 +77,10 @@ export function registerAnomalyAlertType({ alerting.registerType( createLifecycleRuleType({ - id: AlertType.Anomaly, - name: alertTypeConfig.name, - actionGroups: alertTypeConfig.actionGroups, - defaultActionGroupId: alertTypeConfig.defaultActionGroupId, + id: ApmRuleType.Anomaly, + name: ruleTypeConfig.name, + actionGroups: ruleTypeConfig.actionGroups, + defaultActionGroupId: ruleTypeConfig.defaultActionGroupId, validate: { params: paramsSchema, }, @@ -252,7 +252,12 @@ export function registerAnomalyAlertType({ : relativeViewInAppUrl; services .alertWithLifecycle({ - id: [AlertType.Anomaly, serviceName, environment, transactionType] + id: [ + ApmRuleType.Anomaly, + serviceName, + environment, + transactionType, + ] .filter((name) => name) .join('_'), fields: { @@ -266,7 +271,7 @@ export function registerAnomalyAlertType({ [ALERT_REASON]: reasonMessage, }, }) - .scheduleActions(alertTypeConfig.defaultActionGroupId, { + .scheduleActions(ruleTypeConfig.defaultActionGroupId, { serviceName, transactionType, environment: getEnvironmentLabel(environment), diff --git a/x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_error_count.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts similarity index 82% rename from x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_error_count.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts index 4b8574441c4e0..3489ae4d91be6 100644 --- a/x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_error_count.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts @@ -7,10 +7,10 @@ import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; -import { AlertParams } from '../route'; -import { environmentQuery } from '../../../../common/utils/environment_query'; -import { Setup } from '../../../lib/helpers/setup_request'; +import { SERVICE_NAME } from '../../../../../common/elasticsearch_fieldnames'; +import { AlertParams } from '../../route'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { Setup } from '../../../../lib/helpers/setup_request'; export async function getTransactionErrorCountChartPreview({ setup, @@ -51,7 +51,7 @@ export async function getTransactionErrorCountChartPreview({ }; const resp = await apmEventClient.search( - 'get_transaction_error_count_chart_preview', + 'get_error_count_chart_preview', params ); diff --git a/x-pack/plugins/apm/server/routes/alerts/register_error_count_alert_type.test.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.test.ts similarity index 95% rename from x-pack/plugins/apm/server/routes/alerts/register_error_count_alert_type.test.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.test.ts index 3125791e7853b..342832b7e4099 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_error_count_alert_type.test.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { registerErrorCountAlertType } from './register_error_count_alert_type'; -import { createRuleTypeMocks } from './test_utils'; +import { registerErrorCountRuleType } from './register_error_count_rule_type'; +import { createRuleTypeMocks } from '../../test_utils'; describe('Error count alert', () => { it("doesn't send an alert when error count is less than threshold", async () => { const { services, dependencies, executor } = createRuleTypeMocks(); - registerErrorCountAlertType(dependencies); + registerErrorCountRuleType(dependencies); const params = { threshold: 1 }; @@ -42,7 +42,7 @@ describe('Error count alert', () => { const { services, dependencies, executor, scheduleActions } = createRuleTypeMocks(); - registerErrorCountAlertType(dependencies); + registerErrorCountRuleType(dependencies); const params = { threshold: 2, windowSize: 5, windowUnit: 'm' }; diff --git a/x-pack/plugins/apm/server/routes/alerts/register_error_count_alert_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts similarity index 83% rename from x-pack/plugins/apm/server/routes/alerts/register_error_count_alert_type.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts index 3cf88aaac8d4e..93c88b84d1d37 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_error_count_alert_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts @@ -19,24 +19,24 @@ import { ENVIRONMENT_NOT_DEFINED, getEnvironmentEsField, getEnvironmentLabel, -} from '../../../common/environment_filter_values'; -import { getAlertUrlErrorCount } from '../../../common/utils/formatters'; +} from '../../../../../common/environment_filter_values'; +import { getAlertUrlErrorCount } from '../../../../../common/utils/formatters'; import { - AlertType, + ApmRuleType, APM_SERVER_FEATURE_ID, - ALERT_TYPES_CONFIG, + RULE_TYPES_CONFIG, formatErrorCountReason, -} from '../../../common/alert_types'; +} from '../../../../../common/rules/apm_rule_types'; import { PROCESSOR_EVENT, SERVICE_ENVIRONMENT, SERVICE_NAME, -} from '../../../common/elasticsearch_fieldnames'; -import { environmentQuery } from '../../../common/utils/environment_query'; -import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; -import { apmActionVariables } from './action_variables'; -import { alertingEsClient } from './alerting_es_client'; -import { RegisterRuleDependencies } from './register_apm_alerts'; +} from '../../../../../common/elasticsearch_fieldnames'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { getApmIndices } from '../../../settings/apm_indices/get_apm_indices'; +import { apmActionVariables } from '../../action_variables'; +import { alertingEsClient } from '../../alerting_es_client'; +import { RegisterRuleDependencies } from '../../register_apm_rule_types'; const paramsSchema = schema.object({ windowSize: schema.number(), @@ -46,9 +46,9 @@ const paramsSchema = schema.object({ environment: schema.string(), }); -const alertTypeConfig = ALERT_TYPES_CONFIG[AlertType.ErrorCount]; +const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.ErrorCount]; -export function registerErrorCountAlertType({ +export function registerErrorCountRuleType({ alerting, logger, ruleDataClient, @@ -62,10 +62,10 @@ export function registerErrorCountAlertType({ alerting.registerType( createLifecycleRuleType({ - id: AlertType.ErrorCount, - name: alertTypeConfig.name, - actionGroups: alertTypeConfig.actionGroups, - defaultActionGroupId: alertTypeConfig.defaultActionGroupId, + id: ApmRuleType.ErrorCount, + name: ruleTypeConfig.name, + actionGroups: ruleTypeConfig.actionGroups, + defaultActionGroupId: ruleTypeConfig.defaultActionGroupId, validate: { params: paramsSchema, }, @@ -165,7 +165,7 @@ export function registerErrorCountAlertType({ services .alertWithLifecycle({ - id: [AlertType.ErrorCount, serviceName, environment] + id: [ApmRuleType.ErrorCount, serviceName, environment] .filter((name) => name) .join('_'), fields: { @@ -177,7 +177,7 @@ export function registerErrorCountAlertType({ [ALERT_REASON]: alertReason, }, }) - .scheduleActions(alertTypeConfig.defaultActionGroupId, { + .scheduleActions(ruleTypeConfig.defaultActionGroupId, { serviceName, environment: getEnvironmentLabel(environment), threshold: ruleParams.threshold, diff --git a/x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_duration.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts similarity index 87% rename from x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_duration.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts index 680ee0845ea7b..ad01f8a4c3c25 100644 --- a/x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_duration.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts @@ -7,26 +7,26 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; -import { AggregationType } from '../../../../common/alert_types'; +import { AggregationType } from '../../../../../common/rules/apm_rule_types'; import { SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, -} from '../../../../common/elasticsearch_fieldnames'; -import { environmentQuery } from '../../../../common/utils/environment_query'; -import { AlertParams } from '../route'; +} from '../../../../../common/elasticsearch_fieldnames'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { AlertParams } from '../../route'; import { getSearchTransactionsEvents, getDocumentTypeFilterForTransactions, getDurationFieldForTransactions, getProcessorEventForTransactions, -} from '../../../lib/helpers/transactions'; -import { Setup } from '../../../lib/helpers/setup_request'; +} from '../../../../lib/helpers/transactions'; +import { Setup } from '../../../../lib/helpers/setup_request'; import { ENVIRONMENT_NOT_DEFINED, getEnvironmentLabel, -} from '../../../../common/environment_filter_values'; -import { averageOrPercentileAgg } from '../average_or_percentile_agg'; +} from '../../../../../common/environment_filter_values'; +import { averageOrPercentileAgg } from '../../average_or_percentile_agg'; export async function getTransactionDurationChartPreview({ alertParams, diff --git a/x-pack/plugins/apm/server/routes/alerts/register_transaction_duration_alert_type.test.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.test.ts similarity index 87% rename from x-pack/plugins/apm/server/routes/alerts/register_transaction_duration_alert_type.test.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.test.ts index c142f68b6675d..4d8b91636fb6c 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_transaction_duration_alert_type.test.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.test.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { registerTransactionDurationAlertType } from './register_transaction_duration_alert_type'; -import { createRuleTypeMocks } from './test_utils'; +import { registerTransactionDurationRuleType } from './register_transaction_duration_rule_type'; +import { createRuleTypeMocks } from '../../test_utils'; -describe('registerTransactionDurationAlertType', () => { +describe('registerTransactionDurationRuleType', () => { it('sends alert when value is greater than threashold', async () => { const { services, dependencies, executor, scheduleActions } = createRuleTypeMocks(); - registerTransactionDurationAlertType(dependencies); + registerTransactionDurationRuleType(dependencies); services.scopedClusterClient.asCurrentUser.search.mockResponse({ hits: { diff --git a/x-pack/plugins/apm/server/routes/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts similarity index 83% rename from x-pack/plugins/apm/server/routes/alerts/register_transaction_duration_alert_type.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts index 6079716a42cb6..7a7e84414aec0 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_transaction_duration_alert_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts @@ -16,37 +16,37 @@ import { firstValueFrom } from 'rxjs'; import { asDuration } from '@kbn/observability-plugin/common/utils/formatters'; import { createLifecycleRuleTypeFactory } from '@kbn/rule-registry-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; -import { getAlertUrlTransaction } from '../../../common/utils/formatters'; -import { SearchAggregatedTransactionSetting } from '../../../common/aggregated_transactions'; +import { getAlertUrlTransaction } from '../../../../../common/utils/formatters'; +import { SearchAggregatedTransactionSetting } from '../../../../../common/aggregated_transactions'; import { - AlertType, + ApmRuleType, AggregationType, - ALERT_TYPES_CONFIG, + RULE_TYPES_CONFIG, APM_SERVER_FEATURE_ID, formatTransactionDurationReason, -} from '../../../common/alert_types'; +} from '../../../../../common/rules/apm_rule_types'; import { PROCESSOR_EVENT, SERVICE_NAME, TRANSACTION_TYPE, SERVICE_ENVIRONMENT, -} from '../../../common/elasticsearch_fieldnames'; +} from '../../../../../common/elasticsearch_fieldnames'; import { ENVIRONMENT_NOT_DEFINED, getEnvironmentEsField, getEnvironmentLabel, -} from '../../../common/environment_filter_values'; -import { environmentQuery } from '../../../common/utils/environment_query'; -import { getDurationFormatter } from '../../../common/utils/formatters'; +} from '../../../../../common/environment_filter_values'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { getDurationFormatter } from '../../../../../common/utils/formatters'; import { getDocumentTypeFilterForTransactions, getDurationFieldForTransactions, -} from '../../lib/helpers/transactions'; -import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; -import { apmActionVariables } from './action_variables'; -import { alertingEsClient } from './alerting_es_client'; -import { RegisterRuleDependencies } from './register_apm_alerts'; -import { averageOrPercentileAgg } from './average_or_percentile_agg'; +} from '../../../../lib/helpers/transactions'; +import { getApmIndices } from '../../../settings/apm_indices/get_apm_indices'; +import { apmActionVariables } from '../../action_variables'; +import { alertingEsClient } from '../../alerting_es_client'; +import { RegisterRuleDependencies } from '../../register_apm_rule_types'; +import { averageOrPercentileAgg } from '../../average_or_percentile_agg'; const paramsSchema = schema.object({ serviceName: schema.string(), @@ -62,9 +62,9 @@ const paramsSchema = schema.object({ environment: schema.string(), }); -const alertTypeConfig = ALERT_TYPES_CONFIG[AlertType.TransactionDuration]; +const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.TransactionDuration]; -export function registerTransactionDurationAlertType({ +export function registerTransactionDurationRuleType({ alerting, ruleDataClient, config$, @@ -76,11 +76,11 @@ export function registerTransactionDurationAlertType({ logger, }); - const type = createLifecycleRuleType({ - id: AlertType.TransactionDuration, - name: alertTypeConfig.name, - actionGroups: alertTypeConfig.actionGroups, - defaultActionGroupId: alertTypeConfig.defaultActionGroupId, + const ruleType = createLifecycleRuleType({ + id: ApmRuleType.TransactionDuration, + name: ruleTypeConfig.name, + actionGroups: ruleTypeConfig.actionGroups, + defaultActionGroupId: ruleTypeConfig.defaultActionGroupId, validate: { params: paramsSchema, }, @@ -223,7 +223,7 @@ export function registerTransactionDurationAlertType({ : relativeViewInAppUrl; services .alertWithLifecycle({ - id: `${AlertType.TransactionDuration}_${getEnvironmentLabel( + id: `${ApmRuleType.TransactionDuration}_${getEnvironmentLabel( environment )}`, fields: { @@ -236,7 +236,7 @@ export function registerTransactionDurationAlertType({ [ALERT_REASON]: reasonMessage, }, }) - .scheduleActions(alertTypeConfig.defaultActionGroupId, { + .scheduleActions(ruleTypeConfig.defaultActionGroupId, { transactionType: ruleParams.transactionType, serviceName: ruleParams.serviceName, environment: getEnvironmentLabel(environment), @@ -252,5 +252,5 @@ export function registerTransactionDurationAlertType({ }, }); - alerting.registerType(type); + alerting.registerType(ruleType); } diff --git a/x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_error_rate.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts similarity index 86% rename from x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_error_rate.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts index 48d04a856cb55..9921b0ce16a3f 100644 --- a/x-pack/plugins/apm/server/routes/alerts/chart_preview/get_transaction_error_rate.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts @@ -9,19 +9,19 @@ import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { SERVICE_NAME, TRANSACTION_TYPE, -} from '../../../../common/elasticsearch_fieldnames'; -import { environmentQuery } from '../../../../common/utils/environment_query'; -import { AlertParams } from '../route'; +} from '../../../../../common/elasticsearch_fieldnames'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { AlertParams } from '../../route'; import { getSearchTransactionsEvents, getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, -} from '../../../lib/helpers/transactions'; -import { Setup } from '../../../lib/helpers/setup_request'; +} from '../../../../lib/helpers/transactions'; +import { Setup } from '../../../../lib/helpers/setup_request'; import { calculateFailedTransactionRate, getOutcomeAggregation, -} from '../../../lib/helpers/transaction_error_rate'; +} from '../../../../lib/helpers/transaction_error_rate'; export async function getTransactionErrorRateChartPreview({ setup, diff --git a/x-pack/plugins/apm/server/routes/alerts/register_transaction_error_rate_alert_type.test.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.test.ts similarity index 93% rename from x-pack/plugins/apm/server/routes/alerts/register_transaction_error_rate_alert_type.test.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.test.ts index d3a024ec92a73..f28493338ad0d 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_transaction_error_rate_alert_type.test.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { registerTransactionErrorRateAlertType } from './register_transaction_error_rate_alert_type'; -import { createRuleTypeMocks } from './test_utils'; +import { registerTransactionErrorRateRuleType } from './register_transaction_error_rate_rule_type'; +import { createRuleTypeMocks } from '../../test_utils'; describe('Transaction error rate alert', () => { it("doesn't send an alert when rate is less than threshold", async () => { const { services, dependencies, executor } = createRuleTypeMocks(); - registerTransactionErrorRateAlertType({ + registerTransactionErrorRateRuleType({ ...dependencies, }); @@ -49,7 +49,7 @@ describe('Transaction error rate alert', () => { const { services, dependencies, executor, scheduleActions } = createRuleTypeMocks(); - registerTransactionErrorRateAlertType({ + registerTransactionErrorRateRuleType({ ...dependencies, }); diff --git a/x-pack/plugins/apm/server/routes/alerts/register_transaction_error_rate_alert_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts similarity index 84% rename from x-pack/plugins/apm/server/routes/alerts/register_transaction_error_rate_alert_type.ts rename to x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts index c6d80d70c4ef7..5e4e04d293cd7 100644 --- a/x-pack/plugins/apm/server/routes/alerts/register_transaction_error_rate_alert_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts @@ -20,30 +20,30 @@ import { ENVIRONMENT_NOT_DEFINED, getEnvironmentEsField, getEnvironmentLabel, -} from '../../../common/environment_filter_values'; -import { getAlertUrlTransaction } from '../../../common/utils/formatters'; +} from '../../../../../common/environment_filter_values'; +import { getAlertUrlTransaction } from '../../../../../common/utils/formatters'; import { - AlertType, - ALERT_TYPES_CONFIG, + ApmRuleType, + RULE_TYPES_CONFIG, APM_SERVER_FEATURE_ID, formatTransactionErrorRateReason, -} from '../../../common/alert_types'; +} from '../../../../../common/rules/apm_rule_types'; import { EVENT_OUTCOME, PROCESSOR_EVENT, SERVICE_ENVIRONMENT, SERVICE_NAME, TRANSACTION_TYPE, -} from '../../../common/elasticsearch_fieldnames'; -import { EventOutcome } from '../../../common/event_outcome'; -import { asDecimalOrInteger } from '../../../common/utils/formatters'; -import { environmentQuery } from '../../../common/utils/environment_query'; -import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; -import { apmActionVariables } from './action_variables'; -import { alertingEsClient } from './alerting_es_client'; -import { RegisterRuleDependencies } from './register_apm_alerts'; -import { SearchAggregatedTransactionSetting } from '../../../common/aggregated_transactions'; -import { getDocumentTypeFilterForTransactions } from '../../lib/helpers/transactions'; +} from '../../../../../common/elasticsearch_fieldnames'; +import { EventOutcome } from '../../../../../common/event_outcome'; +import { asDecimalOrInteger } from '../../../../../common/utils/formatters'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { getApmIndices } from '../../../settings/apm_indices/get_apm_indices'; +import { apmActionVariables } from '../../action_variables'; +import { alertingEsClient } from '../../alerting_es_client'; +import { RegisterRuleDependencies } from '../../register_apm_rule_types'; +import { SearchAggregatedTransactionSetting } from '../../../../../common/aggregated_transactions'; +import { getDocumentTypeFilterForTransactions } from '../../../../lib/helpers/transactions'; const paramsSchema = schema.object({ windowSize: schema.number(), @@ -54,9 +54,9 @@ const paramsSchema = schema.object({ environment: schema.string(), }); -const alertTypeConfig = ALERT_TYPES_CONFIG[AlertType.TransactionErrorRate]; +const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.TransactionErrorRate]; -export function registerTransactionErrorRateAlertType({ +export function registerTransactionErrorRateRuleType({ alerting, ruleDataClient, logger, @@ -70,10 +70,10 @@ export function registerTransactionErrorRateAlertType({ alerting.registerType( createLifecycleRuleType({ - id: AlertType.TransactionErrorRate, - name: alertTypeConfig.name, - actionGroups: alertTypeConfig.actionGroups, - defaultActionGroupId: alertTypeConfig.defaultActionGroupId, + id: ApmRuleType.TransactionErrorRate, + name: ruleTypeConfig.name, + actionGroups: ruleTypeConfig.actionGroups, + defaultActionGroupId: ruleTypeConfig.defaultActionGroupId, validate: { params: paramsSchema, }, @@ -225,7 +225,7 @@ export function registerTransactionErrorRateAlertType({ services .alertWithLifecycle({ id: [ - AlertType.TransactionErrorRate, + ApmRuleType.TransactionErrorRate, serviceName, transactionType, environment, @@ -242,7 +242,7 @@ export function registerTransactionErrorRateAlertType({ [ALERT_REASON]: reasonMessage, }, }) - .scheduleActions(alertTypeConfig.defaultActionGroupId, { + .scheduleActions(ruleTypeConfig.defaultActionGroupId, { serviceName, transactionType, environment: getEnvironmentLabel(environment), diff --git a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts index 77a7528fbb1a3..56ed34805c2fb 100644 --- a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts +++ b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_aggregation.ts @@ -23,7 +23,7 @@ export async function getSuggestionsWithTermsAggregation({ fieldName: string; fieldValue: string; searchAggregatedTransactions: boolean; - serviceName: string; + serviceName?: string; setup: Setup; size: number; start: number; diff --git a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions.ts b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_enum.ts similarity index 56% rename from x-pack/plugins/apm/server/routes/suggestions/get_suggestions.ts rename to x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_enum.ts index dcab43ca26abc..4437a36151895 100644 --- a/x-pack/plugins/apm/server/routes/suggestions/get_suggestions.ts +++ b/x-pack/plugins/apm/server/routes/suggestions/get_suggestions_with_terms_enum.ts @@ -8,7 +8,7 @@ import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { getProcessorEventForTransactions } from '../../lib/helpers/transactions'; import { Setup } from '../../lib/helpers/setup_request'; -export async function getSuggestions({ +export async function getSuggestionsWithTermsEnum({ fieldName, fieldValue, searchAggregatedTransactions, @@ -27,30 +27,33 @@ export async function getSuggestions({ }) { const { apmEventClient } = setup; - const response = await apmEventClient.termsEnum('get_suggestions', { - apm: { - events: [ - getProcessorEventForTransactions(searchAggregatedTransactions), - ProcessorEvent.error, - ProcessorEvent.metric, - ], - }, - body: { - case_insensitive: true, - field: fieldName, - size, - string: fieldValue, - index_filter: { - range: { - ['@timestamp']: { - gte: start, - lte: end, - format: 'epoch_millis', + const response = await apmEventClient.termsEnum( + 'get_suggestions_with_terms_enum', + { + apm: { + events: [ + getProcessorEventForTransactions(searchAggregatedTransactions), + ProcessorEvent.error, + ProcessorEvent.metric, + ], + }, + body: { + case_insensitive: true, + field: fieldName, + size, + string: fieldValue, + index_filter: { + range: { + ['@timestamp']: { + gte: start, + lte: end, + format: 'epoch_millis', + }, }, }, }, - }, - }); + } + ); return { terms: response.terms }; } diff --git a/x-pack/plugins/apm/server/routes/suggestions/route.ts b/x-pack/plugins/apm/server/routes/suggestions/route.ts index 92a64da42eca3..f0396ac62ca51 100644 --- a/x-pack/plugins/apm/server/routes/suggestions/route.ts +++ b/x-pack/plugins/apm/server/routes/suggestions/route.ts @@ -7,7 +7,7 @@ import * as t from 'io-ts'; import { maxSuggestions } from '@kbn/observability-plugin/common'; -import { getSuggestions } from './get_suggestions'; +import { getSuggestionsWithTermsEnum } from './get_suggestions_with_terms_enum'; import { getSuggestionsWithTermsAggregation } from './get_suggestions_with_terms_aggregation'; import { getSearchTransactionsEvents } from '../../lib/helpers/transactions'; import { setupRequest } from '../../lib/helpers/setup_request'; @@ -41,28 +41,35 @@ const suggestionsRoute = createApmServerRoute({ maxSuggestions ); - const suggestions = serviceName - ? await getSuggestionsWithTermsAggregation({ - fieldName, - fieldValue, - searchAggregatedTransactions, - serviceName, - setup, - size, - start, - end, - }) - : await getSuggestions({ - fieldName, - fieldValue, - searchAggregatedTransactions, - setup, - size, - start, - end, - }); + if (!serviceName) { + const suggestions = await getSuggestionsWithTermsEnum({ + fieldName, + fieldValue, + searchAggregatedTransactions, + setup, + size, + start, + end, + }); - return suggestions; + // if no terms are found using terms enum it will fall back to using ordinary terms agg search + // This is useful because terms enum can only find terms that start with the search query + // whereas terms agg approach can find terms that contain the search query + if (suggestions.terms.length > 0) { + return suggestions; + } + } + + return getSuggestionsWithTermsAggregation({ + fieldName, + fieldValue, + searchAggregatedTransactions, + serviceName, + setup, + size, + start, + end, + }); }, }); diff --git a/x-pack/plugins/cases/docs/openapi/bundled-min.json b/x-pack/plugins/cases/docs/openapi/bundled-min.json index 02e04d2b2fbdd..a3f9567b32b3d 100644 --- a/x-pack/plugins/cases/docs/openapi/bundled-min.json +++ b/x-pack/plugins/cases/docs/openapi/bundled-min.json @@ -816,6 +816,24 @@ "title" ], "properties": { + "assignees": { + "type": "array", + "description": "An array containing users that are assigned to the case.", + "nullable": true, + "items": { + "type": "object", + "required": [ + "uid" + ], + "properties": { + "uid": { + "type": "string", + "description": "A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API.", + "example": "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } + } + } + }, "connector": { "oneOf": [ { @@ -1272,6 +1290,24 @@ "version" ], "properties": { + "assignees": { + "type": "array", + "description": "An array containing users that are assigned to the case.", + "nullable": true, + "items": { + "type": "object", + "required": [ + "uid" + ], + "properties": { + "uid": { + "type": "string", + "description": "A unique identifier for the user profile. You can use the get user profile API to retrieve more details.", + "example": "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } + } + } + }, "closed_at": { "type": "string", "format": "date-time", @@ -1417,6 +1453,24 @@ "version" ], "properties": { + "assignees": { + "type": "array", + "description": "An array containing users that are assigned to the case.", + "nullable": true, + "items": { + "type": "object", + "required": [ + "uid" + ], + "properties": { + "uid": { + "type": "string", + "description": "A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API.", + "example": "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + } + } + } + }, "connector": { "oneOf": [ { @@ -1746,6 +1800,7 @@ "tags": [ "tag 1" ], + "assignees": [], "description": "A case description.", "settings": { "syncAlerts": false @@ -1840,6 +1895,7 @@ "full_name": null, "username": "elastic" }, + "assignees": [], "connector": { "id": "131d4448-abe0-4789-939d-8ef60680b498", "name": "My connector", diff --git a/x-pack/plugins/cases/docs/openapi/bundled-min.yaml b/x-pack/plugins/cases/docs/openapi/bundled-min.yaml index d90783ccb7309..43962944ee9f7 100644 --- a/x-pack/plugins/cases/docs/openapi/bundled-min.yaml +++ b/x-pack/plugins/cases/docs/openapi/bundled-min.yaml @@ -560,6 +560,19 @@ components: - tags - title properties: + assignees: + type: array + description: An array containing users that are assigned to the case. + nullable: true + items: + type: object + required: + - uid + properties: + uid: + type: string + description: A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API. + example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 connector: oneOf: - $ref: '#/components/schemas/connector_properties_none' @@ -896,6 +909,19 @@ components: - updated_by - version properties: + assignees: + type: array + description: An array containing users that are assigned to the case. + nullable: true + items: + type: object + required: + - uid + properties: + uid: + type: string + description: A unique identifier for the user profile. You can use the get user profile API to retrieve more details. + example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 closed_at: type: string format: date-time @@ -992,6 +1018,19 @@ components: - id - version properties: + assignees: + type: array + description: An array containing users that are assigned to the case. + nullable: true + items: + type: object + required: + - uid + properties: + uid: + type: string + description: A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API. + example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 connector: oneOf: - $ref: '#/components/schemas/connector_properties_none' @@ -1222,6 +1261,7 @@ components: title: Case title 1 tags: - tag 1 + assignees: [] description: A case description. settings: syncAlerts: false @@ -1296,6 +1336,7 @@ components: email: null full_name: null username: elastic + assignees: [] connector: id: 131d4448-abe0-4789-939d-8ef60680b498 name: My connector diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/create_case_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/create_case_response.yaml index 7d9cdf3626c72..8cd80595abf30 100644 --- a/x-pack/plugins/cases/docs/openapi/components/examples/create_case_response.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/examples/create_case_response.yaml @@ -8,6 +8,7 @@ value: title: Case title 1 tags: - tag 1 + assignees: [] description: A case description. settings: syncAlerts: false diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/find_case_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/find_case_response.yaml index 1c8168dde7708..6f744d03a1365 100644 --- a/x-pack/plugins/cases/docs/openapi/components/examples/find_case_response.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/examples/find_case_response.yaml @@ -33,6 +33,7 @@ value: "full_name": null, "username": "elastic" }, + "assignees": [], "connector": { "id": "none", "name": "none", diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml index 936a21a5cfc70..bd74fa423bb9c 100644 --- a/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml @@ -34,7 +34,9 @@ value: "created_at":"2022-07-13T15:33:50.604Z", "created_by":{"username":"elastic","email":null,"full_name":null},"status":"open", "updated_at":"2022-07-13T15:40:32.335Z", - "updated_by":{"full_name":null,"email":null,"username":"elastic"},"connector":{ + "updated_by":{"full_name":null,"email":null,"username":"elastic"}, + "assignees":[{"uid":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"}], + "connector":{ "id":"none", "name":"none", "type":".none", diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/update_case_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/update_case_response.yaml index 7413547e6ff60..eaf421771b51e 100644 --- a/x-pack/plugins/cases/docs/openapi/components/examples/update_case_response.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/examples/update_case_response.yaml @@ -31,6 +31,7 @@ value: "full_name": null, "username": "elastic" }, + "assignees": [], "connector": { "id": "131d4448-abe0-4789-939d-8ef60680b498", "name": "My connector", diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml index 05e3fc6ab04b7..3568008b07000 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml @@ -1,6 +1,7 @@ type: string description: The type of action. enum: + - assignees - create_case - comment - connector diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml index a53d88f3be69b..1caa1643476d5 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml @@ -22,7 +22,20 @@ required: - updated_at - updated_by - version -properties: +properties: + assignees: + type: array + description: An array containing users that are assigned to the case. + nullable: true + items: + type: object + required: + - uid + properties: + uid: + type: string + description: A unique identifier for the user profile. You can use the get user profile API to retrieve more details. + example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 closed_at: type: string format: date-time diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/create_case_request.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/create_case_request.yaml index ab6b49c653668..715bfaf112042 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/create_case_request.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/create_case_request.yaml @@ -10,6 +10,19 @@ required: - tags - title properties: + assignees: + type: array + description: An array containing users that are assigned to the case. + nullable: true + items: + type: object + required: + - uid + properties: + uid: + type: string + description: A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API. + example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 connector: oneOf: - $ref: 'connector_properties_none.yaml' diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_assignees.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_assignees.yaml new file mode 100644 index 0000000000000..122541dfe4fe6 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_assignees.yaml @@ -0,0 +1,9 @@ +type: object +properties: + assignees: + type: array + items: + type: object + properties: + uid: + type: string \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_request.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_request.yaml index f6feac43b1613..ee4249aeaf9d3 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_request.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_request.yaml @@ -13,7 +13,20 @@ properties: required: - id - version - properties: + properties: + assignees: + type: array + description: An array containing users that are assigned to the case. + nullable: true + items: + type: object + required: + - uid + properties: + uid: + type: string + description: A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API. + example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 connector: oneOf: - $ref: 'connector_properties_none.yaml' diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml index e828f3441cb5d..a3f57ed53297d 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml @@ -24,6 +24,7 @@ properties: payload: oneOf: - $ref: 'payload_alert_comment.yaml' + - $ref: 'payload_assignees.yaml' - $ref: 'payload_connector.yaml' - $ref: 'payload_create_case.yaml' - $ref: 'payload_description.yaml' diff --git a/x-pack/plugins/cases/public/components/case_view/components/suggest_users_popover.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/suggest_users_popover.test.tsx index 479b8e39d232d..bf22c764290aa 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/suggest_users_popover.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/suggest_users_popover.test.tsx @@ -36,7 +36,7 @@ describe('SuggestUsersPopover', () => { }; }); - it('calls onUsersChange when 1 user is selected', async () => { + it.skip('calls onUsersChange when 1 user is selected', async () => { const onUsersChange = jest.fn(); const props = { ...defaultProps, onUsersChange }; appMockRender.render(); @@ -182,7 +182,7 @@ describe('SuggestUsersPopover', () => { expect(screen.getByText('1 assigned')).toBeInTheDocument(); }); - it('shows the 1 assigned total after clicking on a user', async () => { + it.skip('shows the 1 assigned total after clicking on a user', async () => { appMockRender.render(); await waitForEuiPopoverOpen(); diff --git a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts index 29becfa3e99ae..538d8016a0a73 100644 --- a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts +++ b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts @@ -5,23 +5,34 @@ * 2.0. */ -import { MlTrainedModelConfig } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IngestSetProcessor, MlTrainedModelConfig } from '@elastic/elasticsearch/lib/api/types'; import { BUILT_IN_MODEL_TAG } from '@kbn/ml-plugin/common/constants/data_frame_analytics'; +import { SUPPORTED_PYTORCH_TASKS } from '@kbn/ml-plugin/common/constants/trained_models'; -import { getMlModelTypesForModelConfig, BUILT_IN_MODEL_TAG as LOCAL_BUILT_IN_MODEL_TAG } from '.'; +import { MlInferencePipeline } from '../types/pipelines'; + +import { + BUILT_IN_MODEL_TAG as LOCAL_BUILT_IN_MODEL_TAG, + generateMlInferencePipelineBody, + getMlModelTypesForModelConfig, + getSetProcessorForInferenceType, + SUPPORTED_PYTORCH_TASKS as LOCAL_SUPPORTED_PYTORCH_TASKS, +} from '.'; + +const mockModel: MlTrainedModelConfig = { + inference_config: { + ner: {}, + }, + input: { + field_names: [], + }, + model_id: 'test_id', + model_type: 'pytorch', + tags: ['test_tag'], + version: '1', +}; describe('getMlModelTypesForModelConfig lib function', () => { - const mockModel: MlTrainedModelConfig = { - inference_config: { - ner: {}, - }, - input: { - field_names: [], - }, - model_id: 'test_id', - model_type: 'pytorch', - tags: ['test_tag'], - }; const builtInMockModel: MlTrainedModelConfig = { inference_config: { text_classification: {}, @@ -50,3 +61,140 @@ describe('getMlModelTypesForModelConfig lib function', () => { expect(LOCAL_BUILT_IN_MODEL_TAG).toEqual(BUILT_IN_MODEL_TAG); }); }); + +describe('getSetProcessorForInferenceType lib function', () => { + const destinationField = 'dest'; + + it('local LOCAL_SUPPORTED_PYTORCH_TASKS matches ml plugin', () => { + expect(SUPPORTED_PYTORCH_TASKS).toEqual(LOCAL_SUPPORTED_PYTORCH_TASKS); + }); + + it('should return expected value for TEXT_CLASSIFICATION', () => { + const inferenceType = SUPPORTED_PYTORCH_TASKS.TEXT_CLASSIFICATION; + + const expected: IngestSetProcessor = { + copy_from: 'ml.inference.dest.predicted_value', + description: + "Copy the predicted_value to 'dest' if the prediction_probability is greater than 0.5", + field: destinationField, + if: 'ml.inference.dest.prediction_probability > 0.5', + value: undefined, + }; + + expect(getSetProcessorForInferenceType(destinationField, inferenceType)).toEqual(expected); + }); + + it('should return expected value for TEXT_EMBEDDING', () => { + const inferenceType = SUPPORTED_PYTORCH_TASKS.TEXT_EMBEDDING; + + const expected: IngestSetProcessor = { + copy_from: 'ml.inference.dest.predicted_value', + description: "Copy the predicted_value to 'dest'", + field: destinationField, + value: undefined, + }; + + expect(getSetProcessorForInferenceType(destinationField, inferenceType)).toEqual(expected); + }); + + it('should return undefined for unknown inferenceType', () => { + const inferenceType = 'wrongInferenceType'; + + expect(getSetProcessorForInferenceType(destinationField, inferenceType)).toBeUndefined(); + }); +}); + +describe('generateMlInferencePipelineBody lib function', () => { + const expected: MlInferencePipeline = { + description: 'my-description', + processors: [ + { + remove: { + field: 'ml.inference.my-destination-field', + ignore_missing: true, + }, + }, + { + inference: { + field_map: { + 'my-source-field': 'MODEL_INPUT_FIELD', + }, + model_id: 'test_id', + on_failure: [ + { + append: { + field: '_source._ingest.inference_errors', + value: [ + { + message: + "Processor 'inference' in pipeline 'my-pipeline' failed with message '{{ _ingest.on_failure_message }}'", + pipeline: 'my-pipeline', + timestamp: '{{{ _ingest.timestamp }}}', + }, + ], + }, + }, + ], + target_field: 'ml.inference.my-destination-field', + }, + }, + { + append: { + field: '_source._ingest.processors', + value: [ + { + model_version: '1', + pipeline: 'my-pipeline', + processed_timestamp: '{{{ _ingest.timestamp }}}', + types: ['pytorch', 'ner'], + }, + ], + }, + }, + ], + version: 1, + }; + + it('should return something expected', () => { + const actual: MlInferencePipeline = generateMlInferencePipelineBody({ + description: 'my-description', + destinationField: 'my-destination-field', + model: mockModel, + pipelineName: 'my-pipeline', + sourceField: 'my-source-field', + }); + + expect(actual).toEqual(expected); + }); + + it('should return something expected 2', () => { + const mockTextClassificationModel: MlTrainedModelConfig = { + ...mockModel, + ...{ inference_config: { text_classification: {} } }, + }; + const actual: MlInferencePipeline = generateMlInferencePipelineBody({ + description: 'my-description', + destinationField: 'my-destination-field', + model: mockTextClassificationModel, + pipelineName: 'my-pipeline', + sourceField: 'my-source-field', + }); + + expect(actual).toEqual( + expect.objectContaining({ + description: expect.any(String), + processors: expect.arrayContaining([ + expect.objectContaining({ + set: { + copy_from: 'ml.inference.my-destination-field.predicted_value', + description: + "Copy the predicted_value to 'my-destination-field' if the prediction_probability is greater than 0.5", + field: 'my-destination-field', + if: 'ml.inference.my-destination-field.prediction_probability > 0.5', + }, + }), + ]), + }) + ); + }); +}); diff --git a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts index 00d893ba9abaa..b5b4526d1723b 100644 --- a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts +++ b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { MlTrainedModelConfig } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IngestSetProcessor, MlTrainedModelConfig } from '@elastic/elasticsearch/lib/api/types'; import { MlInferencePipeline } from '../types/pipelines'; @@ -13,6 +13,17 @@ import { MlInferencePipeline } from '../types/pipelines'; // So defining it locally for now with a test to make sure it matches. export const BUILT_IN_MODEL_TAG = 'prepackaged'; +// Getting an error importing this from @kbn/ml-plugin/common/constants/trained_models' +// So defining it locally for now with a test to make sure it matches. +export const SUPPORTED_PYTORCH_TASKS = { + FILL_MASK: 'fill_mask', + NER: 'ner', + QUESTION_ANSWERING: 'question_answering', + TEXT_CLASSIFICATION: 'text_classification', + TEXT_EMBEDDING: 'text_embedding', + ZERO_SHOT_CLASSIFICATION: 'zero_shot_classification', +} as const; + export interface MlInferencePipelineParams { description?: string; destinationField: string; @@ -36,6 +47,10 @@ export const generateMlInferencePipelineBody = ({ // if model returned no input field, insert a placeholder const modelInputField = model.input?.field_names?.length > 0 ? model.input.field_names[0] : 'MODEL_INPUT_FIELD'; + + const inferenceType = Object.keys(model.inference_config)[0]; + const set = getSetProcessorForInferenceType(destinationField, inferenceType); + return { description: description ?? '', processors: [ @@ -51,21 +66,21 @@ export const generateMlInferencePipelineBody = ({ [sourceField]: modelInputField, }, model_id: model.model_id, - target_field: `ml.inference.${destinationField}`, on_failure: [ { append: { field: '_source._ingest.inference_errors', value: [ { - pipeline: pipelineName, message: `Processor 'inference' in pipeline '${pipelineName}' failed with message '{{ _ingest.on_failure_message }}'`, + pipeline: pipelineName, timestamp: '{{{ _ingest.timestamp }}}', }, ], }, }, ], + target_field: `ml.inference.${destinationField}`, }, }, { @@ -81,11 +96,39 @@ export const generateMlInferencePipelineBody = ({ ], }, }, + ...(set ? [{ set }] : []), ], version: 1, }; }; +export const getSetProcessorForInferenceType = ( + destinationField: string, + inferenceType: string +): IngestSetProcessor | undefined => { + let set: IngestSetProcessor | undefined; + const prefixedDestinationField = `ml.inference.${destinationField}`; + + if (inferenceType === SUPPORTED_PYTORCH_TASKS.TEXT_CLASSIFICATION) { + set = { + copy_from: `${prefixedDestinationField}.predicted_value`, + description: `Copy the predicted_value to '${destinationField}' if the prediction_probability is greater than 0.5`, + field: destinationField, + if: `${prefixedDestinationField}.prediction_probability > 0.5`, + value: undefined, + }; + } else if (inferenceType === SUPPORTED_PYTORCH_TASKS.TEXT_EMBEDDING) { + set = { + copy_from: `${prefixedDestinationField}.predicted_value`, + description: `Copy the predicted_value to '${destinationField}'`, + field: destinationField, + value: undefined, + }; + } + + return set; +}; + /** * Parses model types list from the given configuration of a trained machine learning model * @param trainedModel configuration for a trained machine learning model diff --git a/x-pack/plugins/enterprise_search/common/types/@elastic/elasticsearch/index.d.ts b/x-pack/plugins/enterprise_search/common/types/@elastic/elasticsearch/index.d.ts new file mode 100644 index 0000000000000..05227a54bfb51 --- /dev/null +++ b/x-pack/plugins/enterprise_search/common/types/@elastic/elasticsearch/index.d.ts @@ -0,0 +1,20 @@ +/* + * 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 '@elastic/elasticsearch/lib/api/types'; + +// TODO: Remove once type fixed in elasticsearch-specification +// (add github issue) +declare module '@elastic/elasticsearch/lib/api/types' { + // This workaround adds copy_from and description to the original IngestSetProcess and makes value + // optional. It should be value xor copy_from, but that requires using type unions. This + // workaround requires interface merging (ie, not types), so we cannot get. + export interface IngestSetProcessor { + copy_from?: string; + description?: string; + } +} diff --git a/x-pack/plugins/enterprise_search/common/types/index.ts b/x-pack/plugins/enterprise_search/common/types/index.ts index 87dc53051c7b3..9bfb32c239251 100644 --- a/x-pack/plugins/enterprise_search/common/types/index.ts +++ b/x-pack/plugins/enterprise_search/common/types/index.ts @@ -15,13 +15,13 @@ import { } from './workplace_search'; export interface InitialAppData { + access?: ProductAccess; + appSearch?: AppSearchAccount; + configuredLimits?: ConfiguredLimits; enterpriseSearchVersion?: string; kibanaVersion?: string; readOnlyMode?: boolean; searchOAuth?: SearchOAuth; - configuredLimits?: ConfiguredLimits; - access?: ProductAccess; - appSearch?: AppSearchAccount; workplaceSearch?: WorkplaceSearchInitialData; } diff --git a/x-pack/plugins/enterprise_search/common/types/pipelines.ts b/x-pack/plugins/enterprise_search/common/types/pipelines.ts index b103b4a5265b3..9b53e98d584d7 100644 --- a/x-pack/plugins/enterprise_search/common/types/pipelines.ts +++ b/x-pack/plugins/enterprise_search/common/types/pipelines.ts @@ -12,6 +12,7 @@ export interface InferencePipeline { modelState: TrainedModelState; modelStateReason?: string; pipelineName: string; + pipelineReferences: string[]; types: string[]; } @@ -37,7 +38,29 @@ export interface MlInferenceHistoryResponse { } export interface MlInferenceError { - message: string; doc_count: number; + message: string; timestamp: string | undefined; // Date string } + +export interface CreateMlInferencePipelineResponse { + addedToParentPipeline?: boolean; + created?: boolean; + id: string; +} + +export interface AttachMlInferencePipelineResponse { + addedToParentPipeline?: boolean; + created?: boolean; + id: string; +} + +/** + * Response for deleting sub-pipeline from @ml-inference pipeline. + * If sub-pipeline was deleted successfully, 'deleted' field contains its name. + * If parent pipeline was updated successfully, 'updated' field contains its name. + */ +export interface DeleteMlInferencePipelineResponse { + deleted?: string; + updated?: string; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/index/create_custom_pipeline_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/index/create_custom_pipeline_api_logic.test.ts new file mode 100644 index 0000000000000..5d4b175244397 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/index/create_custom_pipeline_api_logic.test.ts @@ -0,0 +1,35 @@ +/* + * 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 { mockHttpValues } from '../../../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test-jest-helpers'; + +import { createCustomPipeline } from './create_custom_pipeline_api_logic'; + +describe('createCustomPipelineApiLogic', () => { + const { http } = mockHttpValues; + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('createCustomPipeline', () => { + it('calls correct pipeline route', async () => { + const responsePromise = Promise.resolve({ created: ['my-custom-pipeline'] }); + http.post.mockReturnValue(responsePromise); + const result = await createCustomPipeline({ indexName: 'indexName' }); + + await nextTick(); + + expect(http.post).toHaveBeenCalledWith( + '/internal/enterprise_search/indices/indexName/pipelines' + ); + + expect(result).toEqual({ created: ['my-custom-pipeline'] }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/mappings/mappings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/mappings/mappings_logic.ts index e0e3db0a2d599..b68ae1f4e1775 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/mappings/mappings_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/mappings/mappings_logic.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types'; +import type { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types'; import { createApiLogic } from '../../../shared/api_logic/create_api_logic'; import { HttpLogic } from '../../../shared/http'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx index 0b927e4d01f4b..d8db39d01722d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx @@ -22,6 +22,7 @@ export const DEFAULT_VALUES: InferencePipeline = { modelId: 'sample-bert-ner-model', modelState: TrainedModelState.Started, pipelineName: 'Sample Processor', + pipelineReferences: [], types: ['pytorch', 'ner'], }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx index ab81e206daf57..a888364ac8bb3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx @@ -160,15 +160,15 @@ export const InferencePipelineCard: React.FC = (pipeline) => )} - {(modelType.length > 0 ? [modelType] : modelTypes).map((type) => ( - - - - {type} - - - - ))} + + + + + {modelType} + + + + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/custom_pipeline_item.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/custom_pipeline_item.tsx index 54471840aff4d..215983e5f40c4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/custom_pipeline_item.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/custom_pipeline_item.tsx @@ -56,15 +56,17 @@ export const CustomPipelineItem: React.FC<{ - - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.ingestPipelinesCard.processorsDescription', - { - defaultMessage: '{processorsCount} Processors', - values: { processorsCount }, - } - )} - + + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.ingestPipelinesCard.processorsDescription', + { + defaultMessage: '{processorsCount} Processors', + values: { processorsCount }, + } + )} + + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/default_pipeline_item.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/default_pipeline_item.tsx index c22f7910bdc4f..3e6ad933c3e82 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/default_pipeline_item.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ingest_pipelines/default_pipeline_item.tsx @@ -75,12 +75,14 @@ export const DefaultPipelineItem: React.FC<{ )} - - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.ingestPipelinesCard.managedBadge.label', - { defaultMessage: 'Managed' } - )} - + + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.ingestPipelinesCard.managedBadge.label', + { defaultMessage: 'Managed' } + )} + + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx index fed9f8e6c5376..868801116a041 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx @@ -17,6 +17,8 @@ import { EuiFormRow, EuiLink, EuiSelect, + EuiSuperSelect, + EuiSuperSelectOption, EuiSpacer, EuiText, } from '@elastic/eui'; @@ -29,6 +31,9 @@ import { docLinks } from '../../../../../shared/doc_links'; import { IndexViewLogic } from '../../index_view_logic'; import { MLInferenceLogic } from './ml_inference_logic'; +import { MlModelSelectOption } from './model_select_option'; + +const MODEL_SELECT_PLACEHOLDER_VALUE = 'model_placeholder$$'; const NoSourceFieldsError: React.FC = () => ( { const nameError = formErrors.pipelineName !== undefined && pipelineName.length > 0; const emptySourceFields = (sourceFields?.length ?? 0) === 0; + const modelOptions: Array> = [ + { + disabled: true, + inputDisplay: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.placeholder', + { defaultMessage: 'Select a model' } + ), + value: MODEL_SELECT_PLACEHOLDER_VALUE, + }, + ...models.map((model) => ({ + dropdownDisplay: , + inputDisplay: model.model_id, + value: model.model_id, + })), + ]; + return ( <> @@ -134,27 +155,19 @@ export const ConfigurePipeline: React.FC = () => { )} fullWidth > - ({ text: m.model_id, value: m.model_id })), - ]} - onChange={(e) => + hasDividers + itemLayoutAlign="top" + onChange={(value) => setInferencePipelineConfiguration({ ...configuration, - modelID: e.target.value, + modelID: value, }) } + options={modelOptions} + valueOfSelected={modelID === '' ? MODEL_SELECT_PLACEHOLDER_VALUE : modelID} /> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.test.ts index f0222becb7961..c605009d7eb0d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.test.ts @@ -163,4 +163,60 @@ describe('MlInferenceLogic', () => { }); }); }); + + describe('listeners', () => { + describe('createPipeline', () => { + const mockModelConfiguration = { + ...DEFAULT_VALUES.addInferencePipelineModal, + configuration: { + destinationField: '', + modelID: 'mock-model-id', + pipelineName: 'mock-pipeline-name', + sourceField: 'mock_text_field', + }, + indexName: 'my-index-123', + }; + it('calls makeCreatePipelineRequest when no destinationField is passed', () => { + mount({ + ...DEFAULT_VALUES, + addInferencePipelineModal: { + ...mockModelConfiguration, + }, + }); + jest.spyOn(MLInferenceLogic.actions, 'makeCreatePipelineRequest'); + MLInferenceLogic.actions.createPipeline(); + + expect(MLInferenceLogic.actions.makeCreatePipelineRequest).toHaveBeenCalledWith({ + destinationField: undefined, + indexName: mockModelConfiguration.indexName, + modelId: mockModelConfiguration.configuration.modelID, + pipelineName: mockModelConfiguration.configuration.pipelineName, + sourceField: mockModelConfiguration.configuration.sourceField, + }); + }); + + it('calls makeCreatePipelineRequest with passed destinationField', () => { + mount({ + ...DEFAULT_VALUES, + addInferencePipelineModal: { + ...mockModelConfiguration, + configuration: { + ...mockModelConfiguration.configuration, + destinationField: 'mockDestinationField', + }, + }, + }); + jest.spyOn(MLInferenceLogic.actions, 'makeCreatePipelineRequest'); + MLInferenceLogic.actions.createPipeline(); + + expect(MLInferenceLogic.actions.makeCreatePipelineRequest).toHaveBeenCalledWith({ + destinationField: 'mockDestinationField', + indexName: mockModelConfiguration.indexName, + modelId: mockModelConfiguration.configuration.modelID, + pipelineName: mockModelConfiguration.configuration.pipelineName, + sourceField: mockModelConfiguration.configuration.sourceField, + }); + }); + }); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts index 6488ca0723142..f4a968da1c2a1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts @@ -94,7 +94,6 @@ interface MLInferenceProcessorsActions { setAddInferencePipelineStep: (step: AddInferencePipelineSteps) => { step: AddInferencePipelineSteps; }; - setCreateErrors(errors: string[]): { errors: string[] }; setIndexName: (indexName: string) => { indexName: string }; setInferencePipelineConfiguration: (configuration: InferencePipelineConfiguration) => { configuration: InferencePipelineConfiguration; @@ -131,14 +130,14 @@ interface MLInferenceProcessorsValues { mappingData: typeof MappingsApiLogic.values.data; mappingStatus: Status; mlInferencePipeline?: MlInferencePipeline; - mlModelsData: typeof MLModelsApiLogic.values.data; + mlModelsData: TrainedModelConfigResponse[]; mlModelsStatus: Status; simulatePipelineData: typeof SimulateMlInterfacePipelineApiLogic.values.data; simulatePipelineErrors: string[]; simulatePipelineResult: IngestSimulateResponse; simulatePipelineStatus: Status; sourceFields: string[] | undefined; - supportedMLModels: typeof MLModelsApiLogic.values.data; + supportedMLModels: TrainedModelConfigResponse[]; } export const MLInferenceLogic = kea< @@ -148,7 +147,6 @@ export const MLInferenceLogic = kea< clearFormErrors: true, createPipeline: true, setAddInferencePipelineStep: (step: AddInferencePipelineSteps) => ({ step }), - setCreateErrors: (errors: string[]) => ({ errors }), setFormErrors: (inputErrors: AddInferencePipelineFormErrors) => ({ inputErrors }), setIndexName: (indexName: string) => ({ indexName }), setInferencePipelineConfiguration: (configuration: InferencePipelineConfiguration) => ({ @@ -208,7 +206,6 @@ export const MLInferenceLogic = kea< sourceField: configuration.sourceField, }); }, - makeCreatePipelineRequest: () => actions.setCreateErrors([]), setIndexName: ({ indexName }) => { actions.makeMLModelsRequest(undefined); actions.makeMappingRequest({ indexName }); @@ -268,7 +265,7 @@ export const MLInferenceLogic = kea< [], { createApiError: (_, error) => getErrorsFromHttpResponse(error), - setCreateErrors: (_, { errors }) => errors, + makeCreatePipelineRequest: () => [], }, ], simulatePipelineErrors: [ diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx new file mode 100644 index 0000000000000..4529e85d720f8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx @@ -0,0 +1,45 @@ +/* + * 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 React from 'react'; + +import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiTextColor, EuiTitle } from '@elastic/eui'; +import { TrainedModelConfigResponse } from '@kbn/ml-plugin/common/types/trained_models'; + +import { getMlModelTypesForModelConfig } from '../../../../../../../common/ml_inference_pipeline'; +import { getMLType, getModelDisplayTitle } from '../../../shared/ml_inference/utils'; + +export interface MlModelSelectOptionProps { + model: TrainedModelConfigResponse; +} +export const MlModelSelectOption: React.FC = ({ model }) => { + const type = getMLType(getMlModelTypesForModelConfig(model)); + const title = getModelDisplayTitle(type); + return ( + + + +

    {title ?? model.model_id}

    +
    +
    + + + {title && ( + + {model.model_id} + + )} + + + {type} + + + + +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx index f6062fda4add9..57f82b277467f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx @@ -27,6 +27,7 @@ describe('TrainedModelHealth', () => { modelId: 'sample-bert-ner-model', modelState: TrainedModelState.NotDeployed, pipelineName: 'Sample Processor', + pipelineReferences: [], types: ['pytorch'], }; it('renders model started', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/pipelines_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/pipelines_logic.test.ts index ff3b779d61e29..0ac8b0949690b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/pipelines_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/pipelines_logic.test.ts @@ -7,7 +7,7 @@ import { LogicMounter, mockFlashMessageHelpers } from '../../../../__mocks__/kea_logic'; import { apiIndex, connectorIndex } from '../../../__mocks__/view_index.mock'; -import { IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; +import type { IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; import { UpdatePipelineApiLogic } from '../../../api/connector/update_pipeline_api_logic'; import { FetchCustomPipelineApiLogic } from '../../../api/index/fetch_custom_pipeline_api_logic'; @@ -223,15 +223,15 @@ describe('PipelinesLogic', () => { expect(PipelinesLogic.values).toEqual({ ...DEFAULT_VALUES, + canSetPipeline: false, + canUseMlInferencePipeline: true, customPipelineData: indexPipelines, + hasIndexIngestionPipeline: true, index: { ...apiIndex, }, indexName, pipelineName: indexName, - canSetPipeline: false, - hasIndexIngestionPipeline: true, - canUseMlInferencePipeline: true, }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts b/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts index 34e781731988c..f92b4b0fc36ac 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts @@ -61,7 +61,6 @@ class DocLinks { public connectorsMongoDB: string; public connectorsMySQL: string; public connectorsWorkplaceSearch: string; - public crawlerGettingStarted: string; public crawlerManaging: string; public crawlerOverview: string; public deployTrainedModels: string; @@ -174,7 +173,6 @@ class DocLinks { this.connectorsMongoDB = ''; this.connectorsMySQL = ''; this.connectorsWorkplaceSearch = ''; - this.crawlerGettingStarted = ''; this.crawlerManaging = ''; this.crawlerOverview = ''; this.deployTrainedModels = ''; @@ -289,7 +287,6 @@ class DocLinks { this.connectorsMongoDB = docLinks.links.enterpriseSearch.connectorsMongoDB; this.connectorsMySQL = docLinks.links.enterpriseSearch.connectorsMySQL; this.connectorsWorkplaceSearch = docLinks.links.enterpriseSearch.connectorsWorkplaceSearch; - this.crawlerGettingStarted = docLinks.links.enterpriseSearch.crawlerGettingStarted; this.crawlerManaging = docLinks.links.enterpriseSearch.crawlerManaging; this.crawlerOverview = docLinks.links.enterpriseSearch.crawlerOverview; this.deployTrainedModels = docLinks.links.enterpriseSearch.deployTrainedModels; diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/delete_ml_inference_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/indices/delete_ml_inference_pipeline.ts deleted file mode 100644 index 04a032e3be102..0000000000000 --- a/x-pack/plugins/enterprise_search/server/lib/indices/delete_ml_inference_pipeline.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 { IngestPutPipelineRequest } from '@elastic/elasticsearch/lib/api/types'; -import { ElasticsearchClient } from '@kbn/core/server'; - -import { getInferencePipelineNameFromIndexName } from '../../utils/ml_inference_pipeline_utils'; - -/** - * Response for deleting sub-pipeline from @ml-inference pipeline. - * If sub-pipeline was deleted successfully, 'deleted' field contains its name. - * If parent pipeline was updated successfully, 'updated' field contains its name. - */ -export interface DeleteMlInferencePipelineResponse { - deleted?: string; - updated?: string; -} - -export const deleteMlInferencePipeline = async ( - indexName: string, - pipelineName: string, - client: ElasticsearchClient -) => { - const response: DeleteMlInferencePipelineResponse = {}; - const parentPipelineId = getInferencePipelineNameFromIndexName(indexName); - - // find parent pipeline - try { - const pipelineResponse = await client.ingest.getPipeline({ - id: parentPipelineId, - }); - - const parentPipeline = pipelineResponse[parentPipelineId]; - - if (parentPipeline !== undefined) { - // remove sub-pipeline from parent pipeline - if (parentPipeline.processors !== undefined) { - const updatedProcessors = parentPipeline.processors.filter( - (p) => !(p.pipeline !== undefined && p.pipeline.name === pipelineName) - ); - // only update if we changed something - if (updatedProcessors.length !== parentPipeline.processors.length) { - const updatedPipeline: IngestPutPipelineRequest = { - ...parentPipeline, - id: parentPipelineId, - processors: updatedProcessors, - }; - - const updateResponse = await client.ingest.putPipeline(updatedPipeline); - if (updateResponse.acknowledged === true) { - response.updated = parentPipelineId; - } - } - } - } - } catch (error) { - // only suppress Not Found error - if (error.meta?.statusCode !== 404) { - throw error; - } - } - - // finally, delete pipeline - const deleteResponse = await client.ingest.deletePipeline({ id: pipelineName }); - if (deleteResponse.acknowledged === true) { - response.deleted = pipelineName; - } - - return response; -}; diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.test.ts index bc77b2dff7827..941ef42aaa448 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { errors } from '@elastic/elasticsearch'; import { ElasticsearchClient } from '@kbn/core/server'; import { MlTrainedModels } from '@kbn/ml-plugin/server'; @@ -13,7 +14,8 @@ import { InferencePipeline, TrainedModelState } from '../../../common/types/pipe import { fetchAndAddTrainedModelData, getMlModelConfigsForModelIds, - fetchMlInferencePipelineProcessorNames, + getMlInferencePipelineProcessorNamesFromPipelines, + fetchMlInferencePipelines, fetchMlInferencePipelineProcessors, fetchPipelineProcessorInferenceData, InferencePipelineData, @@ -247,23 +249,35 @@ const trainedModelDataObject: Record = { modelId: 'trained-model-id-1', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-1', + pipelineReferences: ['my-index@ml-inference'], types: ['lang_ident', 'ner'], }, 'trained-model-id-2': { modelId: 'trained-model-id-2', modelState: TrainedModelState.Started, pipelineName: 'ml-inference-pipeline-2', + pipelineReferences: ['my-index@ml-inference'], types: ['pytorch', 'ner'], }, 'ml-inference-pipeline-3': { modelId: 'trained-model-id-1', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-3', + pipelineReferences: ['my-index@ml-inference'], types: ['lang_ident', 'ner'], }, }; -describe('fetchMlInferencePipelineProcessorNames lib function', () => { +const notFoundResponse = { meta: { statusCode: 404 } }; +const notFoundError = new errors.ResponseError({ + body: notFoundResponse, + statusCode: 404, + headers: {}, + meta: {} as any, + warnings: [], +}); + +describe('fetchMlInferencePipelines lib function', () => { const mockClient = { ingest: { getPipeline: jest.fn(), @@ -274,32 +288,58 @@ describe('fetchMlInferencePipelineProcessorNames lib function', () => { jest.clearAllMocks(); }); - it('should return pipeline processor names for the @ml-inference pipeline', async () => { + it('should return @ml-inference pipelines', async () => { mockClient.ingest.getPipeline.mockImplementation(() => Promise.resolve(mockGetPipeline)); - const expected = ['ml-inference-pipeline-1']; + const response = await fetchMlInferencePipelines(mockClient as unknown as ElasticsearchClient); - const response = await fetchMlInferencePipelineProcessorNames( - mockClient as unknown as ElasticsearchClient, - 'my-index' - ); + expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ id: '*@ml-inference' }); + expect(response).toEqual(mockGetPipeline); + }); - expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ id: 'my-index@ml-inference' }); - expect(response).toEqual(expected); + it('should return an empty object when no @ml-inference pipelines found', async () => { + mockClient.ingest.getPipeline.mockImplementation(() => Promise.resolve({})); + + const response = await fetchMlInferencePipelines(mockClient as unknown as ElasticsearchClient); + + expect(response).toEqual({}); }); - it('should return an empty array for a missing @ml-inference pipeline', async () => { - mockClient.ingest.getPipeline.mockImplementation(() => Promise.resolve(mockGetPipeline)); + it('should return an empty object when getPipeline throws an error ', async () => { + mockClient.ingest.getPipeline.mockImplementation(() => Promise.reject(notFoundError)); - const response = await fetchMlInferencePipelineProcessorNames( - mockClient as unknown as ElasticsearchClient, - 'my-index-without-ml-inference-pipeline' + const response = await fetchMlInferencePipelines(mockClient as unknown as ElasticsearchClient); + + expect(response).toEqual({}); + }); +}); + +describe('getMlInferencePipelineProcessorNamesFromPipelines', () => { + it('should return pipeline processor names for the @ml-inference pipeline', () => { + const expected = ['ml-inference-pipeline-1']; + const processorNames = getMlInferencePipelineProcessorNamesFromPipelines( + 'my-index', + mockGetPipeline + ); + expect(processorNames).toEqual(expected); + }); + it('should return an empty array for a missing @ml-inference pipeline', () => { + const processorNames = getMlInferencePipelineProcessorNamesFromPipelines( + 'my-index-without-ml-inference-pipeline', + mockGetPipeline ); - expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ - id: 'my-index-without-ml-inference-pipeline@ml-inference', - }); - expect(response).toEqual([]); + expect(processorNames).toEqual([]); + }); + it('should return an empty array for a pipeline missing processors', () => { + const processorNames = getMlInferencePipelineProcessorNamesFromPipelines( + 'my-index-without-ml-inference-pipeline', + { + 'my-index-without-ml-inference-pipeline': {}, + } + ); + + expect(processorNames).toEqual([]); }); }); @@ -322,6 +362,7 @@ describe('fetchPipelineProcessorInferenceData lib function', () => { modelId: 'trained-model-id-1', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-1', + pipelineReferences: ['my-index@ml-inference', 'other-index@ml-inference'], trainedModelName: 'trained-model-id-1', types: [], }, @@ -329,6 +370,7 @@ describe('fetchPipelineProcessorInferenceData lib function', () => { modelId: 'trained-model-id-2', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-2', + pipelineReferences: ['my-index@ml-inference'], trainedModelName: 'trained-model-id-2', types: [], }, @@ -336,7 +378,11 @@ describe('fetchPipelineProcessorInferenceData lib function', () => { const response = await fetchPipelineProcessorInferenceData( mockClient as unknown as ElasticsearchClient, - ['ml-inference-pipeline-1', 'ml-inference-pipeline-2', 'non-ml-inference-pipeline'] + ['ml-inference-pipeline-1', 'ml-inference-pipeline-2', 'non-ml-inference-pipeline'], + { + 'ml-inference-pipeline-1': ['my-index@ml-inference', 'other-index@ml-inference'], + 'ml-inference-pipeline-2': ['my-index@ml-inference'], + } ); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ @@ -377,6 +423,7 @@ describe('getMlModelConfigsForModelIds lib function', () => { modelId: 'trained-model-id-1', modelState: TrainedModelState.Started, pipelineName: '', + pipelineReferences: [], trainedModelName: 'trained-model-id-1', types: ['pytorch', 'ner'], }, @@ -384,6 +431,7 @@ describe('getMlModelConfigsForModelIds lib function', () => { modelId: 'trained-model-id-2', modelState: TrainedModelState.Started, pipelineName: '', + pipelineReferences: [], trainedModelName: 'trained-model-id-2', types: ['pytorch', 'ner'], }, @@ -413,6 +461,7 @@ describe('getMlModelConfigsForModelIds lib function', () => { modelId: 'trained-model-id-1', modelState: TrainedModelState.Started, pipelineName: '', + pipelineReferences: [], trainedModelName: 'trained-model-id-1', types: ['pytorch', 'ner'], }, @@ -420,6 +469,7 @@ describe('getMlModelConfigsForModelIds lib function', () => { modelId: 'trained-model-id-2', modelState: TrainedModelState.Started, pipelineName: '', + pipelineReferences: [], trainedModelName: 'trained-model-id-2', types: ['pytorch', 'ner'], }, @@ -427,6 +477,7 @@ describe('getMlModelConfigsForModelIds lib function', () => { modelId: undefined, // Redacted modelState: TrainedModelState.Started, pipelineName: '', + pipelineReferences: [], trainedModelName: 'trained-model-id-3-in-other-space', types: ['pytorch', 'ner'], }, @@ -483,6 +534,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelId: 'trained-model-id-1', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-1', + pipelineReferences: [], trainedModelName: 'trained-model-id-1', types: [], }, @@ -490,6 +542,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelId: 'trained-model-id-2', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-2', + pipelineReferences: [], trainedModelName: 'trained-model-id-2', types: [], }, @@ -497,6 +550,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelId: 'trained-model-id-3', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-3', + pipelineReferences: [], trainedModelName: 'trained-model-id-3', types: [], }, @@ -504,6 +558,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelId: 'trained-model-id-4', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-4', + pipelineReferences: [], trainedModelName: 'trained-model-id-4', types: [], }, @@ -514,6 +569,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelId: 'trained-model-id-1', modelState: TrainedModelState.NotDeployed, pipelineName: 'ml-inference-pipeline-1', + pipelineReferences: [], trainedModelName: 'trained-model-id-1', types: ['lang_ident', 'ner'], }, @@ -521,6 +577,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelId: 'trained-model-id-2', modelState: TrainedModelState.Started, pipelineName: 'ml-inference-pipeline-2', + pipelineReferences: [], trainedModelName: 'trained-model-id-2', types: ['pytorch', 'ner'], }, @@ -529,6 +586,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelState: TrainedModelState.Failed, modelStateReason: 'something is wrong, boom', pipelineName: 'ml-inference-pipeline-3', + pipelineReferences: [], trainedModelName: 'trained-model-id-3', types: ['pytorch', 'text_classification'], }, @@ -536,6 +594,7 @@ describe('fetchAndAddTrainedModelData lib function', () => { modelId: 'trained-model-id-4', modelState: TrainedModelState.Starting, pipelineName: 'ml-inference-pipeline-4', + pipelineReferences: [], trainedModelName: 'trained-model-id-4', types: ['pytorch', 'fill_mask'], }, @@ -577,7 +636,7 @@ describe('fetchMlInferencePipelineProcessors lib function', () => { }); describe('when Machine Learning is disabled in the current space', () => { - it('should throw an eror', () => { + it('should throw an error', () => { expect(() => fetchMlInferencePipelineProcessors( mockClient as unknown as ElasticsearchClient, @@ -599,7 +658,7 @@ describe('fetchMlInferencePipelineProcessors lib function', () => { ); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ - id: 'index-with-no-ml-inference-pipeline@ml-inference', + id: '*@ml-inference', }); expect(mockClient.ingest.getPipeline).toHaveBeenCalledTimes(1); expect(mockClient.ml.getTrainedModels).toHaveBeenCalledTimes(0); @@ -626,7 +685,7 @@ describe('fetchMlInferencePipelineProcessors lib function', () => { ); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ - id: 'my-index@ml-inference', + id: '*@ml-inference', }); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ id: 'ml-inference-pipeline-1', @@ -663,7 +722,7 @@ describe('fetchMlInferencePipelineProcessors lib function', () => { ); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ - id: 'my-index@ml-inference', + id: '*@ml-inference', }); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ id: 'ml-inference-pipeline-1', @@ -707,7 +766,7 @@ describe('fetchMlInferencePipelineProcessors lib function', () => { ); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ - id: 'my-index@ml-inference', + id: '*@ml-inference', }); expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ id: 'ml-inference-pipeline-1,ml-inference-pipeline-3', diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.ts index e5843be2a6d7d..1eabe28eb78b1 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_ml_inference_pipeline_processors.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { IngestGetPipelineResponse } from '@elastic/elasticsearch/lib/api/types'; import { ElasticsearchClient } from '@kbn/core/server'; import { MlTrainedModels } from '@kbn/ml-plugin/server'; @@ -16,31 +17,62 @@ export type InferencePipelineData = InferencePipeline & { trainedModelName: string; }; -export const fetchMlInferencePipelineProcessorNames = async ( - client: ElasticsearchClient, - indexName: string -): Promise => { +export const fetchMlInferencePipelines = async (client: ElasticsearchClient) => { try { - const mlInferencePipelineName = getInferencePipelineNameFromIndexName(indexName); - const { - [mlInferencePipelineName]: { processors: mlInferencePipelineProcessors = [] }, - } = await client.ingest.getPipeline({ - id: mlInferencePipelineName, + return await client.ingest.getPipeline({ + id: getInferencePipelineNameFromIndexName('*'), }); + } catch (error) { + // The GET /_ingest/pipeline API returns an empty object on 404 Not Found. If there are no `@ml-inference` + // pipelines then return an empty record of pipelines + return {}; + } +}; - return mlInferencePipelineProcessors - .map((obj) => obj.pipeline?.name) - .filter((name): name is string => name !== undefined); - } catch (err) { - // The GET /_ingest/pipeline API returns an empty object on 404 Not Found. If someone provides - // a bad index name, catch the error and return an empty array of names. +export const getMlInferencePipelineProcessorNamesFromPipelines = ( + indexName: string, + pipelines: IngestGetPipelineResponse +): string[] => { + const mlInferencePipelineName = getInferencePipelineNameFromIndexName(indexName); + if (pipelines?.[mlInferencePipelineName]?.processors === undefined) { return []; } + const { + [mlInferencePipelineName]: { processors: mlInferencePipelineProcessors = [] }, + } = pipelines; + + return mlInferencePipelineProcessors + .map((obj) => obj.pipeline?.name) + .filter((name): name is string => name !== undefined); +}; + +export const getProcessorPipelineMap = ( + pipelines: IngestGetPipelineResponse +): Record => { + const result: Record = {}; + const addPipelineToProcessorMap = (processorName: string, pipelineName: string) => { + if (processorName in result) { + result[processorName].push(pipelineName); + } else { + result[processorName] = [pipelineName]; + } + }; + + Object.entries(pipelines).forEach(([name, pipeline]) => + pipeline?.processors?.forEach((processor) => { + if (processor.pipeline?.name !== undefined) { + addPipelineToProcessorMap(processor.pipeline.name, name); + } + }) + ); + + return result; }; export const fetchPipelineProcessorInferenceData = async ( client: ElasticsearchClient, - mlInferencePipelineProcessorNames: string[] + mlInferencePipelineProcessorNames: string[], + pipelineProcessorsMap: Record ): Promise => { const mlInferencePipelineProcessorConfigs = await client.ingest.getPipeline({ id: mlInferencePipelineProcessorNames.join(), @@ -61,6 +93,7 @@ export const fetchPipelineProcessorInferenceData = async ( modelId: trainedModelName, modelState: TrainedModelState.NotDeployed, pipelineName: pipelineProcessorName, + pipelineReferences: pipelineProcessorsMap?.[pipelineProcessorName] ?? [], trainedModelName, types: [], }); @@ -96,6 +129,7 @@ export const getMlModelConfigsForModelIds = async ( modelId: modelNamesInCurrentSpace.includes(trainedModelName) ? trainedModelName : undefined, modelState: TrainedModelState.NotDeployed, pipelineName: '', + pipelineReferences: [], trainedModelName, types: getMlModelTypesForModelConfig(trainedModelData), }; @@ -155,9 +189,9 @@ export const fetchAndAddTrainedModelData = async ( return { ...data, modelId, - types, modelState, modelStateReason, + types, }; }); }; @@ -171,9 +205,11 @@ export const fetchMlInferencePipelineProcessors = async ( return Promise.reject(new Error('Machine Learning is not enabled')); } - const mlInferencePipelineProcessorNames = await fetchMlInferencePipelineProcessorNames( - client, - indexName + const allMlPipelines = await fetchMlInferencePipelines(client); + const pipelineProcessorsPipelineCountMap = getProcessorPipelineMap(allMlPipelines); + const mlInferencePipelineProcessorNames = getMlInferencePipelineProcessorNamesFromPipelines( + indexName, + allMlPipelines ); // Elasticsearch's GET pipelines API call will return all of the pipeline data if no ids are @@ -183,7 +219,8 @@ export const fetchMlInferencePipelineProcessors = async ( const pipelineProcessorInferenceData = await fetchPipelineProcessorInferenceData( client, - mlInferencePipelineProcessorNames + mlInferencePipelineProcessorNames, + pipelineProcessorsPipelineCountMap ); // Elasticsearch's GET trained models and GET trained model stats API calls will return the diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline.test.ts new file mode 100644 index 0000000000000..5f907bb19c9c2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline.test.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. + */ + +jest.mock('../../../../../utils/create_ml_inference_pipeline', () => ({ + addSubPipelineToIndexSpecificMlPipeline: jest.fn(() => { + return Promise.resolve({ addedToParentPipeline: true, id: 'pipeline-id' }); + }), +})); + +import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; + +import { addSubPipelineToIndexSpecificMlPipeline } from '../../../../../utils/create_ml_inference_pipeline'; + +import { attachMlInferencePipeline } from './attach_ml_pipeline'; + +describe('attachMlInferencePipeline lib function', () => { + const mockClient = {} as unknown as ElasticsearchClient; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('calls addSubPipelineToIndexSpecificMlPipeline util', async () => { + const result = await attachMlInferencePipeline('indexName', 'pipeline-name', mockClient); + expect(result).toEqual({ + addedToParentPipeline: true, + id: 'pipeline-id', + }); + + expect(addSubPipelineToIndexSpecificMlPipeline).toHaveBeenCalledWith( + 'indexName', + 'pipeline-name', + mockClient + ); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline.ts new file mode 100644 index 0000000000000..4e9e3b0e227c5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline.ts @@ -0,0 +1,20 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; + +import { addSubPipelineToIndexSpecificMlPipeline } from '../../../../../utils/create_ml_inference_pipeline'; + +export const attachMlInferencePipeline = async ( + indexName: string, + pipelineName: string, + esClient: ElasticsearchClient +) => { + const response = await addSubPipelineToIndexSpecificMlPipeline(indexName, pipelineName, esClient); + + return response; +}; diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.test.ts new file mode 100644 index 0000000000000..220db6cca9eb6 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.test.ts @@ -0,0 +1,131 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core/server'; + +import { getPrefixedInferencePipelineProcessorName } from '../../../../../utils/ml_inference_pipeline_utils'; + +import { createMlInferencePipeline } from './create_ml_inference_pipeline'; + +const mockClient = { + ingest: { + getPipeline: jest.fn(), + putPipeline: jest.fn(), + }, + ml: { + getTrainedModels: jest.fn(), + }, +}; + +describe('createMlInferencePipeline lib function', () => { + const pipelineName = 'my-pipeline'; + const modelId = 'my-model-id'; + const sourceField = 'my-source-field'; + const destinationField = 'my-dest-field'; + const inferencePipelineGeneratedName = getPrefixedInferencePipelineProcessorName(pipelineName); + + mockClient.ml.getTrainedModels.mockImplementation(() => + Promise.resolve({ + trained_model_configs: [ + { + inference_config: { + ner: {}, + }, + input: { + field_names: ['target-field'], + }, + }, + ], + }) + ); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("should create the pipeline if it doesn't exist", async () => { + mockClient.ingest.getPipeline.mockImplementation(() => Promise.reject({ statusCode: 404 })); // Pipeline does not exist + mockClient.ingest.putPipeline.mockImplementation(() => Promise.resolve({ acknowledged: true })); + + const expectedResult = { + created: true, + id: inferencePipelineGeneratedName, + }; + + const actualResult = await createMlInferencePipeline( + pipelineName, + modelId, + sourceField, + destinationField, + mockClient as unknown as ElasticsearchClient + ); + + expect(actualResult).toEqual(expectedResult); + expect(mockClient.ingest.putPipeline).toHaveBeenCalled(); + }); + + it('should convert spaces to underscores in the pipeline name', async () => { + await createMlInferencePipeline( + 'my pipeline with spaces ', + modelId, + sourceField, + destinationField, + mockClient as unknown as ElasticsearchClient + ); + + expect(mockClient.ingest.putPipeline).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'ml-inference-my_pipeline_with_spaces', + }) + ); + }); + + it('should default the destination field to the pipeline name', async () => { + mockClient.ingest.getPipeline.mockImplementation(() => Promise.reject({ statusCode: 404 })); // Pipeline does not exist + mockClient.ingest.putPipeline.mockImplementation(() => Promise.resolve({ acknowledged: true })); + + await createMlInferencePipeline( + pipelineName, + modelId, + sourceField, + undefined, // Omitted destination field + mockClient as unknown as ElasticsearchClient + ); + + // Verify the object passed to pipeline creation contains the default target field name + expect(mockClient.ingest.putPipeline).toHaveBeenCalledWith( + expect.objectContaining({ + processors: expect.arrayContaining([ + expect.objectContaining({ + inference: expect.objectContaining({ + target_field: `ml.inference.${pipelineName}`, + }), + }), + ]), + }) + ); + }); + + it('should throw an error without creating the pipeline if it already exists', () => { + mockClient.ingest.getPipeline.mockImplementation(() => + Promise.resolve({ + [inferencePipelineGeneratedName]: {}, + }) + ); // Pipeline exists + + const actualResult = createMlInferencePipeline( + pipelineName, + modelId, + sourceField, + destinationField, + mockClient as unknown as ElasticsearchClient + ); + + expect(actualResult).rejects.toThrow(Error); + expect(mockClient.ingest.putPipeline).not.toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.ts new file mode 100644 index 0000000000000..b454f8b495cb2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline.ts @@ -0,0 +1,104 @@ +/* + * 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 { IngestGetPipelineResponse } from '@elastic/elasticsearch/lib/api/types'; +import { ElasticsearchClient } from '@kbn/core/server'; + +import { formatPipelineName } from '../../../../../../common/ml_inference_pipeline'; +import { ErrorCode } from '../../../../../../common/types/error_codes'; +import type { CreateMlInferencePipelineResponse } from '../../../../../../common/types/pipelines'; +import { addSubPipelineToIndexSpecificMlPipeline } from '../../../../../utils/create_ml_inference_pipeline'; +import { getPrefixedInferencePipelineProcessorName } from '../../../../../utils/ml_inference_pipeline_utils'; +import { formatMlPipelineBody } from '../../../../pipelines/create_pipeline_definitions'; + +/** + * Creates a Machine Learning Inference pipeline with the given settings, if it doesn't exist yet, + * then references it in the "parent" ML Inference pipeline that is associated with the index. + * @param indexName name of the index this pipeline corresponds to. + * @param pipelineName pipeline name set by the user. + * @param modelId model ID selected by the user. + * @param sourceField The document field that model will read. + * @param destinationField The document field that the model will write to. + * @param esClient the Elasticsearch Client to use when retrieving pipeline and model details. + */ +export const createAndReferenceMlInferencePipeline = async ( + indexName: string, + pipelineName: string, + modelId: string, + sourceField: string, + destinationField: string | null | undefined, + esClient: ElasticsearchClient +): Promise => { + const createPipelineResult = await createMlInferencePipeline( + pipelineName, + modelId, + sourceField, + destinationField, + esClient + ); + + const addSubPipelineResult = await addSubPipelineToIndexSpecificMlPipeline( + indexName, + createPipelineResult.id, + esClient + ); + + return { + ...createPipelineResult, + addedToParentPipeline: addSubPipelineResult.addedToParentPipeline, + }; +}; + +/** + * Creates a Machine Learning Inference pipeline with the given settings, if it doesn't exist yet. + * @param pipelineName pipeline name set by the user. + * @param modelId model ID selected by the user. + * @param sourceField The document field that model will read. + * @param destinationField The document field that the model will write to. + * @param esClient the Elasticsearch Client to use when retrieving pipeline and model details. + */ +export const createMlInferencePipeline = async ( + pipelineName: string, + modelId: string, + sourceField: string, + destinationField: string | null | undefined, + esClient: ElasticsearchClient +): Promise => { + const inferencePipelineGeneratedName = getPrefixedInferencePipelineProcessorName(pipelineName); + + // Check that a pipeline with the same name doesn't already exist + let pipelineByName: IngestGetPipelineResponse | undefined; + try { + pipelineByName = await esClient.ingest.getPipeline({ + id: inferencePipelineGeneratedName, + }); + } catch (error) { + // Silently swallow error + } + if (pipelineByName?.[inferencePipelineGeneratedName]) { + throw new Error(ErrorCode.PIPELINE_ALREADY_EXISTS); + } + + // Generate pipeline with default processors + const mlInferencePipeline = await formatMlPipelineBody( + inferencePipelineGeneratedName, + modelId, + sourceField, + destinationField || formatPipelineName(pipelineName), + esClient + ); + + await esClient.ingest.putPipeline({ + id: inferencePipelineGeneratedName, + ...mlInferencePipeline, + }); + + return { + created: true, + id: inferencePipelineGeneratedName, + }; +}; diff --git a/x-pack/plugins/enterprise_search/server/lib/ml_inference_pipeline/get_inference_pipelines.test.ts b/x-pack/plugins/enterprise_search/server/lib/ml_inference_pipeline/get_inference_pipelines.test.ts new file mode 100644 index 0000000000000..45953166667a5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/ml_inference_pipeline/get_inference_pipelines.test.ts @@ -0,0 +1,131 @@ +/* + * 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 { IngestProcessorContainer } from '@elastic/elasticsearch/lib/api/types'; +import { ElasticsearchClient } from '@kbn/core/server'; +import { MlTrainedModels } from '@kbn/ml-plugin/server'; + +import { getMlInferencePipelines } from './get_inference_pipelines'; + +jest.mock('../indices/fetch_ml_inference_pipeline_processors', () => ({ + getMlModelConfigsForModelIds: jest.fn(), +})); + +describe('getMlInferencePipelines', () => { + const mockClient = { + ingest: { + getPipeline: jest.fn(), + }, + }; + const mockTrainedModelsProvider = { + getTrainedModels: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should throw an error if Machine Learning is disabled in the current space', () => { + expect(() => + getMlInferencePipelines(mockClient as unknown as ElasticsearchClient, undefined) + ).rejects.toThrowError('Machine Learning is not enabled'); + }); + + it('should fetch inference pipelines and redact inaccessible model IDs', async () => { + function mockInferencePipeline(modelId: string) { + return { + processors: [ + { + append: {}, + }, + { + inference: { + model_id: modelId, + }, + }, + { + remove: {}, + }, + ], + }; + } + + const mockPipelines = { + pipeline1: mockInferencePipeline('model1'), + pipeline2: mockInferencePipeline('model2'), + pipeline3: mockInferencePipeline('redactedModel3'), + pipeline4: { + // Pipeline with multiple inference processors referencing an inaccessible model + processors: [ + { + append: {}, + }, + { + inference: { + model_id: 'redactedModel3', + }, + }, + { + inference: { + model_id: 'model2', + }, + }, + { + inference: { + model_id: 'redactedModel4', + }, + }, + { + remove: {}, + }, + ], + }, + }; + + const mockTrainedModels = { + trained_model_configs: [ + { + model_id: 'model1', + }, + { + model_id: 'model2', + }, + ], + }; + + mockClient.ingest.getPipeline.mockImplementation(() => Promise.resolve(mockPipelines)); + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockTrainedModels) + ); + + const actualPipelines = await getMlInferencePipelines( + mockClient as unknown as ElasticsearchClient, + mockTrainedModelsProvider as unknown as MlTrainedModels + ); + + expect( + (actualPipelines.pipeline1.processors as IngestProcessorContainer[])[1].inference?.model_id + ).toBeDefined(); + expect( + (actualPipelines.pipeline2.processors as IngestProcessorContainer[])[1].inference?.model_id + ).toBeDefined(); + expect( + (actualPipelines.pipeline3.processors as IngestProcessorContainer[])[1].inference?.model_id + ).toEqual(''); // Redacted model ID + expect( + (actualPipelines.pipeline4.processors as IngestProcessorContainer[])[1].inference?.model_id + ).toEqual(''); + expect( + (actualPipelines.pipeline4.processors as IngestProcessorContainer[])[2].inference?.model_id + ).toBeDefined(); + expect( + (actualPipelines.pipeline4.processors as IngestProcessorContainer[])[3].inference?.model_id + ).toEqual(''); + expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ id: 'ml-inference-*' }); + expect(mockTrainedModelsProvider.getTrainedModels).toHaveBeenCalledWith({}); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/ml_inference_pipeline/get_inference_pipelines.ts b/x-pack/plugins/enterprise_search/server/lib/ml_inference_pipeline/get_inference_pipelines.ts new file mode 100644 index 0000000000000..4bdf7e95d4a06 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/ml_inference_pipeline/get_inference_pipelines.ts @@ -0,0 +1,75 @@ +/* + * 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 { IngestPipeline, IngestProcessorContainer } from '@elastic/elasticsearch/lib/api/types'; +import { ElasticsearchClient } from '@kbn/core/server'; +import { MlTrainedModels } from '@kbn/ml-plugin/server'; + +/** + * Gets all ML inference pipelines. Redacts trained model IDs in those pipelines which reference + * a model inaccessible in the current Kibana space. + * @param esClient the Elasticsearch Client to use to fetch the errors. + * @param trainedModelsProvider ML trained models provider. + */ +export const getMlInferencePipelines = async ( + esClient: ElasticsearchClient, + trainedModelsProvider: MlTrainedModels | undefined +): Promise> => { + if (!trainedModelsProvider) { + return Promise.reject(new Error('Machine Learning is not enabled')); + } + + // Fetch all ML inference pipelines and trained models that are accessible in the current + // Kibana space + const [fetchedInferencePipelines, trainedModels] = await Promise.all([ + esClient.ingest.getPipeline({ + id: 'ml-inference-*', + }), + trainedModelsProvider.getTrainedModels({}), + ]); + const accessibleModelIds = Object.values(trainedModels.trained_model_configs).map( + (modelConfig) => modelConfig.model_id + ); + + // Process pipelines: check if the model_id is one of the redacted ones, if so, redact it in the + // result as well + const inferencePipelinesResult: Record = {}; + Object.entries(fetchedInferencePipelines).forEach(([name, inferencePipeline]) => { + inferencePipelinesResult[name] = { + ...inferencePipeline, + processors: inferencePipeline.processors?.map((processor) => + redactModelIdIfInaccessible(processor, accessibleModelIds) + ), + }; + }); + + return Promise.resolve(inferencePipelinesResult); +}; + +/** + * Convenience function to redact the trained model ID in an ML inference processor if the model is + * not accessible in the current Kibana space. In this case `model_id` gets replaced with `''`. + * @param processor the processor to process. + * @param accessibleModelIds array of known accessible model IDs. + * @returns the input processor if unchanged, or a copy of the processor with the model ID redacted. + */ +function redactModelIdIfInaccessible( + processor: IngestProcessorContainer, + accessibleModelIds: string[] +): IngestProcessorContainer { + if (!processor.inference || accessibleModelIds.includes(processor.inference.model_id)) { + return processor; + } + + return { + ...processor, + inference: { + ...processor.inference, + model_id: '', + }, + }; +} diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/get_custom_pipelines.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_custom_pipelines.ts index 11127e7e5d236..d7f2dd2bbab26 100644 --- a/x-pack/plugins/enterprise_search/server/lib/pipelines/get_custom_pipelines.ts +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_custom_pipelines.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IngestGetPipelineResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IngestGetPipelineResponse } from '@elastic/elasticsearch/lib/api/types'; import { IScopedClusterClient } from '@kbn/core/server'; export const getCustomPipelines = async ( diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/get_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_pipeline.ts index a02b4cdd8b19b..05b83d88a0b1d 100644 --- a/x-pack/plugins/enterprise_search/server/lib/pipelines/get_pipeline.ts +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_pipeline.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IngestGetPipelineResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IngestGetPipelineResponse } from '@elastic/elasticsearch/lib/api/types'; import { IScopedClusterClient } from '@kbn/core/server'; export const getPipeline = async ( diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/delete_ml_inference_pipeline.test.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline.test.ts similarity index 100% rename from x-pack/plugins/enterprise_search/server/lib/indices/delete_ml_inference_pipeline.test.ts rename to x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline.test.ts diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline.ts new file mode 100644 index 0000000000000..19654d0b2e936 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient } from '@kbn/core/server'; + +import { DeleteMlInferencePipelineResponse } from '../../../../../common/types/pipelines'; + +import { detachMlInferencePipeline } from './detach_ml_inference_pipeline'; + +export const deleteMlInferencePipeline = async ( + indexName: string, + pipelineName: string, + client: ElasticsearchClient +) => { + let response: DeleteMlInferencePipelineResponse = {}; + + try { + response = await detachMlInferencePipeline(indexName, pipelineName, client); + } catch (error) { + // only suppress Not Found error + if (error.meta?.statusCode !== 404) { + throw error; + } + } + + // finally, delete pipeline + const deleteResponse = await client.ingest.deletePipeline({ id: pipelineName }); + if (deleteResponse.acknowledged === true) { + response.deleted = pipelineName; + } + + return response; +}; diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline.test.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline.test.ts new file mode 100644 index 0000000000000..bcab516ab5b9c --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline.test.ts @@ -0,0 +1,139 @@ +/* + * 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 { errors } from '@elastic/elasticsearch'; +import { ElasticsearchClient } from '@kbn/core/server'; + +import { detachMlInferencePipeline } from './detach_ml_inference_pipeline'; + +describe('detachMlInferencePipeline', () => { + const mockClient = { + ingest: { + deletePipeline: jest.fn(), + getPipeline: jest.fn(), + putPipeline: jest.fn(), + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + const anyObject: any = {}; + const notFoundResponse = { meta: { statusCode: 404 } }; + const notFoundError = new errors.ResponseError({ + body: notFoundResponse, + statusCode: 404, + headers: {}, + meta: anyObject, + warnings: [], + }); + const mockGetPipeline = { + 'my-index@ml-inference': { + id: 'my-index@ml-inference', + processors: [ + { + pipeline: { + name: 'my-ml-pipeline', + }, + }, + ], + }, + }; + + it('should update parent pipeline', async () => { + mockClient.ingest.getPipeline.mockImplementation(() => Promise.resolve(mockGetPipeline)); + mockClient.ingest.putPipeline.mockImplementation(() => Promise.resolve({ acknowledged: true })); + mockClient.ingest.deletePipeline.mockImplementation(() => + Promise.resolve({ acknowledged: true }) + ); + + const expectedResponse = { updated: 'my-index@ml-inference' }; + + const response = await detachMlInferencePipeline( + 'my-index', + 'my-ml-pipeline', + mockClient as unknown as ElasticsearchClient + ); + + expect(response).toEqual(expectedResponse); + + expect(mockClient.ingest.putPipeline).toHaveBeenCalledWith({ + id: 'my-index@ml-inference', + processors: [], + }); + expect(mockClient.ingest.deletePipeline).not.toHaveBeenCalledWith({ + id: 'my-ml-pipeline', + }); + }); + + it('should only remove provided pipeline from parent', async () => { + mockClient.ingest.getPipeline.mockImplementation(() => + Promise.resolve({ + 'my-index@ml-inference': { + id: 'my-index@ml-inference', + processors: [ + { + pipeline: { + name: 'my-ml-pipeline', + }, + }, + { + pipeline: { + name: 'my-ml-other-pipeline', + }, + }, + ], + }, + }) + ); + mockClient.ingest.putPipeline.mockImplementation(() => Promise.resolve({ acknowledged: true })); + mockClient.ingest.deletePipeline.mockImplementation(() => + Promise.resolve({ acknowledged: true }) + ); + + const expectedResponse = { updated: 'my-index@ml-inference' }; + + const response = await detachMlInferencePipeline( + 'my-index', + 'my-ml-pipeline', + mockClient as unknown as ElasticsearchClient + ); + + expect(response).toEqual(expectedResponse); + + expect(mockClient.ingest.putPipeline).toHaveBeenCalledWith({ + id: 'my-index@ml-inference', + processors: [ + { + pipeline: { + name: 'my-ml-other-pipeline', + }, + }, + ], + }); + expect(mockClient.ingest.deletePipeline).not.toHaveBeenCalledWith({ + id: 'my-ml-pipeline', + }); + }); + + it('should fail when parent pipeline is missing', async () => { + mockClient.ingest.getPipeline.mockImplementation(() => Promise.reject(notFoundError)); + + await expect( + detachMlInferencePipeline( + 'my-index', + 'my-ml-pipeline', + mockClient as unknown as ElasticsearchClient + ) + ).rejects.toThrow(Error); + + expect(mockClient.ingest.getPipeline).toHaveBeenCalledWith({ + id: 'my-index@ml-inference', + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline.ts new file mode 100644 index 0000000000000..02d6c328a8e47 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline.ts @@ -0,0 +1,53 @@ +/* + * 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 { IngestPutPipelineRequest } from '@elastic/elasticsearch/lib/api/types'; +import { ElasticsearchClient } from '@kbn/core/server'; + +import { DeleteMlInferencePipelineResponse } from '../../../../../common/types/pipelines'; + +import { getInferencePipelineNameFromIndexName } from '../../../../utils/ml_inference_pipeline_utils'; + +export const detachMlInferencePipeline = async ( + indexName: string, + pipelineName: string, + client: ElasticsearchClient +) => { + const response: DeleteMlInferencePipelineResponse = {}; + const parentPipelineId = getInferencePipelineNameFromIndexName(indexName); + + // find parent pipeline + const pipelineResponse = await client.ingest.getPipeline({ + id: parentPipelineId, + }); + + const parentPipeline = pipelineResponse[parentPipelineId]; + + if (parentPipeline !== undefined) { + // remove sub-pipeline from parent pipeline + if (parentPipeline.processors !== undefined) { + const updatedProcessors = parentPipeline.processors.filter( + (p) => !(p.pipeline !== undefined && p.pipeline.name === pipelineName) + ); + // only update if we changed something + if (updatedProcessors.length !== parentPipeline.processors.length) { + const updatedPipeline: IngestPutPipelineRequest = { + ...parentPipeline, + id: parentPipelineId, + processors: updatedProcessors, + }; + + const updateResponse = await client.ingest.putPipeline(updatedPipeline); + if (updateResponse.acknowledged === true) { + response.updated = parentPipelineId; + } + } + } + } + + return response; +}; diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts index d0a652b12d9c2..1ad901330caff 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts @@ -20,25 +20,49 @@ jest.mock('../../lib/indices/fetch_ml_inference_pipeline_history', () => ({ jest.mock('../../lib/indices/fetch_ml_inference_pipeline_processors', () => ({ fetchMlInferencePipelineProcessors: jest.fn(), })); -jest.mock('../../utils/create_ml_inference_pipeline', () => ({ - createAndReferenceMlInferencePipeline: jest.fn(), -})); -jest.mock('../../lib/indices/delete_ml_inference_pipeline', () => ({ - deleteMlInferencePipeline: jest.fn(), -})); +jest.mock( + '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline', + () => ({ + createAndReferenceMlInferencePipeline: jest.fn(), + }) +); +jest.mock( + '../../lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline', + () => ({ + attachMlInferencePipeline: jest.fn(), + }) +); +jest.mock( + '../../lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline', + () => ({ + deleteMlInferencePipeline: jest.fn(), + }) +); +jest.mock( + '../../lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline', + () => ({ + detachMlInferencePipeline: jest.fn(), + }) +); jest.mock('../../lib/indices/exists_index', () => ({ indexOrAliasExists: jest.fn(), })); jest.mock('../../lib/ml_inference_pipeline/get_inference_errors', () => ({ getMlInferenceErrors: jest.fn(), })); +jest.mock('../../lib/ml_inference_pipeline/get_inference_pipelines', () => ({ + getMlInferencePipelines: jest.fn(), +})); -import { deleteMlInferencePipeline } from '../../lib/indices/delete_ml_inference_pipeline'; import { indexOrAliasExists } from '../../lib/indices/exists_index'; import { fetchMlInferencePipelineHistory } from '../../lib/indices/fetch_ml_inference_pipeline_history'; import { fetchMlInferencePipelineProcessors } from '../../lib/indices/fetch_ml_inference_pipeline_processors'; +import { attachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline'; +import { createAndReferenceMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline'; import { getMlInferenceErrors } from '../../lib/ml_inference_pipeline/get_inference_errors'; -import { createAndReferenceMlInferencePipeline } from '../../utils/create_ml_inference_pipeline'; +import { getMlInferencePipelines } from '../../lib/ml_inference_pipeline/get_inference_pipelines'; +import { deleteMlInferencePipeline } from '../../lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline'; +import { detachMlInferencePipeline } from '../../lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline'; import { ElasticsearchResponseError } from '../../utils/identify_exceptions'; import { registerIndexRoutes } from './indices'; @@ -275,8 +299,8 @@ describe('Enterprise Search Managed Indices', () => { }); await mockRouter.callRoute({ - params: { indexName: 'my-index-name' }, body: mockRequestBody, + params: { indexName: 'my-index-name' }, }); expect(mockRouter.response.customError).toHaveBeenCalledWith( @@ -287,6 +311,67 @@ describe('Enterprise Search Managed Indices', () => { }); }); + describe('POST /internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/attach', () => { + const pipelineName = 'some-pipeline'; + const indexName = 'some-index'; + + beforeEach(() => { + const context = { + core: Promise.resolve(mockCore), + } as unknown as jest.Mocked; + + mockRouter = new MockRouter({ + context, + method: 'post', + path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/attach', + }); + + registerIndexRoutes({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('fails validation without pipeline name on body', () => { + const request = { + body: {}, + params: { indexName }, + }; + mockRouter.shouldThrow(request); + }); + + it('fails validation without index name', () => { + const request = { + body: {}, + params: { pipelineName }, + }; + mockRouter.shouldThrow(request); + }); + + it('attaches an ML inference pipeline', async () => { + (attachMlInferencePipeline as jest.Mock).mockImplementationOnce(() => + Promise.resolve({ + addedToParentPipeline: true, + created: false, + id: 'ml-inference-my-pipeline-name', + }) + ); + + await mockRouter.callRoute({ body: { pipeline_name: pipelineName }, params: { indexName } }); + + expect(mockRouter.response.ok).toHaveBeenLastCalledWith({ + body: { + addedToParentPipeline: true, + created: false, + id: 'ml-inference-my-pipeline-name', + }, + headers: { + 'content-type': 'application/json', + }, + }); + }); + }); + describe('DELETE /internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/{pipelineName}', () => { const indexName = 'my-index'; const pipelineName = 'my-pipeline'; @@ -642,4 +727,140 @@ describe('Enterprise Search Managed Indices', () => { }); }); }); + + describe('DELETE /internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/{pipelineName}/detach', () => { + const indexName = 'my-index'; + const pipelineName = 'my-pipeline'; + + beforeEach(() => { + const context = { + core: Promise.resolve(mockCore), + } as unknown as jest.Mocked; + + mockRouter = new MockRouter({ + context, + method: 'delete', + path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/{pipelineName}/detach', + }); + + registerIndexRoutes({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('fails validation without index_name', () => { + const request = { params: {} }; + mockRouter.shouldThrow(request); + }); + + it('detaches pipeline', async () => { + const mockResponse = { updated: `${indexName}@ml-inference` }; + + (detachMlInferencePipeline as jest.Mock).mockImplementationOnce(() => { + return Promise.resolve(mockResponse); + }); + + await mockRouter.callRoute({ + params: { indexName, pipelineName }, + }); + + expect(detachMlInferencePipeline).toHaveBeenCalledWith( + indexName, + pipelineName, + mockClient.asCurrentUser + ); + + expect(mockRouter.response.ok).toHaveBeenCalledWith({ + body: mockResponse, + headers: { 'content-type': 'application/json' }, + }); + }); + + it('raises error if detaching failed', async () => { + const errorReason = `pipeline is missing: [${pipelineName}]`; + const mockError = new Error(errorReason) as ElasticsearchResponseError; + mockError.meta = { + body: { + error: { + type: 'resource_not_found_exception', + }, + }, + }; + (detachMlInferencePipeline as jest.Mock).mockImplementationOnce(() => { + return Promise.reject(mockError); + }); + + await mockRouter.callRoute({ + params: { indexName, pipelineName }, + }); + + expect(detachMlInferencePipeline).toHaveBeenCalledWith( + indexName, + pipelineName, + mockClient.asCurrentUser + ); + expect(mockRouter.response.customError).toHaveBeenCalledTimes(1); + }); + }); + + describe('GET /internal/enterprise_search/pipelines/ml_inference', () => { + let mockTrainedModelsProvider: MlTrainedModels; + let mockMl: SharedServices; + + beforeEach(() => { + const context = { + core: Promise.resolve(mockCore), + } as unknown as jest.Mocked; + + mockRouter = new MockRouter({ + context, + method: 'get', + path: '/internal/enterprise_search/pipelines/ml_inference', + }); + + mockTrainedModelsProvider = { + getTrainedModels: jest.fn(), + getTrainedModelsStats: jest.fn(), + } as MlTrainedModels; + + mockMl = { + trainedModelsProvider: () => Promise.resolve(mockTrainedModelsProvider), + } as unknown as jest.Mocked; + + registerIndexRoutes({ + ...mockDependencies, + router: mockRouter.router, + ml: mockMl, + }); + }); + + it('fetches ML inference pipelines', async () => { + const pipelinesResult = { + pipeline1: { + processors: [], + }, + pipeline2: { + processors: [], + }, + pipeline3: { + processors: [], + }, + }; + + (getMlInferencePipelines as jest.Mock).mockResolvedValueOnce(pipelinesResult); + + await mockRouter.callRoute({}); + + expect(getMlInferencePipelines).toHaveBeenCalledWith( + mockClient.asCurrentUser, + mockTrainedModelsProvider + ); + + expect(mockRouter.response.ok).toHaveBeenCalledWith({ + body: pipelinesResult, + headers: { 'content-type': 'application/json' }, + }); + }); + }); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts index e1d2f0238740c..ee497ba671faf 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts @@ -16,29 +16,35 @@ import { i18n } from '@kbn/i18n'; import { DEFAULT_PIPELINE_NAME } from '../../../common/constants'; import { ErrorCode } from '../../../common/types/error_codes'; + +import type { + CreateMlInferencePipelineResponse, + AttachMlInferencePipelineResponse, +} from '../../../common/types/pipelines'; + import { deleteConnectorById } from '../../lib/connectors/delete_connector'; import { fetchConnectorByIndexName, fetchConnectors } from '../../lib/connectors/fetch_connectors'; import { fetchCrawlerByIndexName, fetchCrawlers } from '../../lib/crawler/fetch_crawlers'; import { createIndex } from '../../lib/indices/create_index'; -import { deleteMlInferencePipeline } from '../../lib/indices/delete_ml_inference_pipeline'; import { indexOrAliasExists } from '../../lib/indices/exists_index'; import { fetchIndex } from '../../lib/indices/fetch_index'; import { fetchIndices } from '../../lib/indices/fetch_indices'; import { fetchMlInferencePipelineHistory } from '../../lib/indices/fetch_ml_inference_pipeline_history'; import { fetchMlInferencePipelineProcessors } from '../../lib/indices/fetch_ml_inference_pipeline_processors'; import { generateApiKey } from '../../lib/indices/generate_api_key'; +import { attachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/attach_ml_pipeline'; +import { createAndReferenceMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/create_ml_inference_pipeline'; import { getMlInferenceErrors } from '../../lib/ml_inference_pipeline/get_inference_errors'; +import { getMlInferencePipelines } from '../../lib/ml_inference_pipeline/get_inference_pipelines'; import { createIndexPipelineDefinitions } from '../../lib/pipelines/create_pipeline_definitions'; import { getCustomPipelines } from '../../lib/pipelines/get_custom_pipelines'; import { getPipeline } from '../../lib/pipelines/get_pipeline'; +import { deleteMlInferencePipeline } from '../../lib/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline'; +import { detachMlInferencePipeline } from '../../lib/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline'; import { RouteDependencies } from '../../plugin'; import { createError } from '../../utils/create_error'; -import { - createAndReferenceMlInferencePipeline, - CreatedPipeline, -} from '../../utils/create_ml_inference_pipeline'; import { elasticsearchErrorHandler } from '../../utils/elasticsearch_error_handler'; import { isIndexNotFoundException, @@ -353,10 +359,10 @@ export function registerIndexRoutes({ indexName: schema.string(), }), body: schema.object({ - pipeline_name: schema.string(), + destination_field: schema.maybe(schema.nullable(schema.string())), model_id: schema.string(), + pipeline_name: schema.string(), source_field: schema.string(), - destination_field: schema.maybe(schema.nullable(schema.string())), }), }, }, @@ -371,7 +377,7 @@ export function registerIndexRoutes({ destination_field: destinationField, } = request.body; - let createPipelineResult: CreatedPipeline | undefined; + let createPipelineResult: CreateMlInferencePipelineResponse | undefined; try { // Create the sub-pipeline for inference createPipelineResult = await createAndReferenceMlInferencePipeline( @@ -409,6 +415,45 @@ export function registerIndexRoutes({ }) ); + router.post( + { + path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/attach', + validate: { + body: schema.object({ + pipeline_name: schema.string(), + }), + params: schema.object({ + indexName: schema.string(), + }), + }, + }, + + elasticsearchErrorHandler(log, async (context, request, response) => { + const indexName = decodeURIComponent(request.params.indexName); + const { client } = (await context.core).elasticsearch; + const { pipeline_name: pipelineName } = request.body; + + let attachMlInferencePipelineResult: AttachMlInferencePipelineResponse | undefined; + try { + attachMlInferencePipelineResult = await attachMlInferencePipeline( + indexName, + pipelineName, + client.asCurrentUser + ); + } catch (error) { + throw error; + } + + return response.ok({ + body: { + ...attachMlInferencePipelineResult, + created: false, + }, + headers: { 'content-type': 'application/json' }, + }); + }) + ); + router.post( { path: '/internal/enterprise_search/indices', @@ -680,4 +725,69 @@ export function registerIndexRoutes({ }); }) ); + + router.get( + { + path: '/internal/enterprise_search/pipelines/ml_inference', + validate: {}, + }, + elasticsearchErrorHandler(log, async (context, request, response) => { + const { + elasticsearch: { client }, + savedObjects: { client: savedObjectsClient }, + } = await context.core; + const trainedModelsProvider = ml + ? await ml.trainedModelsProvider(request, savedObjectsClient) + : undefined; + + const pipelines = await getMlInferencePipelines(client.asCurrentUser, trainedModelsProvider); + + return response.ok({ + body: pipelines, + headers: { 'content-type': 'application/json' }, + }); + }) + ); + + router.delete( + { + path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/{pipelineName}/detach', + validate: { + params: schema.object({ + indexName: schema.string(), + pipelineName: schema.string(), + }), + }, + }, + elasticsearchErrorHandler(log, async (context, request, response) => { + const indexName = decodeURIComponent(request.params.indexName); + const pipelineName = decodeURIComponent(request.params.pipelineName); + const { client } = (await context.core).elasticsearch; + + try { + const detachResult = await detachMlInferencePipeline( + indexName, + pipelineName, + client.asCurrentUser + ); + + return response.ok({ + body: detachResult, + headers: { 'content-type': 'application/json' }, + }); + } catch (error) { + if (isResourceNotFoundException(error)) { + // return specific message if pipeline doesn't exist + return createError({ + errorCode: ErrorCode.RESOURCE_NOT_FOUND, + message: error.meta?.body?.error?.reason, + response, + statusCode: 404, + }); + } + // otherwise, let the default handler wrap it + throw error; + } + }) + ); } diff --git a/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.test.ts b/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.test.ts index d3aa24560594d..d1d031b31cfb9 100644 --- a/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.test.ts +++ b/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.test.ts @@ -7,14 +7,8 @@ import { ElasticsearchClient } from '@kbn/core/server'; -import { - createMlInferencePipeline, - addSubPipelineToIndexSpecificMlPipeline, -} from './create_ml_inference_pipeline'; -import { - getInferencePipelineNameFromIndexName, - getPrefixedInferencePipelineProcessorName, -} from './ml_inference_pipeline_utils'; +import { addSubPipelineToIndexSpecificMlPipeline } from './create_ml_inference_pipeline'; +import { getInferencePipelineNameFromIndexName } from './ml_inference_pipeline_utils'; const mockClient = { ingest: { @@ -26,112 +20,6 @@ const mockClient = { }, }; -describe('createMlInferencePipeline util function', () => { - const pipelineName = 'my-pipeline'; - const modelId = 'my-model-id'; - const sourceField = 'my-source-field'; - const destinationField = 'my-dest-field'; - const inferencePipelineGeneratedName = getPrefixedInferencePipelineProcessorName(pipelineName); - - mockClient.ml.getTrainedModels.mockImplementation(() => - Promise.resolve({ - trained_model_configs: [ - { - input: { - field_names: ['target-field'], - }, - }, - ], - }) - ); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("should create the pipeline if it doesn't exist", async () => { - mockClient.ingest.getPipeline.mockImplementation(() => Promise.reject({ statusCode: 404 })); // Pipeline does not exist - mockClient.ingest.putPipeline.mockImplementation(() => Promise.resolve({ acknowledged: true })); - - const expectedResult = { - created: true, - id: inferencePipelineGeneratedName, - }; - - const actualResult = await createMlInferencePipeline( - pipelineName, - modelId, - sourceField, - destinationField, - mockClient as unknown as ElasticsearchClient - ); - - expect(actualResult).toEqual(expectedResult); - expect(mockClient.ingest.putPipeline).toHaveBeenCalled(); - }); - - it('should convert spaces to underscores in the pipeline name', async () => { - await createMlInferencePipeline( - 'my pipeline with spaces ', - modelId, - sourceField, - destinationField, - mockClient as unknown as ElasticsearchClient - ); - - expect(mockClient.ingest.putPipeline).toHaveBeenCalledWith( - expect.objectContaining({ - id: 'ml-inference-my_pipeline_with_spaces', - }) - ); - }); - - it('should default the destination field to the pipeline name', async () => { - mockClient.ingest.getPipeline.mockImplementation(() => Promise.reject({ statusCode: 404 })); // Pipeline does not exist - mockClient.ingest.putPipeline.mockImplementation(() => Promise.resolve({ acknowledged: true })); - - await createMlInferencePipeline( - pipelineName, - modelId, - sourceField, - undefined, // Omitted destination field - mockClient as unknown as ElasticsearchClient - ); - - // Verify the object passed to pipeline creation contains the default target field name - expect(mockClient.ingest.putPipeline).toHaveBeenCalledWith( - expect.objectContaining({ - processors: expect.arrayContaining([ - expect.objectContaining({ - inference: expect.objectContaining({ - target_field: `ml.inference.${pipelineName}`, - }), - }), - ]), - }) - ); - }); - - it('should throw an error without creating the pipeline if it already exists', () => { - mockClient.ingest.getPipeline.mockImplementation(() => - Promise.resolve({ - [inferencePipelineGeneratedName]: {}, - }) - ); // Pipeline exists - - const actualResult = createMlInferencePipeline( - pipelineName, - modelId, - sourceField, - destinationField, - mockClient as unknown as ElasticsearchClient - ); - - expect(actualResult).rejects.toThrow(Error); - expect(mockClient.ingest.putPipeline).not.toHaveBeenCalled(); - }); -}); - describe('addSubPipelineToIndexSpecificMlPipeline util function', () => { const indexName = 'my-index'; const parentPipelineId = getInferencePipelineNameFromIndexName(indexName); @@ -151,8 +39,8 @@ describe('addSubPipelineToIndexSpecificMlPipeline util function', () => { ); const expectedResult = { - id: pipelineName, addedToParentPipeline: true, + id: pipelineName, }; const actualResult = await addSubPipelineToIndexSpecificMlPipeline( @@ -179,8 +67,8 @@ describe('addSubPipelineToIndexSpecificMlPipeline util function', () => { mockClient.ingest.getPipeline.mockImplementation(() => Promise.reject({ statusCode: 404 })); // Pipeline does not exist const expectedResult = { - id: pipelineName, addedToParentPipeline: false, + id: pipelineName, }; const actualResult = await addSubPipelineToIndexSpecificMlPipeline( @@ -210,8 +98,8 @@ describe('addSubPipelineToIndexSpecificMlPipeline util function', () => { ); const expectedResult = { - id: pipelineName, addedToParentPipeline: false, + id: pipelineName, }; const actualResult = await addSubPipelineToIndexSpecificMlPipeline( diff --git a/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.ts b/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.ts index da4bce12d71ef..2562aa7156ffe 100644 --- a/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.ts +++ b/x-pack/plugins/enterprise_search/server/utils/create_ml_inference_pipeline.ts @@ -5,115 +5,12 @@ * 2.0. */ -import { IngestGetPipelineResponse, IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; +import { IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; import { ElasticsearchClient } from '@kbn/core/server'; -import { formatPipelineName } from '../../common/ml_inference_pipeline'; -import { ErrorCode } from '../../common/types/error_codes'; +import type { AttachMlInferencePipelineResponse } from '../../common/types/pipelines'; -import { formatMlPipelineBody } from '../lib/pipelines/create_pipeline_definitions'; - -import { - getInferencePipelineNameFromIndexName, - getPrefixedInferencePipelineProcessorName, -} from './ml_inference_pipeline_utils'; - -/** - * Details of a created pipeline. - */ -export interface CreatedPipeline { - id: string; - created?: boolean; - addedToParentPipeline?: boolean; -} - -/** - * Creates a Machine Learning Inference pipeline with the given settings, if it doesn't exist yet, - * then references it in the "parent" ML Inference pipeline that is associated with the index. - * @param indexName name of the index this pipeline corresponds to. - * @param pipelineName pipeline name set by the user. - * @param modelId model ID selected by the user. - * @param sourceField The document field that model will read. - * @param destinationField The document field that the model will write to. - * @param esClient the Elasticsearch Client to use when retrieving pipeline and model details. - */ -export const createAndReferenceMlInferencePipeline = async ( - indexName: string, - pipelineName: string, - modelId: string, - sourceField: string, - destinationField: string | null | undefined, - esClient: ElasticsearchClient -): Promise => { - const createPipelineResult = await createMlInferencePipeline( - pipelineName, - modelId, - sourceField, - destinationField, - esClient - ); - - const addSubPipelineResult = await addSubPipelineToIndexSpecificMlPipeline( - indexName, - createPipelineResult.id, - esClient - ); - - return Promise.resolve({ - ...createPipelineResult, - addedToParentPipeline: addSubPipelineResult.addedToParentPipeline, - }); -}; - -/** - * Creates a Machine Learning Inference pipeline with the given settings, if it doesn't exist yet. - * @param pipelineName pipeline name set by the user. - * @param modelId model ID selected by the user. - * @param sourceField The document field that model will read. - * @param destinationField The document field that the model will write to. - * @param esClient the Elasticsearch Client to use when retrieving pipeline and model details. - */ -export const createMlInferencePipeline = async ( - pipelineName: string, - modelId: string, - sourceField: string, - destinationField: string | null | undefined, - esClient: ElasticsearchClient -): Promise => { - const inferencePipelineGeneratedName = getPrefixedInferencePipelineProcessorName(pipelineName); - - // Check that a pipeline with the same name doesn't already exist - let pipelineByName: IngestGetPipelineResponse | undefined; - try { - pipelineByName = await esClient.ingest.getPipeline({ - id: inferencePipelineGeneratedName, - }); - } catch (error) { - // Silently swallow error - } - if (pipelineByName?.[inferencePipelineGeneratedName]) { - throw new Error(ErrorCode.PIPELINE_ALREADY_EXISTS); - } - - // Generate pipeline with default processors - const mlInferencePipeline = await formatMlPipelineBody( - inferencePipelineGeneratedName, - modelId, - sourceField, - destinationField || formatPipelineName(pipelineName), - esClient - ); - - await esClient.ingest.putPipeline({ - id: inferencePipelineGeneratedName, - ...mlInferencePipeline, - }); - - return Promise.resolve({ - id: inferencePipelineGeneratedName, - created: true, - }); -}; +import { getInferencePipelineNameFromIndexName } from './ml_inference_pipeline_utils'; /** * Adds the supplied a Machine Learning Inference pipeline reference to the "parent" ML Inference @@ -126,7 +23,7 @@ export const addSubPipelineToIndexSpecificMlPipeline = async ( indexName: string, pipelineName: string, esClient: ElasticsearchClient -): Promise => { +): Promise => { const parentPipelineId = getInferencePipelineNameFromIndexName(indexName); // Fetch the parent pipeline @@ -143,8 +40,8 @@ export const addSubPipelineToIndexSpecificMlPipeline = async ( // Verify the parent pipeline exists with a processors array if (!parentPipeline?.processors) { return Promise.resolve({ - id: pipelineName, addedToParentPipeline: false, + id: pipelineName, }); } @@ -155,8 +52,8 @@ export const addSubPipelineToIndexSpecificMlPipeline = async ( ); if (existingSubPipeline) { return Promise.resolve({ - id: pipelineName, addedToParentPipeline: false, + id: pipelineName, }); } @@ -173,7 +70,7 @@ export const addSubPipelineToIndexSpecificMlPipeline = async ( }); return Promise.resolve({ - id: pipelineName, addedToParentPipeline: true, + id: pipelineName, }); }; diff --git a/x-pack/plugins/files/server/mocks.ts b/x-pack/plugins/files/server/mocks.ts index 033e94c3bfd7f..de9a495818ff2 100644 --- a/x-pack/plugins/files/server/mocks.ts +++ b/x-pack/plugins/files/server/mocks.ts @@ -6,7 +6,9 @@ */ import { KibanaRequest } from '@kbn/core/server'; import { DeeplyMockedKeys } from '@kbn/utility-types-jest'; -import { FileServiceFactory, FileServiceStart } from '.'; +import * as stream from 'stream'; +import { File } from '../common'; +import { FileClient, FileServiceFactory, FileServiceStart } from '.'; export const createFileServiceMock = (): DeeplyMockedKeys => ({ create: jest.fn(), @@ -26,3 +28,51 @@ export const createFileServiceFactoryMock = (): DeeplyMockedKeys createFileServiceMock()), }); + +export const createFileMock = (): DeeplyMockedKeys => { + const fileMock: DeeplyMockedKeys = { + id: '123', + data: { + id: '123', + created: '2022-10-10T14:57:30.682Z', + updated: '2022-10-19T14:43:20.112Z', + name: 'test.txt', + mimeType: 'text/plain', + size: 1234, + extension: '.txt', + meta: {}, + alt: undefined, + fileKind: 'none', + status: 'READY', + }, + update: jest.fn(), + uploadContent: jest.fn(), + downloadContent: jest.fn().mockResolvedValue(new stream.Readable()), + delete: jest.fn(), + share: jest.fn(), + listShares: jest.fn(), + unshare: jest.fn(), + toJSON: jest.fn(), + }; + + fileMock.update.mockResolvedValue(fileMock); + fileMock.uploadContent.mockResolvedValue(fileMock); + + return fileMock; +}; + +export const createFileClientMock = (): DeeplyMockedKeys => { + const fileMock = createFileMock(); + + return { + fileKind: 'none', + create: jest.fn().mockResolvedValue(fileMock), + get: jest.fn().mockResolvedValue(fileMock), + update: jest.fn(), + delete: jest.fn(), + find: jest.fn().mockResolvedValue({ files: [fileMock], total: 1 }), + share: jest.fn(), + unshare: jest.fn(), + listShares: jest.fn().mockResolvedValue({ shares: [] }), + }; +}; diff --git a/x-pack/plugins/fleet/.storybook/context/stubs.tsx b/x-pack/plugins/fleet/.storybook/context/stubs.tsx index 092ab680b819f..fd8612aca6611 100644 --- a/x-pack/plugins/fleet/.storybook/context/stubs.tsx +++ b/x-pack/plugins/fleet/.storybook/context/stubs.tsx @@ -11,6 +11,7 @@ type Stubs = | 'licensing' | 'storage' | 'data' + | 'dataViews' | 'unifiedSearch' | 'deprecations' | 'fatalErrors' @@ -24,6 +25,7 @@ export const stubbedStartServices: StubbedStartServices = { licensing: {} as FleetStartServices['licensing'], storage: {} as FleetStartServices['storage'], data: {} as FleetStartServices['data'], + dataViews: {} as FleetStartServices['dataViews'], unifiedSearch: {} as FleetStartServices['unifiedSearch'], deprecations: {} as FleetStartServices['deprecations'], fatalErrors: {} as FleetStartServices['fatalErrors'], diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx index 6e9aea1d8d2d2..663ebf1aaeb49 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx @@ -45,6 +45,7 @@ export const SearchBar: React.FunctionComponent = ({ }) => { const { data, + dataViews, unifiedSearch, storage, notifications, @@ -131,6 +132,7 @@ export const SearchBar: React.FunctionComponent = ({ docLinks, uiSettings, data, + dataViews, storage, usageCollection, }} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx index 166387780f8cc..684a00eb59e32 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx @@ -28,7 +28,7 @@ export const LogQueryBar: React.FunctionComponent<{ isQueryValid: boolean; onUpdateQuery: (query: string, runQuery?: boolean) => void; }> = memo(({ query, isQueryValid, onUpdateQuery }) => { - const { data, notifications, http, docLinks, uiSettings, unifiedSearch, storage } = + const { data, notifications, http, docLinks, uiSettings, unifiedSearch, storage, dataViews } = useStartServices(); const [indexPatternFields, setIndexPatternFields] = useState(); @@ -81,7 +81,7 @@ export const LogQueryBar: React.FunctionComponent<{ onUpdateQuery(newQuery.query as string, true); }} appName={i18n.translate('xpack.fleet.appTitle', { defaultMessage: 'Fleet' })} - deps={{ unifiedSearch, notifications, http, docLinks, uiSettings, data, storage }} + deps={{ unifiedSearch, notifications, http, docLinks, uiSettings, data, dataViews, storage }} /> ); }); diff --git a/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts b/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts index 3f5ce4a53d1f8..250fb934493c0 100644 --- a/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts +++ b/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts @@ -7,6 +7,7 @@ import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; import { homePluginMock } from '@kbn/home-plugin/public/mocks'; @@ -28,6 +29,7 @@ export const createStartDepsMock = () => { return { licensing: licensingMock.createStart(), data: dataPluginMock.createStartContract(), + dataViews: dataViewPluginMocks.createStartContract(), unifiedSearch: unifiedSearchPluginMock.createStartContract(), navigation: navigationPluginMock.createStartContract(), customIntegrations: customIntegrationsMock.createStart(), diff --git a/x-pack/plugins/fleet/public/plugin.ts b/x-pack/plugins/fleet/public/plugin.ts index 3590a80037b1f..6d41e4073afa0 100644 --- a/x-pack/plugins/fleet/public/plugin.ts +++ b/x-pack/plugins/fleet/public/plugin.ts @@ -37,6 +37,7 @@ import type { import { DEFAULT_APP_CATEGORIES, AppNavLinkStatus } from '@kbn/core/public'; import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; @@ -96,6 +97,7 @@ export interface FleetSetupDeps { export interface FleetStartDeps { licensing: LicensingPluginStart; data: DataPublicPluginStart; + dataViews: DataViewsPublicPluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; navigation: NavigationPublicPluginStart; customIntegrations: CustomIntegrationsStart; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index 62b6083769866..92ea60d290040 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -51,7 +51,7 @@ export type ArchiveAsset = Pick< // KibanaSavedObjectTypes are used to ensure saved objects being created for a given // KibanaAssetType have the correct type -const KibanaSavedObjectTypeMapping: Record = { +export const KibanaSavedObjectTypeMapping: Record = { [KibanaAssetType.dashboard]: KibanaSavedObjectType.dashboard, [KibanaAssetType.indexPattern]: KibanaSavedObjectType.indexPattern, [KibanaAssetType.map]: KibanaSavedObjectType.map, diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts index 33f674d226e89..3c946217d36b4 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts @@ -94,6 +94,8 @@ describe('tagKibanaAssets', () => { search: [{ id: 's1', type: 'search' }], config: [{ id: 'c1', type: 'config' }], visualization: [{ id: 'v1', type: 'visualization' }], + osquery_pack_asset: [{ id: 'osquery-pack-asset1', type: 'osquery-pack-asset' }], + osquery_saved_query: [{ id: 'osquery_saved_query1', type: 'osquery_saved_query' }], } as any; await tagKibanaAssets({ @@ -106,7 +108,13 @@ describe('tagKibanaAssets', () => { expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ tags: ['managed', 'system'], - assign: [...kibanaAssets.dashboard, ...kibanaAssets.search, ...kibanaAssets.visualization], + assign: [ + ...kibanaAssets.dashboard, + ...kibanaAssets.search, + ...kibanaAssets.visualization, + ...kibanaAssets.osquery_pack_asset, + ...kibanaAssets.osquery_saved_query, + ], unassign: [], refresh: false, }); diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts index 53a6df568a8c0..842932d71359e 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts @@ -11,6 +11,7 @@ import type { IAssignmentService, ITagsClient } from '@kbn/saved-objects-tagging import type { KibanaAssetType } from '../../../../../common'; import type { ArchiveAsset } from './install'; +import { KibanaSavedObjectTypeMapping } from './install'; const TAG_COLOR = '#FFFFFF'; const MANAGED_TAG_NAME = 'Managed'; @@ -30,7 +31,7 @@ export async function tagKibanaAssets({ pkgName: string; }) { const taggableAssets = Object.entries(kibanaAssets).flatMap(([assetType, assets]) => { - if (!taggableTypes.includes(assetType as KibanaAssetType)) { + if (!taggableTypes.includes(KibanaSavedObjectTypeMapping[assetType as KibanaAssetType])) { return []; } diff --git a/x-pack/plugins/fleet/server/services/fleet_usage_sender.ts b/x-pack/plugins/fleet/server/services/fleet_usage_sender.ts index b7ab806e5f8c1..ada764fcff927 100644 --- a/x-pack/plugins/fleet/server/services/fleet_usage_sender.ts +++ b/x-pack/plugins/fleet/server/services/fleet_usage_sender.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -/* eslint-disable max-classes-per-file */ import type { ConcreteTaskInstance, TaskManagerStartContract, @@ -12,15 +11,11 @@ import type { } from '@kbn/task-manager-plugin/server'; import type { CoreSetup } from '@kbn/core/server'; -import { ElasticV3ServerShipper } from '@kbn/analytics-shippers-elastic-v3-server'; - import type { Usage } from '../collectors/register'; import { appContextService } from './app_context'; -export class FleetShipper extends ElasticV3ServerShipper { - public static shipperName = 'fleet_shipper'; -} +const EVENT_TYPE = 'fleet_usage'; export class FleetUsageSender { private taskManager?: TaskManagerStartContract; @@ -47,7 +42,7 @@ export class FleetUsageSender { try { const usageData = await fetchUsage(); appContextService.getLogger().debug(JSON.stringify(usageData)); - core.analytics.reportEvent('Fleet Usage', usageData); + core.analytics.reportEvent(EVENT_TYPE, usageData); } catch (error) { appContextService .getLogger() @@ -61,12 +56,6 @@ export class FleetUsageSender { }, }); this.registerTelemetryEventType(core); - - core.analytics.registerShipper(FleetShipper, { - channelName: 'fleet-usages', - version: kibanaVersion, - sendTo: isProductionMode ? 'production' : 'staging', - }); } public async start(taskManager: TaskManagerStartContract) { @@ -90,7 +79,7 @@ export class FleetUsageSender { */ private registerTelemetryEventType(core: CoreSetup): void { core.analytics.registerEventType({ - eventType: 'Fleet Usage', + eventType: EVENT_TYPE, schema: { agents_enabled: { type: 'boolean', _meta: { description: 'agents enabled' } }, agents: { diff --git a/x-pack/plugins/graph/public/components/search_bar.tsx b/x-pack/plugins/graph/public/components/search_bar.tsx index 28e5c5a8337e8..c3e846adffbd3 100644 --- a/x-pack/plugins/graph/public/components/search_bar.tsx +++ b/x-pack/plugins/graph/public/components/search_bar.tsx @@ -103,6 +103,7 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps) appName, unifiedSearch, data, + dataViews, storage, notifications, http, @@ -176,6 +177,7 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps) deps={{ unifiedSearch, data, + dataViews, storage, notifications, http, diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page_toolbar.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page_toolbar.tsx index 440edcbdd6c0e..210def8f8844c 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page_toolbar.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page_toolbar.tsx @@ -32,7 +32,7 @@ export const LogsToolbar = () => { const { filterQueryDraft, isFilterQueryDraftValid, applyLogFilterQuery, setLogFilterQueryDraft } = useLogFilterStateContext(); const { setSurroundingLogsId } = useLogEntryFlyoutContext(); - const { http, notifications, docLinks, uiSettings, data, storage, unifiedSearch } = + const { http, notifications, docLinks, uiSettings, data, dataViews, storage, unifiedSearch } = useKibanaContextForPlugin().services; const { @@ -77,7 +77,16 @@ export const LogsToolbar = () => { appName={i18n.translate('xpack.infra.appName', { defaultMessage: 'Infra logs', })} - deps={{ unifiedSearch, notifications, http, docLinks, uiSettings, data, storage }} + deps={{ + unifiedSearch, + notifications, + http, + docLinks, + uiSettings, + data, + dataViews, + storage, + }} /> diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts index e8ac68460beb9..3f30dff6fd1a7 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts @@ -1675,6 +1675,29 @@ describe('IndexPattern Data Source', () => { }, }); }); + + it('should remove linked layers', () => { + const state = { + layers: { + first: { + indexPatternId: '1', + columnOrder: [], + columns: {}, + }, + second: { + indexPatternId: '2', + columnOrder: [], + columns: {}, + linkToLayers: ['first'], + }, + }, + currentIndexPatternId: '1', + }; + expect(FormBasedDatasource.removeLayer(state, 'first')).toEqual({ + ...state, + layers: {}, + }); + }); }); describe('#createEmptyLayer', () => { diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx index d41218f785d9b..62c77ec5225fe 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx @@ -219,6 +219,14 @@ export function getFormBasedDatasource({ const newLayers = { ...state.layers }; delete newLayers[layerId]; + // delete layers linked to this layer + Object.keys(newLayers).forEach((id) => { + const linkedLayers = newLayers[id]?.linkToLayers; + if (linkedLayers && linkedLayers.includes(layerId)) { + delete newLayers[id]; + } + }); + return { ...state, layers: newLayers, diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula.scss b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula.scss index 493f3525ec604..2b1753ebef1b3 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula.scss +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula.scss @@ -33,10 +33,6 @@ padding: $euiSizeS; } -.lnsFormula__docsHeader { - margin: 0; -} - .lnsFormula__editorFooter { // make sure docs are rendered in front of monaco z-index: 1; @@ -98,76 +94,6 @@ background: $euiColorEmptyShade; } -.lnsFormula__docs--inline { - display: flex; - flex-direction: column; - // make sure docs are rendered in front of monaco - z-index: 1; -} - -.lnsFormula__docsContent { - .lnsFormula__docs--overlay & { - height: 40vh; - width: #{'min(75vh, 90vw)'}; - } - - .lnsFormula__docs--inline & { - flex: 1; - min-height: 0; - } - - & > * + * { - border-left: $euiBorderThin; - } -} - -.lnsFormula__docsSidebar { - background: $euiColorLightestShade; -} - -.lnsFormula__docsSidebarInner { - min-height: 0; - - & > * + * { - border-top: $euiBorderThin; - } -} - -.lnsFormula__docsSearch { - padding: $euiSize; -} - -.lnsFormula__docsNav { - @include euiYScroll; -} - -.lnsFormula__docsNavGroup { - padding: $euiSize; - - & + & { - border-top: $euiBorderThin; - } -} - -.lnsFormula__docsNavGroupLink { - font-weight: inherit; -} - -.lnsFormula__docsText { - @include euiYScroll; - padding: $euiSize; -} - -.lnsFormula__docsTextGroup, -.lnsFormula__docsTextItem { - margin-top: $euiSizeXXL; -} - -.lnsFormula__docsTextGroup { - border-top: $euiBorderThin; - padding-top: $euiSizeXXL; -} - .lnsFormulaOverflow { // Needs to be higher than the modal and all flyouts z-index: $euiZLevel9 + 1; diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_editor.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_editor.tsx index fa293a57903fc..7fa1a5edb4f7d 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_editor.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_editor.tsx @@ -7,6 +7,10 @@ import React, { useCallback, useEffect, useState, useMemo, useRef } from 'react'; import { i18n } from '@kbn/i18n'; +import { + LanguageDocumentationPopover, + LanguageDocumentationPopoverContent, +} from '@kbn/language-documentation-popover'; import { css } from '@emotion/react'; import { EuiButtonIcon, @@ -27,7 +31,7 @@ import { monaco } from '@kbn/monaco'; import classNames from 'classnames'; import { CodeEditor } from '@kbn/kibana-react-plugin/public'; import type { CodeEditorProps } from '@kbn/kibana-react-plugin/public'; -import { TooltipWrapper, useDebounceWithOptions } from '../../../../../../shared_components'; +import { useDebounceWithOptions } from '../../../../../../shared_components'; import { ParamEditorProps } from '../..'; import { getManagedColumnsFrom } from '../../../layer_helpers'; import { ErrorWrapper, runASTValidation, tryToParse } from '../validation'; @@ -45,13 +49,13 @@ import { MARKER, } from './math_completion'; import { LANGUAGE_ID } from './math_tokenization'; -import { MemoizedFormulaHelp } from './formula_help'; import './formula.scss'; import { FormulaIndexPatternColumn } from '../formula'; import { insertOrReplaceFormulaColumn } from '../parse'; import { filterByVisibleOperation, nonNullable } from '../util'; import { getColumnTimeShiftWarnings, getDateHistogramInterval } from '../../../../time_shift_utils'; +import { getDocumentationSections } from './formula_help'; function tableHasData( activeData: ParamEditorProps['activeData'], @@ -126,6 +130,15 @@ export function FormulaEditor({ [operationDefinitionMap] ); + const documentationSections = useMemo( + () => + getDocumentationSections({ + indexPattern, + operationDefinitionMap: visibleOperationsMap, + }), + [indexPattern, visibleOperationsMap] + ); + const baseInterval = 'interval' in dateHistogramInterval ? dateHistogramInterval.interval?.asMilliseconds() @@ -600,7 +613,9 @@ export function FormulaEditor({ column: currentPosition.startColumn + cursorOffset, lineNumber: currentPosition.startLineNumber, }); - editor.trigger('lens', 'editor.action.triggerSuggest', {}); + if (editOperation?.text !== '=') { + editor.trigger('lens', 'editor.action.triggerSuggest', {}); + } }, 0); } } @@ -829,47 +844,21 @@ export function FormulaEditor({ ) : ( - - setIsHelpOpen(false)} - button={ - { - setIsHelpOpen(!isHelpOpen); - }} - iconType="documentation" - color="text" - aria-label={i18n.translate( - 'xpack.lens.formula.editorHelpInlineShowToolTip', - { - defaultMessage: 'Show function reference', - } - )} - /> - } - > - - - + )} @@ -926,12 +915,12 @@ export function FormulaEditor({
    + {/* fix the css here */} {isFullscreen && isHelpOpen ? ( -
    - +
    ) : null} diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_help.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_help.tsx index d0b4b3b0bb173..3c578c646a830 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_help.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/formula_help.tsx @@ -5,21 +5,8 @@ * 2.0. */ -import React, { useEffect, useRef, useState, useMemo } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiPopoverTitle, - EuiText, - EuiListGroupItem, - EuiListGroup, - EuiTitle, - EuiFieldSearch, - EuiHighlight, - EuiSpacer, -} from '@elastic/eui'; import { Markdown } from '@kbn/kibana-react-plugin/public'; import { groupBy } from 'lodash'; import type { IndexPattern } from '../../../../../../types'; @@ -35,24 +22,13 @@ import type { } from '../..'; import type { FormulaIndexPatternColumn } from '../formula'; -function FormulaHelp({ +export function getDocumentationSections({ indexPattern, operationDefinitionMap, - isFullscreen, }: { indexPattern: IndexPattern; operationDefinitionMap: Record; - isFullscreen: boolean; }) { - const [selectedFunction, setSelectedFunction] = useState(); - const scrollTargets = useRef>({}); - - useEffect(() => { - if (selectedFunction && scrollTargets.current[selectedFunction]) { - scrollTargets.current[selectedFunction].scrollIntoView(); - } - }, [selectedFunction]); - const helpGroups: Array<{ label: string; description?: string; @@ -199,18 +175,14 @@ max(system.network.in.bytes, reducedTimeRange="30m") calculation: calculationFunction, math: mathOperations, comparison: comparisonOperations, - } = useMemo( - () => - groupBy(getPossibleFunctions(indexPattern), (key) => { - if (key in operationDefinitionMap) { - return operationDefinitionMap[key].documentation?.section; - } - if (key in tinymathFunctions) { - return tinymathFunctions[key].section; - } - }), - [operationDefinitionMap, indexPattern] - ); + } = groupBy(getPossibleFunctions(indexPattern), (key) => { + if (key in operationDefinitionMap) { + return operationDefinitionMap[key].documentation?.section; + } + if (key in tinymathFunctions) { + return tinymathFunctions[key].section; + } + }); // Es aggs helpGroups[2].items.push( @@ -259,10 +231,6 @@ max(system.network.in.bytes, reducedTimeRange="30m") ) : null} ), - checked: - selectedFunction === `${key}: ${operationDefinitionMap[key].displayName}` - ? ('on' as const) - : undefined, })) ); @@ -277,16 +245,14 @@ max(system.network.in.bytes, reducedTimeRange="30m") items: [], }); - const mathFns = useMemo(() => { - return mathOperations.sort().map((key) => { - const [description, examples] = tinymathFunctions[key].help.split(`\`\`\``); - return { - label: key, - description: description.replace(/\n/g, '\n\n'), - examples: examples ? `\`\`\`${examples}\`\`\`` : '', - }; - }); - }, [mathOperations]); + const mathFns = mathOperations.sort().map((key) => { + const [description, examples] = tinymathFunctions[key].help.split(`\`\`\``); + return { + label: key, + description: description.replace(/\n/g, '\n\n'), + examples: examples ? `\`\`\`${examples}\`\`\`` : '', + }; + }); helpGroups[4].items.push( ...mathFns.map(({ label, description, examples }) => { @@ -313,16 +279,14 @@ max(system.network.in.bytes, reducedTimeRange="30m") items: [], }); - const comparisonFns = useMemo(() => { - return comparisonOperations.sort().map((key) => { - const [description, examples] = tinymathFunctions[key].help.split(`\`\`\``); - return { - label: key, - description: description.replace(/\n/g, '\n\n'), - examples: examples ? `\`\`\`${examples}\`\`\`` : '', - }; - }); - }, [comparisonOperations]); + const comparisonFns = comparisonOperations.sort().map((key) => { + const [description, examples] = tinymathFunctions[key].help.split(`\`\`\``); + return { + label: key, + description: description.replace(/\n/g, '\n\n'), + examples: examples ? `\`\`\`${examples}\`\`\`` : '', + }; + }); helpGroups[5].items.push( ...comparisonFns.map(({ label, description, examples }) => { @@ -339,119 +303,12 @@ max(system.network.in.bytes, reducedTimeRange="30m") }) ); - const [searchText, setSearchText] = useState(''); - - const normalizedSearchText = searchText.trim().toLocaleLowerCase(); - - const filteredHelpGroups = helpGroups - .map((group) => { - const items = group.items.filter((helpItem) => { - return ( - !normalizedSearchText || helpItem.label.toLocaleLowerCase().includes(normalizedSearchText) - ); - }); - return { ...group, items }; - }) - .filter((group) => { - if (group.items.length > 0 || !normalizedSearchText) { - return true; - } - return group.label.toLocaleLowerCase().includes(normalizedSearchText); - }); - - return ( - <> - - {i18n.translate('xpack.lens.formulaDocumentation.header', { - defaultMessage: 'Formula reference', - })} - - - - - - - { - setSearchText(e.target.value); - }} - placeholder={i18n.translate('xpack.lens.formulaSearchPlaceholder', { - defaultMessage: 'Search functions', - })} - /> - - - - {filteredHelpGroups.map((helpGroup, index) => { - return ( - - ); - })} - - - - - - -
    { - if (el) { - scrollTargets.current[helpGroups[0].label] = el; - } - }} - > - -
    - - {helpGroups.slice(1).map((helpGroup, index) => { - return ( -
    { - if (el) { - scrollTargets.current[helpGroup.label] = el; - } - }} - > -

    {helpGroup.label}

    - -

    {helpGroup.description}

    - - {helpGroups[index + 1].items.map((helpItem) => { - return ( -
    { - if (el) { - scrollTargets.current[helpItem.label] = el; - } - }} - > - {helpItem.description} -
    - ); - })} -
    - ); - })} -
    -
    -
    - - ); -} + `, + description: + 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', + })} + /> + ), + }; -export const MemoizedFormulaHelp = React.memo(FormulaHelp); + return sections; +} export function getFunctionSignatureLabel( name: string, diff --git a/x-pack/plugins/lens/public/shared_components/query_input/query_input.tsx b/x-pack/plugins/lens/public/shared_components/query_input/query_input.tsx index 487f14312b495..c5cbdebf20fff 100644 --- a/x-pack/plugins/lens/public/shared_components/query_input/query_input.tsx +++ b/x-pack/plugins/lens/public/shared_components/query_input/query_input.tsx @@ -36,7 +36,7 @@ export const QueryInput = ({ const { inputValue, handleInputChange } = useDebouncedValue({ value, onChange }); const lensAppServices = useKibana().services; - const { data, uiSettings, http, notifications, docLinks, storage, unifiedSearch } = + const { data, uiSettings, http, notifications, docLinks, storage, unifiedSearch, dataViews } = lensAppServices; return ( @@ -74,7 +74,7 @@ export const QueryInput = ({ appName={i18n.translate('xpack.lens.queryInput.appName', { defaultMessage: 'Lens', })} - deps={{ unifiedSearch, notifications, http, docLinks, uiSettings, data, storage }} + deps={{ unifiedSearch, notifications, http, docLinks, uiSettings, data, storage, dataViews }} /> ); }; diff --git a/x-pack/plugins/lens/public/shared_components/value_labels_settings.tsx b/x-pack/plugins/lens/public/shared_components/value_labels_settings.tsx index f5378a2e3ba01..929478a67beb1 100644 --- a/x-pack/plugins/lens/public/shared_components/value_labels_settings.tsx +++ b/x-pack/plugins/lens/public/shared_components/value_labels_settings.tsx @@ -7,7 +7,7 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonGroup, EuiFormRow } from '@elastic/eui'; +import { EuiButtonGroup, EuiFormRow, EuiIconTip } from '@elastic/eui'; import { ValueLabelConfig } from '../../common/types'; const valueLabelsOptions: Array<{ @@ -54,7 +54,26 @@ export const ValueLabelsSettings: FC = ({ const isSelected = valueLabelsOptions.find(({ value }) => value === valueLabels)?.id || 'value_labels_hide'; return ( - {label}}> + + {label}{' '} + + + } + > { `); }); + it('removes all accessors from a layer', () => { + const chk = visualization.removeLayer!(fullState, 'first'); + expect(chk.metricAccessor).toBeUndefined(); + expect(chk.trendlineLayerId).toBeUndefined(); + expect(chk.trendlineLayerType).toBeUndefined(); + expect(chk.trendlineMetricAccessor).toBeUndefined(); + expect(chk.trendlineTimeAccessor).toBeUndefined(); + expect(chk.trendlineBreakdownByAccessor).toBeUndefined(); + }); + it('appends a trendline layer', () => { const newLayerId = 'new-layer-id'; const chk = visualization.appendLayer!(fullState, newLayerId, 'metricTrendline', ''); @@ -767,6 +777,7 @@ describe('metric visualization', () => { it('removes trendline layer', () => { const chk = visualization.removeLayer!(fullStateWTrend, fullStateWTrend.trendlineLayerId); + expect(chk.metricAccessor).toBe('metric-col-id'); expect(chk.trendlineLayerId).toBeUndefined(); expect(chk.trendlineLayerType).toBeUndefined(); expect(chk.trendlineMetricAccessor).toBeUndefined(); diff --git a/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx b/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx index 95c9785b2e9fe..123821a62aa69 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx @@ -440,9 +440,10 @@ export const getMetricVisualization = ({ return { ...state, trendlineLayerId: layerId, trendlineLayerType: layerType }; }, - removeLayer(state) { + removeLayer(state, layerId) { const newState: MetricVisualizationState = { ...state, + ...(state.layerId === layerId && { metricAccessor: undefined }), trendlineLayerId: undefined, trendlineLayerType: undefined, trendlineMetricAccessor: undefined, diff --git a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/index.tsx b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/index.tsx index dc621b8b236e0..e1f995393ee7e 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/index.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/index.tsx @@ -55,11 +55,7 @@ export const VisualOptionsPopover: React.FC = ({ ); const hasNonBarSeries = dataLayers.some(({ seriesType }) => - ['area_stacked', 'area', 'line'].includes(seriesType) - ); - - const hasBarNotStacked = dataLayers.some(({ seriesType }) => - ['bar', 'bar_horizontal'].includes(seriesType) + ['area_stacked', 'area', 'line', 'area_percentage_stacked'].includes(seriesType) ); const hasAreaSeries = dataLayers.some(({ seriesType }) => @@ -68,8 +64,8 @@ export const VisualOptionsPopover: React.FC = ({ const isHistogramSeries = Boolean(hasHistogramSeries(dataLayers, datasourceLayers)); - const isValueLabelsEnabled = !hasNonBarSeries && hasBarNotStacked && !isHistogramSeries; - const isFittingEnabled = hasNonBarSeries; + const isValueLabelsEnabled = !hasNonBarSeries; + const isFittingEnabled = hasNonBarSeries && !isAreaPercentage; const isCurveTypeEnabled = hasNonBarSeries || isAreaPercentage; const valueLabelsDisabledReason = getValueLabelDisableReason({ diff --git a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/visual_options_popover.test.tsx b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/visual_options_popover.test.tsx index 0e29a5fa6634e..a6e6d54893d66 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/visual_options_popover.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/visual_options_popover/visual_options_popover.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { shallowWithIntl as shallow } from '@kbn/test-jest-helpers'; import { Position } from '@elastic/charts'; -import type { FramePublicAPI, DatasourcePublicAPI } from '../../../../types'; +import type { FramePublicAPI } from '../../../../types'; import { createMockDatasource, createMockFramePublicAPI } from '../../../../mocks'; import { State, XYLayerConfig } from '../../types'; import { VisualOptionsPopover } from '.'; @@ -44,21 +44,6 @@ describe('Visual options popover', () => { first: createMockDatasource('test').publicAPIMock, }; }); - it('should disable the visual options for stacked bar charts', () => { - const state = testState(); - const component = shallow( - - ); - - expect(component.find(ToolbarPopover).prop('isDisabled')).toEqual(true); - }); it('should disable the values and fitting for percentage area charts', () => { const state = testState(); @@ -109,28 +94,6 @@ describe('Visual options popover', () => { expect(component.find(ToolbarPopover).prop('isDisabled')).toEqual(false); }); - it('should disabled the popover if there is histogram series', () => { - // make it detect an histogram series - const datasourceLayers = frame.datasourceLayers as Record; - datasourceLayers.first.getOperationForColumnId = jest.fn().mockReturnValueOnce({ - isBucketed: true, - scale: 'interval', - }); - const state = testState(); - const component = shallow( - - ); - - expect(component.find(ToolbarPopover).prop('isDisabled')).toEqual(true); - }); - it('should hide the fitting option for bar series', () => { const state = testState(); const component = shallow( diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx index 6d6fed5181864..b272b5ec3e362 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx @@ -31,6 +31,7 @@ import { ReactWrapper, mount } from 'enzyme'; import { getFoundListsBySizeSchemaMock } from '../../../../common/schemas/response/found_lists_by_size_schema.mock'; import { BuilderEntryItem } from './entry_renderer'; +import * as i18n from './translations'; jest.mock('@kbn/securitysolution-list-hooks'); jest.mock('@kbn/securitysolution-utils'); @@ -81,11 +82,78 @@ describe('BuilderEntryItem', () => { onChange={jest.fn()} setErrorsExist={jest.fn()} setWarningsExist={jest.fn()} - showLabel={true} + showLabel /> ); expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldFormRow"]')).not.toEqual(0); + expect(wrapper.find('.euiFormHelpText.euiFormRow__text').exists()).toBeFalsy(); + }); + + test('it renders custom option text if "allowCustomOptions" is "true" and it is not a nested entry', () => { + wrapper = mount( + + ); + + expect(wrapper.find('.euiFormHelpText.euiFormRow__text').at(0).text()).toEqual( + i18n.CUSTOM_COMBOBOX_OPTION_TEXT + ); + }); + + test('it does not render custom option text when "allowCustomOptions" is "true" and it is a nested entry', () => { + wrapper = mount( + + ); + + expect(wrapper.find('.euiFormHelpText.euiFormRow__text').exists()).toBeFalsy(); }); test('it renders field values correctly when operator is "isOperator"', () => { @@ -259,7 +327,7 @@ describe('BuilderEntryItem', () => { onChange={jest.fn()} setErrorsExist={jest.fn()} setWarningsExist={jest.fn()} - showLabel={true} + showLabel /> ); @@ -297,7 +365,7 @@ describe('BuilderEntryItem', () => { onChange={jest.fn()} setErrorsExist={jest.fn()} setWarningsExist={jest.fn()} - showLabel={true} + showLabel /> ); diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx index 8f0bc15bd7da6..2df0b4b41a2f1 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx @@ -75,6 +75,7 @@ export interface EntryItemProps { setWarningsExist: (arg: boolean) => void; isDisabled?: boolean; operatorsList?: OperatorOption[]; + allowCustomOptions?: boolean; } export const BuilderEntryItem: React.FC = ({ @@ -93,6 +94,7 @@ export const BuilderEntryItem: React.FC = ({ showLabel, isDisabled = false, operatorsList, + allowCustomOptions = false, }): JSX.Element => { const handleError = useCallback( (err: boolean): void => { @@ -163,9 +165,9 @@ export const BuilderEntryItem: React.FC = ({ const isFieldComponentDisabled = useMemo( (): boolean => isDisabled || - indexPattern == null || - (indexPattern != null && indexPattern.fields.length === 0), - [isDisabled, indexPattern] + (!allowCustomOptions && + (indexPattern == null || (indexPattern != null && indexPattern.fields.length === 0))), + [isDisabled, indexPattern, allowCustomOptions] ); const renderFieldInput = useCallback( @@ -190,6 +192,7 @@ export const BuilderEntryItem: React.FC = ({ isLoading={false} isDisabled={isDisabled || indexPattern == null} onChange={handleFieldChange} + acceptsCustomOptions={entry.nested == null} data-test-subj="exceptionBuilderEntryField" /> ); @@ -199,6 +202,11 @@ export const BuilderEntryItem: React.FC = ({ {comboBox} @@ -206,7 +214,16 @@ export const BuilderEntryItem: React.FC = ({ ); } else { return ( - + {comboBox} ); @@ -220,6 +237,7 @@ export const BuilderEntryItem: React.FC = ({ handleFieldChange, osTypes, isDisabled, + allowCustomOptions, ] ); diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx index 84c18baf51569..d891c1a5eea08 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx @@ -63,6 +63,7 @@ interface BuilderExceptionListItemProps { onlyShowListOperators?: boolean; isDisabled?: boolean; operatorsList?: OperatorOption[]; + allowCustomOptions?: boolean; } export const BuilderExceptionListItemComponent = React.memo( @@ -85,6 +86,7 @@ export const BuilderExceptionListItemComponent = React.memo { const handleEntryChange = useCallback( (entry: BuilderEntry, entryIndex: number): void => { @@ -117,9 +119,9 @@ export const BuilderExceptionListItemComponent = React.memo { const hasIndexPatternAndEntries = indexPattern != null && exceptionItem.entries.length > 0; return hasIndexPatternAndEntries - ? getFormattedBuilderEntries(indexPattern, exceptionItem.entries) + ? getFormattedBuilderEntries(indexPattern, exceptionItem.entries, allowCustomOptions) : []; - }, [exceptionItem.entries, indexPattern]); + }, [exceptionItem.entries, indexPattern, allowCustomOptions]); return ( @@ -157,6 +159,7 @@ export const BuilderExceptionListItemComponent = React.memo DataViewBase; onChange: (arg: OnChangeProps) => void; - exceptionItemName?: string; ruleName?: string; isDisabled?: boolean; operatorsList?: OperatorOption[]; + exceptionItemName?: string; + allowCustomFieldOptions?: boolean; } export const ExceptionBuilderComponent = ({ @@ -118,6 +119,7 @@ export const ExceptionBuilderComponent = ({ isDisabled = false, osTypes, operatorsList, + allowCustomFieldOptions = false, }: ExceptionBuilderProps): JSX.Element => { const [ { @@ -229,7 +231,6 @@ export const ExceptionBuilderComponent = ({ }, ...exceptions.slice(index + 1), ]; - setUpdateExceptions(updatedExceptions); }, [setUpdateExceptions, exceptions] @@ -278,7 +279,6 @@ export const ExceptionBuilderComponent = ({ ...lastException, entries: [...entries, isNested ? getDefaultNestedEmptyEntry() : getDefaultEmptyEntry()], }; - setUpdateExceptions([...exceptions.slice(0, exceptions.length - 1), { ...updatedException }]); }, [setUpdateExceptions, exceptions] @@ -290,11 +290,12 @@ export const ExceptionBuilderComponent = ({ // would then be arbitrary, decided to just create a new exception list item const newException = getNewExceptionItem({ listId, + name: exceptionItemName ?? `${ruleName ?? 'Rule'} - Exception item`, namespaceType: listNamespaceType, - ruleName: exceptionItemName ?? `${ruleName ?? 'Rule'} - Exception item`, }); + setUpdateExceptions([...exceptions, { ...newException }]); - }, [listId, listNamespaceType, exceptionItemName, ruleName, setUpdateExceptions, exceptions]); + }, [setUpdateExceptions, exceptions, listId, listNamespaceType, ruleName, exceptionItemName]); // The builder can have existing exception items, or new exception items that have yet // to be created (and thus lack an id), this was creating some React bugs with relying @@ -334,7 +335,6 @@ export const ExceptionBuilderComponent = ({ }, ], }; - setUpdateExceptions([...exceptions.slice(0, exceptions.length - 1), { ...updatedException }]); } else { setUpdateExceptions(exceptions); @@ -359,19 +359,23 @@ export const ExceptionBuilderComponent = ({ handleAddNewExceptionItemEntry(); }, [handleAddNewExceptionItemEntry, setUpdateOrDisabled, setUpdateAddNested]); + const memoExceptionItems = useMemo(() => { + return filterExceptionItems(exceptions); + }, [exceptions]); + + // useEffect(() => { + // setUpdateExceptions([]); + // }, [osTypes, setUpdateExceptions]); + // Bubble up changes to parent useEffect(() => { onChange({ errorExists: errorExists > 0, - exceptionItems: filterExceptionItems(exceptions), + exceptionItems: memoExceptionItems, exceptionsToDelete, warningExists: warningExists > 0, }); - }, [onChange, exceptionsToDelete, exceptions, errorExists, warningExists]); - - useEffect(() => { - setUpdateExceptions([]); - }, [osTypes, setUpdateExceptions]); + }, [onChange, exceptionsToDelete, memoExceptionItems, errorExists, warningExists]); // Defaults builder to never be sans entry, instead // always falls back to an empty entry if user deletes all @@ -436,6 +440,7 @@ export const ExceptionBuilderComponent = ({ osTypes={osTypes} isDisabled={isDisabled} operatorsList={operatorsList} + allowCustomOptions={allowCustomFieldOptions} /> diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts index 73bf42e767dd6..38323fcf88cbf 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts @@ -6,13 +6,11 @@ */ import { - CreateExceptionListItemSchema, EntryExists, EntryList, EntryMatch, EntryMatchAny, EntryNested, - ExceptionListItemSchema, ExceptionListType, ListOperatorEnum as OperatorEnum, ListOperatorTypeEnum as OperatorTypeEnum, @@ -24,6 +22,7 @@ import { EXCEPTION_OPERATORS_SANS_LISTS, EmptyEntry, ExceptionsBuilderExceptionItem, + ExceptionsBuilderReturnExceptionItem, FormattedBuilderEntry, OperatorOption, doesNotExistOperator, @@ -1056,10 +1055,10 @@ describe('Exception builder helpers', () => { }); describe('#getFormattedBuilderEntries', () => { - test('it returns formatted entry with field undefined if it unable to find a matching index pattern field', () => { + test('it returns formatted entry with field undefined if it unable to find a matching index pattern field and "allowCustomFieldOptions" is "false"', () => { const payloadIndexPattern = getMockIndexPattern(); const payloadItems: BuilderEntry[] = [getEntryMatchWithIdMock()]; - const output = getFormattedBuilderEntries(payloadIndexPattern, payloadItems); + const output = getFormattedBuilderEntries(payloadIndexPattern, payloadItems, false); const expected: FormattedBuilderEntry[] = [ { correspondingKeywordField: undefined, @@ -1075,13 +1074,35 @@ describe('Exception builder helpers', () => { expect(output).toEqual(expected); }); + test('it returns formatted entry with field even if it is unable to find a matching index pattern field and "allowCustomFieldOptions" is "true"', () => { + const payloadIndexPattern = getMockIndexPattern(); + const payloadItems: BuilderEntry[] = [getEntryMatchWithIdMock()]; + const output = getFormattedBuilderEntries(payloadIndexPattern, payloadItems, true); + const expected: FormattedBuilderEntry[] = [ + { + correspondingKeywordField: undefined, + entryIndex: 0, + field: { + name: 'host.name', + type: 'keyword', + }, + id: '123', + nested: undefined, + operator: isOperator, + parent: undefined, + value: 'some host name', + }, + ]; + expect(output).toEqual(expected); + }); + test('it returns formatted entries when no nested entries exist', () => { const payloadIndexPattern = getMockIndexPattern(); const payloadItems: BuilderEntry[] = [ { ...getEntryMatchWithIdMock(), field: 'ip', value: 'some ip' }, { ...getEntryMatchAnyWithIdMock(), field: 'extension', value: ['some extension'] }, ]; - const output = getFormattedBuilderEntries(payloadIndexPattern, payloadItems); + const output = getFormattedBuilderEntries(payloadIndexPattern, payloadItems, false); const field1: FieldSpec = { aggregatable: true, count: 0, @@ -1139,7 +1160,7 @@ describe('Exception builder helpers', () => { { ...payloadParent }, ]; - const output = getFormattedBuilderEntries(payloadIndexPattern, payloadItems); + const output = getFormattedBuilderEntries(payloadIndexPattern, payloadItems, false); const field1: FieldSpec = { aggregatable: true, count: 0, @@ -1313,7 +1334,8 @@ describe('Exception builder helpers', () => { payloadItem, 0, undefined, - undefined + undefined, + false ); const field: FieldSpec = { aggregatable: false, @@ -1338,6 +1360,95 @@ describe('Exception builder helpers', () => { expect(output).toEqual(expected); }); + test('it returns entry with field value undefined if "allowCustomFieldOptions" is "false" and no matching field found', () => { + const payloadIndexPattern: DataViewBase = { + ...getMockIndexPattern(), + fields: [ + ...fields, + { + aggregatable: false, + count: 0, + esTypes: ['text'], + name: 'machine.os.raw.text', + readFromDocValues: true, + scripted: false, + searchable: false, + type: 'string', + }, + ], + }; + const payloadItem: BuilderEntry = { + ...getEntryMatchWithIdMock(), + field: 'custom.text', + value: 'some os', + }; + const output = getFormattedBuilderEntry( + payloadIndexPattern, + payloadItem, + 0, + undefined, + undefined, + false + ); + const expected: FormattedBuilderEntry = { + correspondingKeywordField: undefined, + entryIndex: 0, + field: undefined, + id: '123', + nested: undefined, + operator: isOperator, + parent: undefined, + value: 'some os', + }; + expect(output).toEqual(expected); + }); + + test('it returns entry with custom field value if "allowCustomFieldOptions" is "true" and no matching field found', () => { + const payloadIndexPattern: DataViewBase = { + ...getMockIndexPattern(), + fields: [ + ...fields, + { + aggregatable: false, + count: 0, + esTypes: ['text'], + name: 'machine.os.raw.text', + readFromDocValues: true, + scripted: false, + searchable: false, + type: 'string', + }, + ], + }; + const payloadItem: BuilderEntry = { + ...getEntryMatchWithIdMock(), + field: 'custom.text', + value: 'some os', + }; + const output = getFormattedBuilderEntry( + payloadIndexPattern, + payloadItem, + 0, + undefined, + undefined, + true + ); + const expected: FormattedBuilderEntry = { + correspondingKeywordField: undefined, + entryIndex: 0, + field: { + name: 'custom.text', + type: 'keyword', + }, + id: '123', + nested: undefined, + operator: isOperator, + parent: undefined, + value: 'some os', + }; + expect(output).toEqual(expected); + }); + test('it returns "FormattedBuilderEntry" with value "nested" of "child" when "parent" and "parentIndex" are defined', () => { const payloadIndexPattern = getMockIndexPattern(); const payloadItem: BuilderEntry = { ...getEntryMatchWithIdMock(), field: 'child' }; @@ -1351,7 +1462,8 @@ describe('Exception builder helpers', () => { payloadItem, 0, payloadParent, - 1 + 1, + false ); const field: FieldSpec = { aggregatable: false, @@ -1401,7 +1513,8 @@ describe('Exception builder helpers', () => { payloadItem, 0, undefined, - undefined + undefined, + false ); const field: FieldSpec = { aggregatable: true, @@ -1577,8 +1690,9 @@ describe('Exception builder helpers', () => { // Please see `x-pack/plugins/lists/public/exceptions/transforms.ts` doc notes // for context around the temporary `id` test('it correctly validates entries that include a temporary `id`', () => { - const output: Array = - filterExceptionItems([{ ...getExceptionListItemSchemaMock(), entries: ENTRIES_WITH_IDS }]); + const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ + { ...getExceptionListItemSchemaMock(), entries: ENTRIES_WITH_IDS }, + ]); expect(output).toEqual([{ ...getExceptionListItemSchemaMock(), entries: ENTRIES_WITH_IDS }]); }); @@ -1611,13 +1725,12 @@ describe('Exception builder helpers', () => { type: OperatorTypeEnum.MATCH, value: '', }; - const output: Array = - filterExceptionItems([ - { - ...rest, - entries: [...entries, mockEmptyException], - }, - ]); + const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ + { + ...rest, + entries: [...entries, mockEmptyException], + }, + ]); expect(output).toEqual([{ ...getExceptionListItemSchemaMock() }]); }); @@ -1631,13 +1744,12 @@ describe('Exception builder helpers', () => { type: OperatorTypeEnum.MATCH, value: 'some value', }; - const output: Array = - filterExceptionItems([ - { - ...rest, - entries: [...entries, mockEmptyException], - }, - ]); + const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ + { + ...rest, + entries: [...entries, mockEmptyException], + }, + ]); expect(output).toEqual([{ ...getExceptionListItemSchemaMock() }]); }); @@ -1651,13 +1763,12 @@ describe('Exception builder helpers', () => { type: OperatorTypeEnum.MATCH_ANY, value: ['some value'], }; - const output: Array = - filterExceptionItems([ - { - ...rest, - entries: [...entries, mockEmptyException], - }, - ]); + const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ + { + ...rest, + entries: [...entries, mockEmptyException], + }, + ]); expect(output).toEqual([{ ...getExceptionListItemSchemaMock() }]); }); @@ -1669,13 +1780,12 @@ describe('Exception builder helpers', () => { field: '', type: OperatorTypeEnum.NESTED, }; - const output: Array = - filterExceptionItems([ - { - ...rest, - entries: [...entries, mockEmptyException], - }, - ]); + const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ + { + ...rest, + entries: [...entries, mockEmptyException], + }, + ]); expect(output).toEqual([{ ...getExceptionListItemSchemaMock() }]); }); @@ -1687,13 +1797,12 @@ describe('Exception builder helpers', () => { field: 'host.name', type: OperatorTypeEnum.NESTED, }; - const output: Array = - filterExceptionItems([ - { - ...rest, - entries: [...entries, mockEmptyException], - }, - ]); + const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ + { + ...rest, + entries: [...entries, mockEmptyException], + }, + ]); expect(output).toEqual([ { @@ -1713,27 +1822,134 @@ describe('Exception builder helpers', () => { field: 'host.name', type: OperatorTypeEnum.NESTED, }; - const output: Array = - filterExceptionItems([ - { - ...rest, - entries: [...entries, mockEmptyException], - }, - ]); + const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ + { + ...rest, + entries: [...entries, mockEmptyException], + }, + ]); expect(output).toEqual([{ ...getExceptionListItemSchemaMock() }]); }); - test('it removes `temporaryId` from items', () => { + test('it removes `temporaryId` from "createExceptionListItemSchema" items', () => { const { meta, ...rest } = getNewExceptionItem({ listId: '123', + name: 'rule name', namespaceType: 'single', - ruleName: 'rule name', }); const exceptions = filterExceptionItems([{ ...rest, entries: [getEntryMatchMock()], meta }]); expect(exceptions).toEqual([{ ...rest, entries: [getEntryMatchMock()], meta: undefined }]); }); + + test('it removes `temporaryId` from "createRuleExceptionListItemSchema" items', () => { + const { meta, ...rest } = getNewExceptionItem({ + listId: undefined, + name: 'rule name', + namespaceType: undefined, + }); + const exceptions = filterExceptionItems([{ ...rest, entries: [getEntryMatchMock()], meta }]); + + expect(exceptions).toEqual([{ ...rest, entries: [getEntryMatchMock()], meta: undefined }]); + }); + }); + + describe('#getNewExceptionItem', () => { + it('returns new item with updated name', () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { meta, ...rest } = getNewExceptionItem({ + listId: '123', + name: 'My Item Name', + namespaceType: 'single', + }); + + expect(rest.name).toEqual('My Item Name'); + }); + + it('returns new item with list_id if one is passed in', () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { meta, ...rest } = getNewExceptionItem({ + listId: '123', + name: 'My Item Name', + namespaceType: 'single', + }); + + expect(rest).toEqual({ + comments: [], + description: 'Exception list item', + entries: [{ field: '', id: '123', operator: 'included', type: 'match', value: '' }], + item_id: undefined, + list_id: '123', + name: 'My Item Name', + namespace_type: 'single', + tags: [], + type: 'simple', + }); + }); + + it('returns new item without list_id if none is passed in', () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { meta, ...rest } = getNewExceptionItem({ + listId: undefined, + name: 'My Item Name', + namespaceType: 'single', + }); + + expect(rest).toEqual({ + comments: [], + description: 'Exception list item', + entries: [{ field: '', id: '123', operator: 'included', type: 'match', value: '' }], + item_id: undefined, + list_id: undefined, + name: 'My Item Name', + namespace_type: 'single', + tags: [], + type: 'simple', + }); + }); + + it('returns new item with namespace_type if one is passed in', () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { meta, ...rest } = getNewExceptionItem({ + listId: '123', + name: 'My Item Name', + namespaceType: 'single', + }); + + expect(rest).toEqual({ + comments: [], + description: 'Exception list item', + entries: [{ field: '', id: '123', operator: 'included', type: 'match', value: '' }], + item_id: undefined, + list_id: '123', + name: 'My Item Name', + namespace_type: 'single', + tags: [], + type: 'simple', + }); + }); + + it('returns new item without namespace_type if none is passed in', () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { meta, ...rest } = getNewExceptionItem({ + listId: '123', + name: 'My Item Name', + namespaceType: undefined, + }); + + expect(rest).toEqual({ + comments: [], + description: 'Exception list item', + entries: [{ field: '', id: '123', operator: 'included', type: 'match', value: '' }], + item_id: undefined, + list_id: '123', + name: 'My Item Name', + namespace_type: undefined, + tags: [], + type: 'simple', + }); + }); }); describe('#getEntryValue', () => { diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/translations.ts b/x-pack/plugins/lists/public/exceptions/components/builder/translations.ts index 291ef7a420f0f..ee7971e69c83a 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/translations.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/translations.ts @@ -75,3 +75,11 @@ export const AND = i18n.translate('xpack.lists.exceptions.andDescription', { export const OR = i18n.translate('xpack.lists.exceptions.orDescription', { defaultMessage: 'OR', }); + +export const CUSTOM_COMBOBOX_OPTION_TEXT = i18n.translate( + 'xpack.lists.exceptions.comboBoxCustomOptionText', + { + defaultMessage: + 'Select a field from the list. If your field is not available, create a custom one.', + } +); diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts index e17b0d7eff412..5b9e2f7d2ab27 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -6,6 +6,7 @@ */ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { useKibana, KibanaReactContextValue } from '@kbn/kibana-react-plugin/public'; @@ -27,6 +28,7 @@ import type { MlServicesContext } from '../../app'; interface StartPlugins { data: DataPublicPluginStart; + dataViews: DataViewsPublicPluginStart; security?: SecurityPluginSetup; licenseManagement?: LicenseManagementUIPluginSetup; share: SharePluginStart; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/get_destination_index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/get_destination_index.ts new file mode 100644 index 0000000000000..2058cce04850d --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/get_destination_index.ts @@ -0,0 +1,11 @@ +/* + * 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 { DataFrameAnalyticsConfig } from '../../../../common/types/data_frame_analytics'; + +export const getDestinationIndex = (jobConfig: DataFrameAnalyticsConfig | undefined) => + (Array.isArray(jobConfig?.dest.index) ? jobConfig?.dest.index[0] : jobConfig?.dest.index) ?? ''; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/index.ts index f47b5b66f4944..d7391f7dfa8b7 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/index.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/index.ts @@ -31,6 +31,7 @@ export { getDefaultFieldsFromJobCaps, sortExplorationResultsFields, MAX_COLUMNS export { getIndexData } from './get_index_data'; export { getIndexFields } from './get_index_fields'; +export { getDestinationIndex } from './get_destination_index'; export { getScatterplotMatrixLegendType } from './get_scatterplot_matrix_legend_type'; export { useResultsViewConfig } from './use_results_view_config'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts index 9f739bfb3d58c..df430142a3193 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts @@ -29,6 +29,7 @@ import { isClassificationAnalysis, isRegressionAnalysis, } from '../../../../common/util/analytics_utils'; +import { getDestinationIndex } from './get_destination_index'; export const useResultsViewConfig = (jobId: string) => { const mlContext = useMlContext(); @@ -95,9 +96,7 @@ export const useResultsViewConfig = (jobId: string) => { } try { - const destIndex = Array.isArray(jobConfigUpdate.dest.index) - ? jobConfigUpdate.dest.index[0] - : jobConfigUpdate.dest.index; + const destIndex = getDestinationIndex(jobConfigUpdate); const destDataViewId = (await getDataViewIdFromName(destIndex)) ?? destIndex; let dataView: DataView | undefined; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx index 17453dd87b0d0..482c214f884a3 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx @@ -19,6 +19,7 @@ import { getScatterplotMatrixLegendType, useResultsViewConfig, DataFrameAnalyticsConfig, + getDestinationIndex, } from '../../../../common'; import { ResultsSearchQuery, ANALYSIS_CONFIG_TYPE } from '../../../../common/analytics'; @@ -32,6 +33,7 @@ import { LoadingPanel } from '../loading_panel'; import { FeatureImportanceSummaryPanelProps } from '../total_feature_importance_summary/feature_importance_summary'; import { useExplorationUrlState } from '../../hooks/use_exploration_url_state'; import { ExplorationQueryBarProps } from '../exploration_query_bar/exploration_query_bar'; +import { IndexPatternPrompt } from '../index_pattern_prompt'; function getFilters(resultsField: string) { return { @@ -114,6 +116,8 @@ export const ExplorationPageWrapper: FC = ({ }; const resultsField = jobConfig?.dest.results_field ?? ''; + const destIndex = getDestinationIndex(jobConfig); + const scatterplotFieldOptions = useScatterplotFieldOptions( indexPattern, jobConfig?.analyzed_fields?.includes, @@ -131,7 +135,12 @@ export const ExplorationPageWrapper: FC = ({ color="danger" iconType="cross" > -

    {indexPatternErrorMessage}

    +

    + {indexPatternErrorMessage} + {needsDestIndexPattern ? ( + + ) : null} +

    ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx index 33ab5e72b9fd1..464d57ff2917a 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx @@ -58,8 +58,17 @@ export const ExplorationQueryBar: FC = ({ const [errorMessage, setErrorMessage] = useState(undefined); const { services } = useMlKibana(); - const { unifiedSearch, data, storage, appName, notifications, http, docLinks, uiSettings } = - services; + const { + unifiedSearch, + data, + storage, + appName, + notifications, + http, + docLinks, + uiSettings, + dataViews, + } = services; const searchChangeHandler = (q: Query) => setSearchInput(q); @@ -203,7 +212,16 @@ export const ExplorationQueryBar: FC = ({ dataTestSubj="mlDFAnalyticsQueryInput" languageSwitcherPopoverAnchorPosition="rightDown" appName={appName} - deps={{ unifiedSearch, notifications, http, docLinks, uiSettings, data, storage }} + deps={{ + unifiedSearch, + notifications, + http, + docLinks, + uiSettings, + data, + storage, + dataViews, + }} /> {filters && filters.options && ( diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx index 1f9362d7e56ca..cd60be7290b96 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx @@ -11,10 +11,11 @@ import { EuiLink, EuiText } from '@elastic/eui'; import { useMlKibana } from '../../../../../contexts/kibana'; interface Props { - destIndex: string; + color?: string; + destIndex?: string; } -export const IndexPatternPrompt: FC = ({ destIndex }) => { +export const IndexPatternPrompt: FC = ({ destIndex, color }) => { const { services: { http: { basePath }, @@ -30,20 +31,20 @@ export const IndexPatternPrompt: FC = ({ destIndex }) => { return ( <> - + {canCreateDataView === true ? ( ; @@ -90,6 +96,7 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = jobConfig?.analyzed_fields?.excludes, resultsField ); + const destIndex = getDestinationIndex(jobConfig); if (indexPatternErrorMessage !== undefined) { return ( @@ -101,7 +108,12 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = color="danger" iconType="cross" > -

    {indexPatternErrorMessage}

    +

    + {indexPatternErrorMessage} + {needsDestIndexPattern ? ( + + ) : null} +

    ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx index 7d2798f020242..efe5275685e9c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx @@ -5,10 +5,12 @@ * 2.0. */ -import { EuiToolTip } from '@elastic/eui'; +import { EuiToolTip, EuiLink, EuiText } from '@elastic/eui'; import React, { FC } from 'react'; import { cloneDeep, isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public'; import { DeepReadonly } from '../../../../../../../common/types/common'; import { DataFrameAnalyticsConfig, isOutlierAnalysis } from '../../../../common'; import { isClassificationAnalysis, isRegressionAnalysis } from '../../../../common/analytics'; @@ -401,9 +403,15 @@ export const useNavigateToWizardWithClonedJob = () => { services: { notifications: { toasts }, data: { dataViews }, + http: { basePath }, + application: { capabilities }, + theme, }, } = useMlKibana(); + const theme$ = theme.theme$; const navigateToPath = useNavigateToPath(); + const canCreateDataView = + capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true; return async (item: Pick) => { const sourceIndex = Array.isArray(item.config.source.index) @@ -416,13 +424,42 @@ export const useNavigateToWizardWithClonedJob = () => { if (dv !== undefined) { sourceIndexId = dv.id; } else { - toasts.addDanger( - i18n.translate('xpack.ml.dataframe.analyticsList.noSourceDataViewForClone', { - defaultMessage: - 'Unable to clone the analytics job. No data view exists for index {dataView}.', - values: { dataView: sourceIndex }, - }) - ); + toasts.addDanger({ + title: toMountPoint( + wrapWithTheme( + <> + + {canCreateDataView ? ( + + + + + ), + }} + /> + + ) : null} + , + theme$ + ) + ), + }); } } catch (e) { const error = extractErrorMessage(e); diff --git a/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx b/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx index 90afeb2efb3b1..7c5390b667866 100644 --- a/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx +++ b/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx @@ -113,8 +113,17 @@ export const ExplorerQueryBar: FC = ({ }) => { const { anomalyExplorerCommonStateService } = useAnomalyExplorerContext(); const { services } = useMlKibana(); - const { unifiedSearch, data, storage, appName, notifications, http, docLinks, uiSettings } = - services; + const { + unifiedSearch, + data, + storage, + appName, + notifications, + http, + docLinks, + uiSettings, + dataViews, + } = services; // The internal state of the input query bar updated on every key stroke. const [searchInput, setSearchInput] = useState( @@ -171,7 +180,16 @@ export const ExplorerQueryBar: FC = ({ dataTestSubj="explorerQueryInput" languageSwitcherPopoverAnchorPosition="rightDown" appName={appName} - deps={{ unifiedSearch, notifications, http, docLinks, uiSettings, data, storage }} + deps={{ + unifiedSearch, + notifications, + http, + docLinks, + uiSettings, + data, + storage, + dataViews, + }} /> } isOpen={errorMessage?.query === searchInput.query && errorMessage?.message !== ''} diff --git a/x-pack/plugins/observability/kibana.json b/x-pack/plugins/observability/kibana.json index 365bc50e8abf1..43e69c1b4d952 100644 --- a/x-pack/plugins/observability/kibana.json +++ b/x-pack/plugins/observability/kibana.json @@ -27,7 +27,6 @@ "features", "inspector", "ruleRegistry", - "timelines", "triggersActionsUi", "inspector", "unifiedSearch", @@ -44,7 +43,8 @@ "kibanaReact", "kibanaUtils", "lens", - "usageCollection" + "usageCollection", + "visualizations" ], "extraPublicDirs": [ "common" diff --git a/x-pack/plugins/observability/public/application/types.ts b/x-pack/plugins/observability/public/application/types.ts index 7e76a46c03c0c..4707760c63e39 100644 --- a/x-pack/plugins/observability/public/application/types.ts +++ b/x-pack/plugins/observability/public/application/types.ts @@ -24,8 +24,6 @@ import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { LensPublicStart } from '@kbn/lens-plugin/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import { CasesUiStart } from '@kbn/cases-plugin/public'; -import { TimelinesUIStart } from '@kbn/timelines-plugin/public'; - export interface ObservabilityAppServices { application: ApplicationStart; cases: CasesUiStart; @@ -42,7 +40,6 @@ export interface ObservabilityAppServices { stateTransfer: EmbeddableStateTransfer; storage: IStorageWrapper; theme: ThemeServiceStart; - timelines: TimelinesUIStart; triggersActionsUi: TriggersAndActionsUIPublicPluginStart; uiSettings: IUiSettingsClient; isDev?: boolean; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts index b031bff08b0f8..d1fdd6bc7cf67 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -158,7 +158,7 @@ describe('Lens Attribute', () => { customLabel: true, dataType: 'number', isBucketed: false, - label: 'Pages loaded', + label: 'test-series', operationType: 'formula', params: { format: { @@ -427,7 +427,13 @@ describe('Lens Attribute', () => { ], }, ], - legend: { isVisible: true, showSingleSeries: true, position: 'right' }, + legend: { + isVisible: true, + showSingleSeries: true, + position: 'right', + legendSize: 'large', + shouldTruncate: false, + }, preferredSeriesType: 'line', tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true }, valueLabels: 'hide', @@ -545,7 +551,7 @@ describe('Lens Attribute', () => { 'transaction.type: page-load and processor.event: transaction and transaction.type : *', }, isBucketed: false, - label: 'Pages loaded', + label: 'test-series', operationType: 'formula', params: { format: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts index 8e39ff3bdd2c6..60f554d5344c4 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -37,6 +37,7 @@ import { } from '@kbn/lens-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/common'; import { PersistableFilter } from '@kbn/lens-plugin/common'; +import { LegendSize } from '@kbn/visualizations-plugin/common/constants'; import { urlFiltersToKueryString } from '../utils/stringify_kueries'; import { FILTER_RECORDS, @@ -397,15 +398,14 @@ export class LensAttributes { return { ...buildNumberColumn(sourceField), label: - operationType === 'unique_count' || shortLabel - ? label || seriesConfig.labels[sourceField] - : i18n.translate('xpack.observability.expView.columns.operation.label', { - defaultMessage: '{operationType} of {sourceField}', - values: { - sourceField: label || seriesConfig.labels[sourceField], - operationType: capitalize(operationType), - }, - }), + label ?? + i18n.translate('xpack.observability.expView.columns.operation.label', { + defaultMessage: '{operationType} of {sourceField}', + values: { + sourceField: seriesConfig.labels[sourceField], + operationType: capitalize(operationType), + }, + }), filter: columnFilter, operationType, params: @@ -574,7 +574,7 @@ export class LensAttributes { const { type: fieldType } = fieldMeta ?? {}; if (columnType === TERMS_COLUMN) { - return this.getTermsColumn(fieldName, columnLabel || label); + return this.getTermsColumn(fieldName, label || columnLabel); } if (fieldName === RECORDS_FIELD || columnType === FILTER_RECORDS) { @@ -606,7 +606,7 @@ export class LensAttributes { columnType, columnFilter: columnFilters?.[0], operationType, - label: columnLabel || label, + label: label || columnLabel, seriesConfig: layerConfig.seriesConfig, shortLabel, }); @@ -615,7 +615,7 @@ export class LensAttributes { return this.getNumberOperationColumn({ sourceField: fieldName, operationType: 'unique_count', - label: columnLabel || label, + label: label || columnLabel, seriesConfig: layerConfig.seriesConfig, columnFilter: columnFilters?.[0], }); @@ -687,8 +687,18 @@ export class LensAttributes { getMainYAxis(layerConfig: LayerConfig, layerId: string, columnFilter: string) { const { breakdown } = layerConfig; - const { sourceField, operationType, label, timeScale } = - layerConfig.seriesConfig.yAxisColumns[0]; + const { + sourceField, + operationType, + label: colLabel, + timeScale, + } = layerConfig.seriesConfig.yAxisColumns[0]; + + let label = layerConfig.name || colLabel; + + if (layerConfig.seriesConfig.reportType === ReportTypes.CORE_WEB_VITAL) { + label = colLabel; + } if (sourceField === RECORDS_PERCENTAGE_FIELD) { return [ @@ -1028,7 +1038,13 @@ export class LensAttributes { getXyState(): XYState { return { - legend: { isVisible: true, showSingleSeries: true, position: 'right' }, + legend: { + isVisible: true, + showSingleSeries: true, + position: 'right', + legendSize: LegendSize.LARGE, + shouldTruncate: false, + }, valueLabels: 'hide', fittingFunction: 'Linear', curveType: 'CURVE_MONOTONE_X' as XYCurveType, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/mobile_test_attribute.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/mobile_test_attribute.ts index 85fd0c9f601b8..1af87c385d31e 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/mobile_test_attribute.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/mobile_test_attribute.ts @@ -39,7 +39,7 @@ export const testMobileKPIAttr = { }, 'y-axis-column-layer0-0': { isBucketed: false, - label: 'Median of System memory usage', + label: 'test-series', operationType: 'median', params: {}, scale: 'ratio', @@ -58,7 +58,13 @@ export const testMobileKPIAttr = { }, }, visualization: { - legend: { isVisible: true, showSingleSeries: true, position: 'right' }, + legend: { + isVisible: true, + showSingleSeries: true, + position: 'right', + legendSize: 'large', + shouldTruncate: false, + }, valueLabels: 'hide', fittingFunction: 'Linear', curveType: 'CURVE_MONOTONE_X', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts index 6c6424a0362d1..4661775b3a83f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts @@ -67,7 +67,7 @@ export const sampleAttribute = { 'transaction.type: page-load and processor.event: transaction and transaction.type : *', }, isBucketed: false, - label: 'Pages loaded', + label: 'test-series', operationType: 'formula', params: { format: { @@ -322,6 +322,8 @@ export const sampleAttribute = { isVisible: true, position: 'right', showSingleSeries: true, + legendSize: 'large', + shouldTruncate: false, }, preferredSeriesType: 'line', tickLabelsVisibilitySettings: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts index 1cf945c4456a5..15e462c10be28 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts @@ -141,6 +141,8 @@ export const sampleAttributeCoreWebVital = { isVisible: true, showSingleSeries: true, position: 'right', + shouldTruncate: false, + legendSize: 'large', }, preferredSeriesType: 'line', tickLabelsVisibilitySettings: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts index 280438737b5da..6482795198898 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts @@ -45,7 +45,7 @@ export const sampleAttributeKpi = { query: 'transaction.type: page-load and processor.event: transaction', }, isBucketed: false, - label: 'Page views', + label: 'test-series', operationType: 'count', scale: 'ratio', sourceField: RECORDS_FIELD, @@ -95,6 +95,8 @@ export const sampleAttributeKpi = { isVisible: true, showSingleSeries: true, position: 'right', + legendSize: 'large', + shouldTruncate: false, }, preferredSeriesType: 'line', tickLabelsVisibilitySettings: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_with_reference_lines.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_with_reference_lines.ts index 5d51b1c193401..873e4a6269de6 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_with_reference_lines.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_with_reference_lines.ts @@ -67,7 +67,7 @@ export const sampleAttributeWithReferenceLines = { 'transaction.type: page-load and processor.event: transaction and transaction.type : * and service.name: (elastic or kibana)', }, isBucketed: false, - label: 'Pages loaded', + label: 'test-series', operationType: 'formula', params: { format: { @@ -322,6 +322,8 @@ export const sampleAttributeWithReferenceLines = { isVisible: true, position: 'right', showSingleSeries: true, + legendSize: 'large', + shouldTruncate: false, }, preferredSeriesType: 'line', tickLabelsVisibilitySettings: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_name.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_name.tsx index 68a628e23292c..a8d0338e9eb7e 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_name.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_name.tsx @@ -54,12 +54,14 @@ export function SeriesName({ series, seriesId }: Props) { const onOutsideClick = (event: Event) => { if (event.target !== buttonRef.current) { setIsEditingEnabled(false); + onSave(); } }; const onKeyDown: KeyboardEventHandler = (event) => { if (event.key === 'Enter') { setIsEditingEnabled(false); + onSave(); } }; diff --git a/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx b/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx index bc41b8d803285..d6ac49b736a5a 100644 --- a/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx +++ b/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx @@ -12,9 +12,9 @@ import { casesFeatureId, observabilityFeatureId } from '../../common'; import { useBulkAddToCaseActions } from '../hooks/use_alert_bulk_case_actions'; import { TopAlert, useToGetInternalFlyout } from '../pages/alerts'; import { getRenderCellValue } from '../pages/alerts/components/render_cell_value'; -import { addDisplayNames } from '../pages/alerts/containers/alerts_table_t_grid/add_display_names'; -import { columns as alertO11yColumns } from '../pages/alerts/containers/alerts_table_t_grid/alerts_table_t_grid'; -import { getRowActions } from '../pages/alerts/containers/alerts_table_t_grid/get_row_actions'; +import { addDisplayNames } from '../pages/alerts/containers/alerts_table/add_display_names'; +import { columns as alertO11yColumns } from '../pages/alerts/containers/alerts_table/default_columns'; +import { getRowActions } from '../pages/alerts/containers/alerts_table/get_row_actions'; import type { ObservabilityRuleTypeRegistry } from '../rules/create_observability_rule_type_registry'; import type { ConfigSchema } from '../plugin'; diff --git a/x-pack/plugins/observability/public/hooks/use_alert_bulk_case_actions.ts b/x-pack/plugins/observability/public/hooks/use_alert_bulk_case_actions.ts index 40219feb09c21..6e4b915eccfe7 100644 --- a/x-pack/plugins/observability/public/hooks/use_alert_bulk_case_actions.ts +++ b/x-pack/plugins/observability/public/hooks/use_alert_bulk_case_actions.ts @@ -12,7 +12,7 @@ import { ADD_TO_CASE_DISABLED, ADD_TO_EXISTING_CASE, ADD_TO_NEW_CASE, -} from '../pages/alerts/containers/alerts_table_t_grid/translations'; +} from '../pages/alerts/containers/alerts_table/translations'; import { useGetUserCasesPermissions } from './use_get_user_cases_permissions'; import { ObservabilityAppServices } from '../application/types'; diff --git a/x-pack/plugins/observability/public/pages/alerts/components/default_cell_actions.tsx b/x-pack/plugins/observability/public/pages/alerts/components/default_cell_actions.tsx deleted file mode 100644 index 115fa703459b9..0000000000000 --- a/x-pack/plugins/observability/public/pages/alerts/components/default_cell_actions.tsx +++ /dev/null @@ -1,42 +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 React from 'react'; -import { i18n } from '@kbn/i18n'; -import { TimelineNonEcsData } from '@kbn/timelines-plugin/common/search_strategy'; -import { TGridCellAction } from '@kbn/timelines-plugin/common/types/timeline'; -import { getPageRowIndex } from '@kbn/timelines-plugin/public'; -import FilterForValueButton from './filter_for_value'; -import { getMappedNonEcsValue } from './render_cell_value'; - -export const FILTER_FOR_VALUE = i18n.translate('xpack.observability.hoverActions.filterForValue', { - defaultMessage: 'Filter for value', -}); - -/** actions for adding filters to the search bar */ -const buildFilterCellActions = (addToQuery: (value: string) => void): TGridCellAction[] => [ - ({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) => - ({ rowIndex, columnId, Component }) => { - const value = getMappedNonEcsValue({ - data: data[getPageRowIndex(rowIndex, pageSize)], - fieldName: columnId, - }); - - return ( - - ); - }, -]; - -/** returns the default actions shown in `EuiDataGrid` cells */ -export const getDefaultCellActions = ({ addToQuery }: { addToQuery: (value: string) => void }) => - buildFilterCellActions(addToQuery); diff --git a/x-pack/plugins/observability/public/pages/alerts/components/index.ts b/x-pack/plugins/observability/public/pages/alerts/components/index.ts index 113e4b86c0e71..592ab16ddcadf 100644 --- a/x-pack/plugins/observability/public/pages/alerts/components/index.ts +++ b/x-pack/plugins/observability/public/pages/alerts/components/index.ts @@ -10,7 +10,6 @@ export * from './render_cell_value'; export * from './severity_badge'; export * from './workflow_status_filter'; export * from './alerts_search_bar'; -export * from './default_cell_actions'; export * from './filter_for_value'; export * from './parse_alert'; export * from './alerts_status_filter'; diff --git a/x-pack/plugins/observability/public/pages/alerts/components/observability_actions.tsx b/x-pack/plugins/observability/public/pages/alerts/components/observability_actions.tsx index 8bed941ce1741..0583b9a35eb64 100644 --- a/x-pack/plugins/observability/public/pages/alerts/components/observability_actions.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/components/observability_actions.tsx @@ -24,10 +24,7 @@ import { useKibana } from '../../../utils/kibana_react'; import { useGetUserCasesPermissions } from '../../../hooks/use_get_user_cases_permissions'; import { parseAlert } from './parse_alert'; import { translations, paths } from '../../../config'; -import { - ADD_TO_EXISTING_CASE, - ADD_TO_NEW_CASE, -} from '../containers/alerts_table_t_grid/translations'; +import { ADD_TO_EXISTING_CASE, ADD_TO_NEW_CASE } from '../containers/alerts_table/translations'; import { ObservabilityAppServices } from '../../../application/types'; import { RULE_DETAILS_PAGE_ID } from '../../rule_details/types'; import type { TopAlert } from '../containers/alerts_page/types'; diff --git a/x-pack/plugins/observability/public/pages/alerts/components/render_cell_value/index.ts b/x-pack/plugins/observability/public/pages/alerts/components/render_cell_value/index.ts index b6df77f075888..009feb015eefd 100644 --- a/x-pack/plugins/observability/public/pages/alerts/components/render_cell_value/index.ts +++ b/x-pack/plugins/observability/public/pages/alerts/components/render_cell_value/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { getRenderCellValue, getMappedNonEcsValue } from './render_cell_value'; +export { getRenderCellValue } from './render_cell_value'; diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/add_display_names.ts b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/add_display_names.ts similarity index 90% rename from x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/add_display_names.ts rename to x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/add_display_names.ts index ef36911a93530..1f2efcbd6d7ea 100644 --- a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/add_display_names.ts +++ b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/add_display_names.ts @@ -6,12 +6,10 @@ */ import { ALERT_DURATION, ALERT_REASON, ALERT_STATUS, TIMESTAMP } from '@kbn/rule-data-utils'; import { EuiDataGridColumn } from '@elastic/eui'; -import type { ColumnHeaderOptions } from '@kbn/timelines-plugin/common'; import { translations } from '../../../../config'; export const addDisplayNames = ( - column: Pick & - ColumnHeaderOptions + column: Pick ) => { if (column.id === ALERT_REASON) { return { ...column, displayAsText: translations.alertsTable.reasonColumnDescription }; diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/default_columns.tsx b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/default_columns.tsx new file mode 100644 index 0000000000000..4c187514d41de --- /dev/null +++ b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/default_columns.tsx @@ -0,0 +1,52 @@ +/* + * 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. + */ + +/** + * We need to produce types and code transpilation at different folders during the build of the package. + * We have types and code at different imports because we don't want to import the whole package in the resulting webpack bundle for the plugin. + * This way plugins can do targeted imports to reduce the final code bundle + */ +import { ALERT_DURATION, ALERT_REASON, ALERT_STATUS, TIMESTAMP } from '@kbn/rule-data-utils'; + +import { EuiDataGridColumn } from '@elastic/eui'; + +import type { ColumnHeaderOptions } from '@kbn/timelines-plugin/common'; + +import { translations } from '../../../../config'; + +/** + * columns implements a subset of `EuiDataGrid`'s `EuiDataGridColumn` interface, + * plus additional TGrid column properties + */ +export const columns: Array< + Pick & ColumnHeaderOptions +> = [ + { + columnHeaderType: 'not-filtered', + displayAsText: translations.alertsTable.statusColumnDescription, + id: ALERT_STATUS, + initialWidth: 110, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: translations.alertsTable.lastUpdatedColumnDescription, + id: TIMESTAMP, + initialWidth: 230, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: translations.alertsTable.durationColumnDescription, + id: ALERT_DURATION, + initialWidth: 116, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: translations.alertsTable.reasonColumnDescription, + id: ALERT_REASON, + linkField: '*', + }, +]; diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/get_row_actions.tsx b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/get_row_actions.tsx similarity index 100% rename from x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/get_row_actions.tsx rename to x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/get_row_actions.tsx diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/translations.ts b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/translations.ts similarity index 100% rename from x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/translations.ts rename to x-pack/plugins/observability/public/pages/alerts/containers/alerts_table/translations.ts diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/alerts_table_t_grid.tsx deleted file mode 100644 index bcb2495d88b8f..0000000000000 --- a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/alerts_table_t_grid.tsx +++ /dev/null @@ -1,331 +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. - */ - -/** - * We need to produce types and code transpilation at different folders during the build of the package. - * We have types and code at different imports because we don't want to import the whole package in the resulting webpack bundle for the plugin. - * This way plugins can do targeted imports to reduce the final code bundle - */ -import { - ALERT_DURATION, - ALERT_EVALUATION_THRESHOLD, - ALERT_EVALUATION_VALUE, - ALERT_REASON, - ALERT_RULE_CATEGORY, - ALERT_RULE_NAME, - ALERT_STATUS, - ALERT_UUID, - TIMESTAMP, - ALERT_START, -} from '@kbn/rule-data-utils'; - -import { EuiDataGridColumn, EuiFlexGroup } from '@elastic/eui'; - -import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; - -import styled from 'styled-components'; -import React, { Suspense, useMemo, useState, useCallback, useEffect } from 'react'; - -import { pick } from 'lodash'; -import type { - TGridType, - TGridState, - TGridModel, - SortDirection, -} from '@kbn/timelines-plugin/public'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { - ActionProps, - ColumnHeaderOptions, - ControlColumnProps, - RowRenderer, -} from '@kbn/timelines-plugin/common'; -import { getAlertsPermissions } from '../../../../hooks/use_alert_permission'; - -import type { TopAlert } from '../alerts_page/types'; - -import { getRenderCellValue } from '../../components/render_cell_value'; -import { observabilityAppId, observabilityFeatureId } from '../../../../../common'; -import { useGetUserCasesPermissions } from '../../../../hooks/use_get_user_cases_permissions'; -import { usePluginContext } from '../../../../hooks/use_plugin_context'; -import { LazyAlertsFlyout } from '../../../..'; -import { translations } from '../../../../config'; -import { addDisplayNames } from './add_display_names'; -import { ObservabilityAppServices } from '../../../../application/types'; -import { useBulkAddToCaseActions } from '../../../../hooks/use_alert_bulk_case_actions'; -import { - ObservabilityActions, - ObservabilityActionsProps, -} from '../../components/observability_actions'; - -interface AlertsTableTGridProps { - indexNames: string[]; - rangeFrom: string; - rangeTo: string; - kuery?: string; - stateStorageKey: string; - storage: IStorageWrapper; - setRefetch: (ref: () => void) => void; - itemsPerPage?: number; -} - -const EventsThContent = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsTable__thContent ${className}`, -}))<{ textAlign?: string; width?: number }>` - font-size: ${({ theme }) => theme.eui.euiFontSizeXS}; - font-weight: ${({ theme }) => theme.eui.euiFontWeightBold}; - line-height: ${({ theme }) => theme.eui.euiLineHeight}; - min-width: 0; - padding: ${({ theme }) => theme.eui.euiSizeXS}; - text-align: ${({ textAlign }) => textAlign}; - width: ${({ width }) => - width != null - ? `${width}px` - : '100%'}; /* Using width: 100% instead of flex: 1 and max-width: 100% for IE11 */ - - > button.euiButtonIcon, - > .euiToolTipAnchor > button.euiButtonIcon { - margin-left: ${({ theme }) => `-${theme.eui.euiSizeXS}`}; - } -`; -/** - * columns implements a subset of `EuiDataGrid`'s `EuiDataGridColumn` interface, - * plus additional TGrid column properties - */ -export const columns: Array< - Pick & ColumnHeaderOptions -> = [ - { - columnHeaderType: 'not-filtered', - displayAsText: translations.alertsTable.statusColumnDescription, - id: ALERT_STATUS, - initialWidth: 110, - }, - { - columnHeaderType: 'not-filtered', - displayAsText: translations.alertsTable.lastUpdatedColumnDescription, - id: TIMESTAMP, - initialWidth: 230, - }, - { - columnHeaderType: 'not-filtered', - displayAsText: translations.alertsTable.durationColumnDescription, - id: ALERT_DURATION, - initialWidth: 116, - }, - { - columnHeaderType: 'not-filtered', - displayAsText: translations.alertsTable.reasonColumnDescription, - id: ALERT_REASON, - linkField: '*', - }, -]; - -const NO_ROW_RENDER: RowRenderer[] = []; - -const trailingControlColumns: never[] = []; - -const FIELDS_WITHOUT_CELL_ACTIONS = [ - '@timestamp', - 'signal.rule.risk_score', - 'signal.reason', - 'kibana.alert.duration.us', - 'kibana.alert.reason', -]; - -export function AlertsTableTGrid(props: AlertsTableTGridProps) { - const { - indexNames, - rangeFrom, - rangeTo, - kuery, - setRefetch, - stateStorageKey, - storage, - itemsPerPage, - } = props; - - const { - timelines, - application: { capabilities }, - } = useKibana().services; - const { observabilityRuleTypeRegistry, config } = usePluginContext(); - - const [flyoutAlert, setFlyoutAlert] = useState(undefined); - const [tGridState, setTGridState] = useState | null>( - storage.get(stateStorageKey) - ); - - const userCasesPermissions = useGetUserCasesPermissions(); - - const hasAlertsCrudPermissions = useCallback( - ({ ruleConsumer, ruleProducer }: { ruleConsumer: string; ruleProducer?: string }) => { - if (ruleConsumer === 'alerts' && ruleProducer) { - return getAlertsPermissions(capabilities, ruleProducer).crud; - } - return getAlertsPermissions(capabilities, ruleConsumer).crud; - }, - [capabilities] - ); - - const [deletedEventIds, setDeletedEventIds] = useState([]); - - useEffect(() => { - if (tGridState) { - const newState = { - ...tGridState, - columns: tGridState.columns?.map((c) => - pick(c, ['columnHeaderType', 'displayAsText', 'id', 'initialWidth', 'linkField']) - ), - }; - if (newState !== storage.get(stateStorageKey)) { - storage.set(stateStorageKey, newState); - } - } - }, [tGridState, stateStorageKey, storage]); - - const setEventsDeleted = useCallback((action) => { - if (action.isDeleted) { - setDeletedEventIds((ids) => [...ids, ...action.eventIds]); - } - }, []); - - const leadingControlColumns: ControlColumnProps[] = useMemo(() => { - return [ - { - id: 'expand', - width: 120, - headerCellRender: () => { - return {translations.alertsTable.actionsTextLabel}; - }, - rowCellRender: (actionProps: ActionProps) => { - return ( - - - - ); - }, - }, - ]; - }, [setEventsDeleted, observabilityRuleTypeRegistry, config]); - - const onStateChange = useCallback( - (state: TGridState) => { - const pickedState = pick(state.tableById['standalone-t-grid'], [ - 'columns', - 'sort', - 'selectedEventIds', - ]); - if (JSON.stringify(pickedState) !== JSON.stringify(tGridState)) { - setTGridState(pickedState); - } - }, - [tGridState] - ); - - const addToCaseBulkActions = useBulkAddToCaseActions(); - const bulkActions = useMemo( - () => ({ - alertStatusActions: false, - customBulkActions: addToCaseBulkActions, - }), - [addToCaseBulkActions] - ); - const tGridProps = useMemo(() => { - const type: TGridType = 'standalone'; - const sortDirection: SortDirection = 'desc'; - return { - appId: observabilityAppId, - casesOwner: observabilityFeatureId, - casePermissions: userCasesPermissions, - type, - columns: (tGridState?.columns ?? columns).map(addDisplayNames), - deletedEventIds, - disabledCellActions: FIELDS_WITHOUT_CELL_ACTIONS, - end: rangeTo, - filters: [], - hasAlertsCrudPermissions, - indexNames, - itemsPerPage, - itemsPerPageOptions: [10, 25, 50], - loadingText: translations.alertsTable.loadingTextLabel, - onStateChange, - query: { - query: kuery ?? '', - language: 'kuery', - }, - renderCellValue: getRenderCellValue({ setFlyoutAlert, observabilityRuleTypeRegistry }), - rowRenderers: NO_ROW_RENDER, - // TODO: implement Kibana data view runtime fields in observability - runtimeMappings: {}, - start: rangeFrom, - setRefetch, - bulkActions, - sort: tGridState?.sort ?? [ - { - columnId: '@timestamp', - columnType: 'date', - sortDirection, - }, - ], - queryFields: [ - ALERT_DURATION, - ALERT_EVALUATION_THRESHOLD, - ALERT_EVALUATION_VALUE, - ALERT_REASON, - ALERT_RULE_CATEGORY, - ALERT_RULE_NAME, - ALERT_STATUS, - ALERT_UUID, - ALERT_START, - TIMESTAMP, - ], - leadingControlColumns, - trailingControlColumns, - unit: (totalAlerts: number) => translations.alertsTable.showingAlertsTitle(totalAlerts), - }; - }, [ - userCasesPermissions, - tGridState?.columns, - tGridState?.sort, - deletedEventIds, - rangeTo, - hasAlertsCrudPermissions, - indexNames, - itemsPerPage, - observabilityRuleTypeRegistry, - onStateChange, - kuery, - rangeFrom, - setRefetch, - bulkActions, - leadingControlColumns, - ]); - - const handleFlyoutClose = () => setFlyoutAlert(undefined); - - return ( - <> - {flyoutAlert && ( - - - - )} - {timelines.getTGrid<'standalone'>(tGridProps)} - - ); -} diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/index.ts b/x-pack/plugins/observability/public/pages/alerts/containers/index.ts index 074f48f426640..23b65105b7881 100644 --- a/x-pack/plugins/observability/public/pages/alerts/containers/index.ts +++ b/x-pack/plugins/observability/public/pages/alerts/containers/index.ts @@ -6,5 +6,4 @@ */ export * from './alerts_page'; -export * from './alerts_table_t_grid'; export * from './state_container'; diff --git a/x-pack/plugins/observability/server/domain/services/date_range.test.ts b/x-pack/plugins/observability/server/domain/services/date_range.test.ts index 3553b04fa16e1..e4a8cdac45931 100644 --- a/x-pack/plugins/observability/server/domain/services/date_range.test.ts +++ b/x-pack/plugins/observability/server/domain/services/date_range.test.ts @@ -6,7 +6,7 @@ */ import { TimeWindow } from '../../types/models/time_window'; -import { Duration, DurationUnit } from '../../types/schema'; +import { Duration, DurationUnit } from '../../types/models'; import { toDateRange } from './date_range'; const THIRTY_DAYS = new Duration(30, DurationUnit.d); diff --git a/x-pack/plugins/observability/server/domain/services/date_range.ts b/x-pack/plugins/observability/server/domain/services/date_range.ts index adb2d3420bc97..e556d85a09f6f 100644 --- a/x-pack/plugins/observability/server/domain/services/date_range.ts +++ b/x-pack/plugins/observability/server/domain/services/date_range.ts @@ -7,13 +7,10 @@ import { assertNever } from '@kbn/std'; import moment from 'moment'; +import { toMomentUnitOfTime } from '../../types/models'; import type { TimeWindow } from '../../types/models/time_window'; -import { - calendarAlignedTimeWindowSchema, - DurationUnit, - rollingTimeWindowSchema, -} from '../../types/schema'; +import { calendarAlignedTimeWindowSchema, rollingTimeWindowSchema } from '../../types/schema'; export interface DateRange { from: Date; @@ -49,20 +46,3 @@ export const toDateRange = (timeWindow: TimeWindow, currentDate: Date = new Date assertNever(timeWindow); }; - -const toMomentUnitOfTime = (unit: DurationUnit): moment.unitOfTime.Diff => { - switch (unit) { - case DurationUnit.d: - return 'days'; - case DurationUnit.w: - return 'weeks'; - case DurationUnit.M: - return 'months'; - case DurationUnit.Q: - return 'quarters'; - case DurationUnit.Y: - return 'years'; - default: - assertNever(unit); - } -}; diff --git a/x-pack/plugins/observability/server/domain/services/index.ts b/x-pack/plugins/observability/server/domain/services/index.ts index 02bae9354dc08..8fd5a1e24b772 100644 --- a/x-pack/plugins/observability/server/domain/services/index.ts +++ b/x-pack/plugins/observability/server/domain/services/index.ts @@ -8,3 +8,4 @@ export * from './compute_error_budget'; export * from './compute_sli'; export * from './date_range'; +export * from './validate_slo'; diff --git a/x-pack/plugins/observability/server/domain/services/validate_slo.test.ts b/x-pack/plugins/observability/server/domain/services/validate_slo.test.ts new file mode 100644 index 0000000000000..2a1142aa22076 --- /dev/null +++ b/x-pack/plugins/observability/server/domain/services/validate_slo.test.ts @@ -0,0 +1,147 @@ +/* + * 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 { validateSLO } from '.'; +import { createSLO } from '../../services/slo/fixtures/slo'; +import { Duration, DurationUnit } from '../../types/models/duration'; + +describe('validateSLO', () => { + describe('any slo', () => { + it("throws when 'objective.target' is lte 0", () => { + const slo = createSLO({ objective: { target: 0 } }); + expect(() => validateSLO(slo)).toThrowError('Invalid objective.target'); + }); + + it("throws when 'objective.target' is gt 1", () => { + const slo = createSLO({ objective: { target: 1.0001 } }); + expect(() => validateSLO(slo)).toThrowError('Invalid objective.target'); + }); + + it("throws when time window duration unit is 'm'", () => { + const slo = createSLO({ + time_window: { duration: new Duration(1, DurationUnit.m), is_rolling: true }, + }); + expect(() => validateSLO(slo)).toThrowError('Invalid time_window.duration'); + }); + + it("throws when time window duration unit is 'h'", () => { + const slo = createSLO({ + time_window: { duration: new Duration(1, DurationUnit.h), is_rolling: true }, + }); + expect(() => validateSLO(slo)).toThrowError('Invalid time_window.duration'); + }); + }); + + describe('slo with timeslices budgeting method', () => { + it("throws when 'objective.timeslice_target' is not present", () => { + const slo = createSLO({ + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_window: new Duration(1, DurationUnit.m), + }, + }); + expect(() => validateSLO(slo)).toThrowError('Invalid objective.timeslice_target'); + }); + + it("throws when 'objective.timeslice_target' is lte 0", () => { + const slo = createSLO({ + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 0, + timeslice_window: new Duration(1, DurationUnit.m), + }, + }); + + expect(() => validateSLO(slo)).toThrowError('Invalid objective.timeslice_target'); + }); + + it("throws when 'objective.timeslice_target' is gt 1", () => { + const slo = createSLO({ + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 1.001, + timeslice_window: new Duration(1, DurationUnit.m), + }, + }); + expect(() => validateSLO(slo)).toThrowError('Invalid objective.timeslice_target'); + }); + + it("throws when 'objective.timeslice_window' is not present", () => { + const slo = createSLO({ + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 0.95, + }, + }); + + expect(() => validateSLO(slo)).toThrowError('Invalid objective.timeslice_window'); + }); + + it("throws when 'objective.timeslice_window' is not in minutes or hours", () => { + const slo = createSLO({ + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 0.95, + }, + }); + + expect(() => + validateSLO({ + ...slo, + objective: { ...slo.objective, timeslice_window: new Duration(1, DurationUnit.d) }, + }) + ).toThrowError('Invalid objective.timeslice_window'); + + expect(() => + validateSLO({ + ...slo, + objective: { ...slo.objective, timeslice_window: new Duration(1, DurationUnit.w) }, + }) + ).toThrowError('Invalid objective.timeslice_window'); + + expect(() => + validateSLO({ + ...slo, + objective: { ...slo.objective, timeslice_window: new Duration(1, DurationUnit.M) }, + }) + ).toThrowError('Invalid objective.timeslice_window'); + + expect(() => + validateSLO({ + ...slo, + objective: { ...slo.objective, timeslice_window: new Duration(1, DurationUnit.Q) }, + }) + ).toThrowError('Invalid objective.timeslice_window'); + + expect(() => + validateSLO({ + ...slo, + objective: { ...slo.objective, timeslice_window: new Duration(1, DurationUnit.Y) }, + }) + ).toThrowError('Invalid objective.timeslice_window'); + }); + + it("throws when 'objective.timeslice_window' is longer than 'slo.time_window'", () => { + const slo = createSLO({ + time_window: { duration: new Duration(1, DurationUnit.w), is_rolling: true }, + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 0.95, + timeslice_window: new Duration(169, DurationUnit.h), // 1 week + 1 hours = 169 hours + }, + }); + + expect(() => validateSLO(slo)).toThrowError('Invalid objective.timeslice_window'); + }); + }); +}); diff --git a/x-pack/plugins/observability/server/domain/services/validate_slo.ts b/x-pack/plugins/observability/server/domain/services/validate_slo.ts new file mode 100644 index 0000000000000..db9c1cbf97ddc --- /dev/null +++ b/x-pack/plugins/observability/server/domain/services/validate_slo.ts @@ -0,0 +1,61 @@ +/* + * 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 { IllegalArgumentError } from '../../errors'; +import { SLO } from '../../types/models'; +import { Duration, DurationUnit } from '../../types/models/duration'; +import { timeslicesBudgetingMethodSchema } from '../../types/schema'; + +/** + * Asserts the SLO is valid from a business invariants point of view. + * e.g. a 'target' objective requires a number between ]0, 1] + * e.g. a 'timeslices' budgeting method requires an objective's timeslice_target to be defined. + * + * @param slo {SLO} + */ +export function validateSLO(slo: SLO) { + if (!isValidTargetNumber(slo.objective.target)) { + throw new IllegalArgumentError('Invalid objective.target'); + } + + if (!isValidTimeWindowDuration(slo.time_window.duration)) { + throw new IllegalArgumentError('Invalid time_window.duration'); + } + + if (timeslicesBudgetingMethodSchema.is(slo.budgeting_method)) { + if ( + slo.objective.timeslice_target === undefined || + !isValidTargetNumber(slo.objective.timeslice_target) + ) { + throw new IllegalArgumentError('Invalid objective.timeslice_target'); + } + + if ( + slo.objective.timeslice_window === undefined || + !isValidTimesliceWindowDuration(slo.objective.timeslice_window, slo.time_window.duration) + ) { + throw new IllegalArgumentError('Invalid objective.timeslice_window'); + } + } +} + +function isValidTargetNumber(value: number): boolean { + return value > 0 && value <= 1; +} + +function isValidTimeWindowDuration(duration: Duration): boolean { + return [DurationUnit.d, DurationUnit.w, DurationUnit.M, DurationUnit.Q, DurationUnit.Y].includes( + duration.unit + ); +} + +function isValidTimesliceWindowDuration(timesliceWindow: Duration, timeWindow: Duration): boolean { + return ( + [DurationUnit.m, DurationUnit.h].includes(timesliceWindow.unit) && + timesliceWindow.isShorterThan(timeWindow) + ); +} diff --git a/x-pack/plugins/observability/server/errors/errors.ts b/x-pack/plugins/observability/server/errors/errors.ts index a83a0c31610e9..8f04cc58bc4da 100644 --- a/x-pack/plugins/observability/server/errors/errors.ts +++ b/x-pack/plugins/observability/server/errors/errors.ts @@ -17,3 +17,4 @@ export class ObservabilityError extends Error { export class SLONotFound extends ObservabilityError {} export class InternalQueryError extends ObservabilityError {} export class NotSupportedError extends ObservabilityError {} +export class IllegalArgumentError extends ObservabilityError {} diff --git a/x-pack/plugins/observability/server/services/slo/create_slo.ts b/x-pack/plugins/observability/server/services/slo/create_slo.ts index 35a908a48bd2f..6d79a6906fc88 100644 --- a/x-pack/plugins/observability/server/services/slo/create_slo.ts +++ b/x-pack/plugins/observability/server/services/slo/create_slo.ts @@ -12,6 +12,7 @@ import { ResourceInstaller } from './resource_installer'; import { SLORepository } from './slo_repository'; import { TransformManager } from './transform_manager'; import { CreateSLOParams, CreateSLOResponse } from '../../types/rest_specs'; +import { validateSLO } from '../../domain/services'; export class CreateSLO { constructor( @@ -22,6 +23,7 @@ export class CreateSLO { public async execute(params: CreateSLOParams): Promise { const slo = this.toSLO(params); + validateSLO(slo); await this.resourceInstaller.ensureCommonResourcesInstalled(); await this.repository.save(slo); diff --git a/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts b/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts index 58846f16a5163..a6d46b0689bb2 100644 --- a/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts +++ b/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts @@ -5,9 +5,10 @@ * 2.0. */ +import { cloneDeep } from 'lodash'; import uuid from 'uuid'; +import { Duration, DurationUnit } from '../../../types/models/duration'; -import { Duration, DurationUnit } from '../../../types/schema'; import { APMTransactionDurationIndicator, APMTransactionErrorRateIndicator, @@ -65,14 +66,14 @@ export const createSLOParams = (params: Partial = {}): CreateSL export const createSLO = (params: Partial = {}): SLO => { const now = new Date(); - return { + return cloneDeep({ ...defaultSLO, id: uuid.v1(), revision: 1, created_at: now, updated_at: now, ...params, - }; + }); }; export const createSLOWithCalendarTimeWindow = (params: Partial = {}): SLO => { diff --git a/x-pack/plugins/observability/server/services/slo/sli_client.test.ts b/x-pack/plugins/observability/server/services/slo/sli_client.test.ts index 7b0d0a04ab7af..7729bab2f9055 100644 --- a/x-pack/plugins/observability/server/services/slo/sli_client.test.ts +++ b/x-pack/plugins/observability/server/services/slo/sli_client.test.ts @@ -7,10 +7,10 @@ import { ElasticsearchClientMock, elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { SLO_DESTINATION_INDEX_NAME } from '../../assets/constants'; -import { toDateRange } from '../../domain/services/date_range'; +import { toDateRange } from '../../domain/services'; import { InternalQueryError } from '../../errors'; -import { Duration, DurationUnit } from '../../types/schema'; -import { createAPMTransactionErrorRateIndicator, createSLO } from './fixtures/slo'; +import { Duration, DurationUnit } from '../../types/models'; +import { createSLO } from './fixtures/slo'; import { DefaultSLIClient } from './sli_client'; describe('SLIClient', () => { @@ -21,31 +21,8 @@ describe('SLIClient', () => { }); describe('fetchCurrentSLIData', () => { - it('throws when aggregations failed', async () => { - const slo = createSLO({ indicator: createAPMTransactionErrorRateIndicator() }); - esClientMock.search.mockResolvedValueOnce({ - took: 100, - timed_out: false, - _shards: { - total: 0, - successful: 0, - skipped: 0, - failed: 0, - }, - hits: { - hits: [], - }, - aggregations: {}, - }); - const sliClient = new DefaultSLIClient(esClientMock); - - await expect(sliClient.fetchCurrentSLIData(slo)).rejects.toThrowError( - new InternalQueryError('SLI aggregation query') - ); - }); - - describe('For a rolling time window SLO type', () => { - it('returns the aggregated good and total values', async () => { + describe('for SLO defined with occurrences budgeting method', () => { + it('throws when aggregations failed', async () => { const slo = createSLO({ time_window: { duration: new Duration(7, DurationUnit.d), @@ -64,53 +41,144 @@ describe('SLIClient', () => { hits: { hits: [], }, - aggregations: { - full_window: { buckets: [{ good: { value: 90 }, total: { value: 100 } }] }, - }, + aggregations: {}, }); const sliClient = new DefaultSLIClient(esClientMock); - const result = await sliClient.fetchCurrentSLIData(slo); - - expect(result).toEqual({ good: 90, total: 100 }); - expect(esClientMock.search).toHaveBeenCalledWith( - expect.objectContaining({ - index: `${SLO_DESTINATION_INDEX_NAME}*`, - query: { - bool: { - filter: [ - { term: { 'slo.id': slo.id } }, - { term: { 'slo.revision': slo.revision } }, - ], - }, + await expect(sliClient.fetchCurrentSLIData(slo)).rejects.toThrowError( + new InternalQueryError('SLI aggregation query') + ); + }); + + describe('for a rolling time window SLO type', () => { + it('returns the aggregated good and total values', async () => { + const slo = createSLO({ + time_window: { + duration: new Duration(7, DurationUnit.d), + is_rolling: true, }, - aggs: { - full_window: { - date_range: { - field: '@timestamp', - ranges: [{ from: 'now-7d/m', to: 'now/m' }], - }, - aggs: { - good: { sum: { field: 'slo.numerator' } }, - total: { sum: { field: 'slo.denominator' } }, + }); + esClientMock.search.mockResolvedValueOnce({ + took: 100, + timed_out: false, + _shards: { + total: 0, + successful: 0, + skipped: 0, + failed: 0, + }, + hits: { + hits: [], + }, + aggregations: { + good: { value: 90 }, + total: { value: 100 }, + }, + }); + const sliClient = new DefaultSLIClient(esClientMock); + + const result = await sliClient.fetchCurrentSLIData(slo); + + expect(result).toEqual({ good: 90, total: 100 }); + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ + index: `${SLO_DESTINATION_INDEX_NAME}*`, + query: { + bool: { + filter: [ + { term: { 'slo.id': slo.id } }, + { term: { 'slo.revision': slo.revision } }, + { + range: { + '@timestamp': { gte: 'now-7d/m', lt: 'now/m' }, + }, + }, + ], }, }, + aggs: { + good: { sum: { field: 'slo.numerator' } }, + total: { sum: { field: 'slo.denominator' } }, + }, + }) + ); + }); + }); + + describe('for a calendar aligned time window SLO type', () => { + it('returns the aggregated good and total values', async () => { + const slo = createSLO({ + time_window: { + duration: new Duration(1, DurationUnit.M), + calendar: { + start_time: new Date('2022-09-01T00:00:00.000Z'), + }, }, - }) - ); + }); + esClientMock.search.mockResolvedValueOnce({ + took: 100, + timed_out: false, + _shards: { + total: 0, + successful: 0, + skipped: 0, + failed: 0, + }, + hits: { + hits: [], + }, + aggregations: { + good: { value: 90 }, + total: { value: 100 }, + }, + }); + const sliClient = new DefaultSLIClient(esClientMock); + + const result = await sliClient.fetchCurrentSLIData(slo); + + const expectedDateRange = toDateRange(slo.time_window); + + expect(result).toEqual({ good: 90, total: 100 }); + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ + index: `${SLO_DESTINATION_INDEX_NAME}*`, + query: { + bool: { + filter: [ + { term: { 'slo.id': slo.id } }, + { term: { 'slo.revision': slo.revision } }, + { + range: { + '@timestamp': { + gte: expectedDateRange.from.toISOString(), + lt: expectedDateRange.to.toISOString(), + }, + }, + }, + ], + }, + }, + aggs: { + good: { sum: { field: 'slo.numerator' } }, + total: { sum: { field: 'slo.denominator' } }, + }, + }) + ); + }); }); }); - describe('For a calendar aligned time window SLO type', () => { - it('returns the aggregated good and total values', async () => { + describe('for SLO defined with timeslices budgeting method', () => { + it('throws when aggregations failed', async () => { const slo = createSLO({ - time_window: { - duration: new Duration(1, DurationUnit.M), - calendar: { - start_time: new Date('2022-09-01T00:00:00.000Z'), - }, + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 0.95, + timeslice_window: new Duration(10, DurationUnit.m), }, }); + esClientMock.search.mockResolvedValueOnce({ took: 100, timed_out: false, @@ -123,47 +191,228 @@ describe('SLIClient', () => { hits: { hits: [], }, - aggregations: { - full_window: { buckets: [{ good: { value: 90 }, total: { value: 100 } }] }, - }, + aggregations: {}, }); const sliClient = new DefaultSLIClient(esClientMock); - const result = await sliClient.fetchCurrentSLIData(slo); - - const expectedDateRange = toDateRange(slo.time_window); + await expect(sliClient.fetchCurrentSLIData(slo)).rejects.toThrowError( + new InternalQueryError('SLI aggregation query') + ); + }); - expect(result).toEqual({ good: 90, total: 100 }); - expect(esClientMock.search).toHaveBeenCalledWith( - expect.objectContaining({ - index: `${SLO_DESTINATION_INDEX_NAME}*`, - query: { - bool: { - filter: [ - { term: { 'slo.id': slo.id } }, - { term: { 'slo.revision': slo.revision } }, - ], + describe('for a calendar aligned time window SLO type', () => { + it('returns the aggregated good and total values', async () => { + const slo = createSLO({ + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 0.9, + timeslice_window: new Duration(10, DurationUnit.m), + }, + time_window: { + duration: new Duration(1, DurationUnit.M), + calendar: { + start_time: new Date('2022-09-01T00:00:00.000Z'), }, }, - aggs: { - full_window: { - date_range: { - field: '@timestamp', - ranges: [ + }); + esClientMock.search.mockResolvedValueOnce({ + took: 100, + timed_out: false, + _shards: { + total: 0, + successful: 0, + skipped: 0, + failed: 0, + }, + hits: { + hits: [], + }, + aggregations: { + slices: { buckets: [] }, + good: { value: 90 }, + total: { value: 100 }, + }, + }); + const sliClient = new DefaultSLIClient(esClientMock); + + const result = await sliClient.fetchCurrentSLIData(slo); + + const expectedDateRange = toDateRange(slo.time_window); + + expect(result).toEqual({ good: 90, total: 100 }); + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ + index: `${SLO_DESTINATION_INDEX_NAME}*`, + query: { + bool: { + filter: [ + { term: { 'slo.id': slo.id } }, + { term: { 'slo.revision': slo.revision } }, { - from: expectedDateRange.from.toISOString(), - to: expectedDateRange.to.toISOString(), + range: { + '@timestamp': { + gte: expectedDateRange.from.toISOString(), + lt: expectedDateRange.to.toISOString(), + }, + }, }, ], }, - aggs: { - good: { sum: { field: 'slo.numerator' } }, - total: { sum: { field: 'slo.denominator' } }, + }, + aggs: { + slices: { + date_histogram: { + field: '@timestamp', + fixed_interval: '10m', + }, + aggs: { + good: { + sum: { + field: 'slo.numerator', + }, + }, + total: { + sum: { + field: 'slo.denominator', + }, + }, + good_slice: { + bucket_script: { + buckets_path: { + good: 'good', + total: 'total', + }, + script: `params.good / params.total >= ${slo.objective.timeslice_target} ? 1 : 0`, + }, + }, + count_slice: { + bucket_script: { + buckets_path: {}, + script: '1', + }, + }, + }, + }, + good: { + sum_bucket: { + buckets_path: 'slices>good_slice.value', + }, + }, + total: { + sum_bucket: { + buckets_path: 'slices>count_slice.value', + }, }, }, + }) + ); + }); + }); + + describe('for a rolling time window SLO type', () => { + it('returns the aggregated good and total values', async () => { + const slo = createSLO({ + budgeting_method: 'timeslices', + objective: { + target: 0.95, + timeslice_target: 0.9, + timeslice_window: new Duration(10, DurationUnit.m), }, - }) - ); + time_window: { + duration: new Duration(1, DurationUnit.M), + is_rolling: true, + }, + }); + esClientMock.search.mockResolvedValueOnce({ + took: 100, + timed_out: false, + _shards: { + total: 0, + successful: 0, + skipped: 0, + failed: 0, + }, + hits: { + hits: [], + }, + aggregations: { + good: { value: 90 }, + total: { value: 100 }, + }, + }); + const sliClient = new DefaultSLIClient(esClientMock); + + const result = await sliClient.fetchCurrentSLIData(slo); + + expect(result).toEqual({ good: 90, total: 100 }); + expect(esClientMock.search).toHaveBeenCalledWith( + expect.objectContaining({ + index: `${SLO_DESTINATION_INDEX_NAME}*`, + query: { + bool: { + filter: [ + { term: { 'slo.id': slo.id } }, + { term: { 'slo.revision': slo.revision } }, + { + range: { + '@timestamp': { + gte: 'now-1M/m', + lt: 'now/m', + }, + }, + }, + ], + }, + }, + aggs: { + slices: { + date_histogram: { + field: '@timestamp', + fixed_interval: '10m', + }, + aggs: { + good: { + sum: { + field: 'slo.numerator', + }, + }, + total: { + sum: { + field: 'slo.denominator', + }, + }, + good_slice: { + bucket_script: { + buckets_path: { + good: 'good', + total: 'total', + }, + script: `params.good / params.total >= ${slo.objective.timeslice_target} ? 1 : 0`, + }, + }, + count_slice: { + bucket_script: { + buckets_path: {}, + script: '1', + }, + }, + }, + }, + good: { + sum_bucket: { + buckets_path: 'slices>good_slice.value', + }, + }, + total: { + sum_bucket: { + buckets_path: 'slices>count_slice.value', + }, + }, + }, + }) + ); + }); }); }); }); diff --git a/x-pack/plugins/observability/server/services/slo/sli_client.ts b/x-pack/plugins/observability/server/services/slo/sli_client.ts index 93d1e7b207827..dc97aa1c651f0 100644 --- a/x-pack/plugins/observability/server/services/slo/sli_client.ts +++ b/x-pack/plugins/observability/server/services/slo/sli_client.ts @@ -5,77 +5,143 @@ * 2.0. */ +import { AggregationsSumAggregate } from '@elastic/elasticsearch/lib/api/types'; import { ElasticsearchClient } from '@kbn/core/server'; import { assertNever } from '@kbn/std'; import { SLO_DESTINATION_INDEX_NAME } from '../../assets/constants'; import { toDateRange } from '../../domain/services/date_range'; -import { InternalQueryError, NotSupportedError } from '../../errors'; -import { IndicatorData, SLO } from '../../types/models'; +import { InternalQueryError } from '../../errors'; +import { Duration, IndicatorData, SLO } from '../../types/models'; import { calendarAlignedTimeWindowSchema, rollingTimeWindowSchema } from '../../types/schema'; +import { + occurencesBudgetingMethodSchema, + timeslicesBudgetingMethodSchema, +} from '../../types/schema'; export interface SLIClient { fetchCurrentSLIData(slo: SLO): Promise; } +type AggKey = 'good' | 'total'; + export class DefaultSLIClient implements SLIClient { constructor(private esClient: ElasticsearchClient) {} async fetchCurrentSLIData(slo: SLO): Promise { - if (slo.budgeting_method !== 'occurrences') { - throw new NotSupportedError(`Budgeting method: ${slo.budgeting_method}`); + if (occurencesBudgetingMethodSchema.is(slo.budgeting_method)) { + const result = await this.esClient.search>({ + ...commonQuery(slo), + aggs: { + good: { sum: { field: 'slo.numerator' } }, + total: { sum: { field: 'slo.denominator' } }, + }, + }); + + return handleResult(result.aggregations); } - const result = await this.esClient.search({ - size: 0, - index: `${SLO_DESTINATION_INDEX_NAME}*`, - query: { - bool: { - filter: [{ term: { 'slo.id': slo.id } }, { term: { 'slo.revision': slo.revision } }], - }, - }, - aggs: { - full_window: { - date_range: { - field: '@timestamp', - ranges: [fromSLOTimeWindowToEsRange(slo)], + if (timeslicesBudgetingMethodSchema.is(slo.budgeting_method)) { + const result = await this.esClient.search>({ + ...commonQuery(slo), + aggs: { + slices: { + date_histogram: { + field: '@timestamp', + fixed_interval: toInterval(slo.objective.timeslice_window), + }, + aggs: { + good: { sum: { field: 'slo.numerator' } }, + total: { sum: { field: 'slo.denominator' } }, + good_slice: { + bucket_script: { + buckets_path: { + good: 'good', + total: 'total', + }, + script: `params.good / params.total >= ${slo.objective.timeslice_target} ? 1 : 0`, + }, + }, + count_slice: { + bucket_script: { + buckets_path: {}, + script: '1', + }, + }, + }, }, - aggs: { - good: { sum: { field: 'slo.numerator' } }, - total: { sum: { field: 'slo.denominator' } }, + good: { + sum_bucket: { + buckets_path: 'slices>good_slice.value', + }, + }, + total: { + sum_bucket: { + buckets_path: 'slices>count_slice.value', + }, }, }, - }, - }); + }); - // @ts-ignore buckets is not recognized - const aggs = result.aggregations?.full_window?.buckets[0]; - if (aggs === undefined) { - throw new InternalQueryError('SLI aggregation query'); + return handleResult(result.aggregations); } - return { - good: aggs.good.value, - total: aggs.total.value, - }; + assertNever(slo.budgeting_method); } } -function fromSLOTimeWindowToEsRange(slo: SLO): { from: string; to: string } { +function fromSLOTimeWindowToEsRange(slo: SLO): { gte: string; lt: string } { if (calendarAlignedTimeWindowSchema.is(slo.time_window)) { const dateRange = toDateRange(slo.time_window); return { - from: `${dateRange.from.toISOString()}`, - to: `${dateRange.to.toISOString()}`, + gte: `${dateRange.from.toISOString()}`, + lt: `${dateRange.to.toISOString()}`, }; } if (rollingTimeWindowSchema.is(slo.time_window)) { return { - from: `now-${slo.time_window.duration.value}${slo.time_window.duration.unit}/m`, - to: `now/m`, + gte: `now-${slo.time_window.duration.value}${slo.time_window.duration.unit}/m`, + lt: `now/m`, }; } assertNever(slo.time_window); } + +function commonQuery(slo: SLO) { + return { + size: 0, + index: `${SLO_DESTINATION_INDEX_NAME}*`, + query: { + bool: { + filter: [ + { term: { 'slo.id': slo.id } }, + { term: { 'slo.revision': slo.revision } }, + { range: { '@timestamp': fromSLOTimeWindowToEsRange(slo) } }, + ], + }, + }, + }; +} + +function handleResult( + aggregations: Record | undefined +): IndicatorData { + const good = aggregations?.good; + const total = aggregations?.total; + if (good === undefined || good.value === null || total === undefined || total.value === null) { + throw new InternalQueryError('SLI aggregation query'); + } + + return { + good: good.value, + total: total.value, + }; +} + +function toInterval(duration: Duration | undefined): string { + if (duration === undefined) return '1m'; + + return `${duration.value}${duration.unit}`; +} diff --git a/x-pack/plugins/observability/server/services/slo/update_slo.ts b/x-pack/plugins/observability/server/services/slo/update_slo.ts index e356cb4701c85..9daf1596e442a 100644 --- a/x-pack/plugins/observability/server/services/slo/update_slo.ts +++ b/x-pack/plugins/observability/server/services/slo/update_slo.ts @@ -17,6 +17,7 @@ import { import { SLORepository } from './slo_repository'; import { TransformManager } from './transform_manager'; import { SLO } from '../../types/models'; +import { validateSLO } from '../../domain/services'; export class UpdateSLO { constructor( @@ -45,6 +46,7 @@ export class UpdateSLO { private updateSLO(originalSlo: SLO, params: UpdateSLOParams) { let hasBreakingChange = false; const updatedSlo: SLO = Object.assign({}, originalSlo, params, { updated_at: new Date() }); + validateSLO(updatedSlo); if (!deepEqual(originalSlo.indicator, updatedSlo.indicator)) { hasBreakingChange = true; diff --git a/x-pack/plugins/observability/server/types/models/duration.test.ts b/x-pack/plugins/observability/server/types/models/duration.test.ts new file mode 100644 index 0000000000000..4383c8e3ddd79 --- /dev/null +++ b/x-pack/plugins/observability/server/types/models/duration.test.ts @@ -0,0 +1,45 @@ +/* + * 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 { Duration, DurationUnit } from './duration'; + +describe('Duration', () => { + it('throws when value is negative', () => { + expect(() => new Duration(-1, DurationUnit.d)).toThrow('invalid duration value'); + }); + + it('throws when value is zero', () => { + expect(() => new Duration(0, DurationUnit.d)).toThrow('invalid duration value'); + }); + + it('throws when unit is not valid', () => { + expect(() => new Duration(1, 'z' as DurationUnit)).toThrow('invalid duration unit'); + }); + + describe('isShorterThan', () => { + it('returns true when the current duration is shorter than the other duration', () => { + const short = new Duration(1, DurationUnit.m); + expect(short.isShorterThan(new Duration(1, DurationUnit.h))).toBe(true); + expect(short.isShorterThan(new Duration(1, DurationUnit.d))).toBe(true); + expect(short.isShorterThan(new Duration(1, DurationUnit.w))).toBe(true); + expect(short.isShorterThan(new Duration(1, DurationUnit.M))).toBe(true); + expect(short.isShorterThan(new Duration(1, DurationUnit.Q))).toBe(true); + expect(short.isShorterThan(new Duration(1, DurationUnit.Y))).toBe(true); + }); + + it('returns false when the current duration is longer (or equal) than the other duration', () => { + const long = new Duration(1, DurationUnit.Y); + expect(long.isShorterThan(new Duration(1, DurationUnit.m))).toBe(false); + expect(long.isShorterThan(new Duration(1, DurationUnit.h))).toBe(false); + expect(long.isShorterThan(new Duration(1, DurationUnit.d))).toBe(false); + expect(long.isShorterThan(new Duration(1, DurationUnit.w))).toBe(false); + expect(long.isShorterThan(new Duration(1, DurationUnit.M))).toBe(false); + expect(long.isShorterThan(new Duration(1, DurationUnit.Q))).toBe(false); + expect(long.isShorterThan(new Duration(1, DurationUnit.Y))).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/observability/server/types/models/duration.ts b/x-pack/plugins/observability/server/types/models/duration.ts new file mode 100644 index 0000000000000..e34a748e30ba6 --- /dev/null +++ b/x-pack/plugins/observability/server/types/models/duration.ts @@ -0,0 +1,59 @@ +/* + * 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 { assertNever } from '@kbn/std'; +import * as moment from 'moment'; + +enum DurationUnit { + 'm' = 'm', + 'h' = 'h', + 'd' = 'd', + 'w' = 'w', + 'M' = 'M', + 'Q' = 'Q', + 'Y' = 'Y', +} + +class Duration { + constructor(public readonly value: number, public readonly unit: DurationUnit) { + if (isNaN(value) || value <= 0) { + throw new Error('invalid duration value'); + } + if (!Object.values(DurationUnit).includes(unit as unknown as DurationUnit)) { + throw new Error('invalid duration unit'); + } + } + + isShorterThan(other: Duration): boolean { + const otherDurationMoment = moment.duration(other.value, toMomentUnitOfTime(other.unit)); + const currentDurationMoment = moment.duration(this.value, toMomentUnitOfTime(this.unit)); + return currentDurationMoment.asSeconds() < otherDurationMoment.asSeconds(); + } +} + +const toMomentUnitOfTime = (unit: DurationUnit): moment.unitOfTime.Diff => { + switch (unit) { + case DurationUnit.m: + return 'minutes'; + case DurationUnit.h: + return 'hours'; + case DurationUnit.d: + return 'days'; + case DurationUnit.w: + return 'weeks'; + case DurationUnit.M: + return 'months'; + case DurationUnit.Q: + return 'quarters'; + case DurationUnit.Y: + return 'years'; + default: + assertNever(unit); + } +}; + +export { Duration, DurationUnit, toMomentUnitOfTime }; diff --git a/x-pack/plugins/observability/server/types/models/index.ts b/x-pack/plugins/observability/server/types/models/index.ts index 0f83e97aee6fd..d27c9f27c868b 100644 --- a/x-pack/plugins/observability/server/types/models/index.ts +++ b/x-pack/plugins/observability/server/types/models/index.ts @@ -8,3 +8,4 @@ export * from './slo'; export * from './indicators'; export * from './error_budget'; +export * from './duration'; diff --git a/x-pack/plugins/observability/server/types/schema/duration.ts b/x-pack/plugins/observability/server/types/schema/duration.ts index 68f6fad27a772..b4fa5065063f3 100644 --- a/x-pack/plugins/observability/server/types/schema/duration.ts +++ b/x-pack/plugins/observability/server/types/schema/duration.ts @@ -7,25 +7,7 @@ import { either } from 'fp-ts/lib/Either'; import * as t from 'io-ts'; - -enum DurationUnit { - 'd' = 'd', - 'w' = 'w', - 'M' = 'M', - 'Q' = 'Q', - 'Y' = 'Y', -} - -class Duration { - constructor(public readonly value: number, public readonly unit: DurationUnit) { - if (isNaN(value) || value <= 0) { - throw new Error('invalid duration value'); - } - if (!Object.values(DurationUnit).includes(unit as unknown as DurationUnit)) { - throw new Error('invalid duration unit'); - } - } -} +import { Duration, DurationUnit } from '../models/duration'; const durationType = new t.Type( 'Duration', @@ -45,4 +27,4 @@ const durationType = new t.Type( (duration: Duration): string => `${duration.value}${duration.unit}` ); -export { Duration, DurationUnit, durationType }; +export { durationType }; diff --git a/x-pack/plugins/observability/server/types/schema/schema.test.ts b/x-pack/plugins/observability/server/types/schema/schema.test.ts index 69cdb00aac095..1f16c1dfa267e 100644 --- a/x-pack/plugins/observability/server/types/schema/schema.test.ts +++ b/x-pack/plugins/observability/server/types/schema/schema.test.ts @@ -10,7 +10,6 @@ import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import { dateType } from './common'; -import { Duration, DurationUnit } from './duration'; describe('Schema', () => { describe('DateType', () => { @@ -42,18 +41,4 @@ describe('Schema', () => { ).toThrow(new Error('decode')); }); }); - - describe('Duration', () => { - it('throws when value is negative', () => { - expect(() => new Duration(-1, DurationUnit.d)).toThrow('invalid duration value'); - }); - - it('throws when value is zero', () => { - expect(() => new Duration(0, DurationUnit.d)).toThrow('invalid duration value'); - }); - - it('throws when unit is not valid', () => { - expect(() => new Duration(1, 'z' as DurationUnit)).toThrow('invalid duration unit'); - }); - }); }); diff --git a/x-pack/plugins/observability/server/types/schema/slo.ts b/x-pack/plugins/observability/server/types/schema/slo.ts index fbcf3ae458ad4..e9a3a752c8840 100644 --- a/x-pack/plugins/observability/server/types/schema/slo.ts +++ b/x-pack/plugins/observability/server/types/schema/slo.ts @@ -6,11 +6,24 @@ */ import * as t from 'io-ts'; +import { durationType } from './duration'; -const budgetingMethodSchema = t.literal('occurrences'); +const occurencesBudgetingMethodSchema = t.literal('occurrences'); +const timeslicesBudgetingMethodSchema = t.literal('timeslices'); -const objectiveSchema = t.type({ - target: t.number, -}); +const budgetingMethodSchema = t.union([ + occurencesBudgetingMethodSchema, + timeslicesBudgetingMethodSchema, +]); -export { budgetingMethodSchema, objectiveSchema }; +const objectiveSchema = t.intersection([ + t.type({ target: t.number }), + t.partial({ timeslice_target: t.number, timeslice_window: durationType }), +]); + +export { + budgetingMethodSchema, + occurencesBudgetingMethodSchema, + timeslicesBudgetingMethodSchema, + objectiveSchema, +}; diff --git a/x-pack/plugins/osquery/server/utils/register_features.ts b/x-pack/plugins/osquery/server/utils/register_features.ts index 4925b1ea14ad6..5af2335489dff 100644 --- a/x-pack/plugins/osquery/server/utils/register_features.ts +++ b/x-pack/plugins/osquery/server/utils/register_features.ts @@ -115,7 +115,7 @@ export const registerFeatures = (features: SetupPlugins['features']) => { name: 'All', savedObject: { all: [savedQuerySavedObjectType], - read: [], + read: ['tag'], }, ui: ['writeSavedQueries', 'readSavedQueries'], }, @@ -126,7 +126,7 @@ export const registerFeatures = (features: SetupPlugins['features']) => { name: 'Read', savedObject: { all: [], - read: [savedQuerySavedObjectType], + read: [savedQuerySavedObjectType, 'tag'], }, ui: ['readSavedQueries'], }, @@ -149,7 +149,7 @@ export const registerFeatures = (features: SetupPlugins['features']) => { name: 'All', savedObject: { all: [packSavedObjectType, packAssetSavedObjectType], - read: [], + read: ['tag'], }, ui: ['writePacks', 'readPacks'], }, @@ -160,7 +160,7 @@ export const registerFeatures = (features: SetupPlugins['features']) => { name: 'Read', savedObject: { all: [], - read: [packSavedObjectType], + read: [packSavedObjectType, 'tag'], }, ui: ['readPacks'], }, diff --git a/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap b/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap index 690259a1c240e..057f85d2c81d7 100644 --- a/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap +++ b/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap @@ -36,7 +36,7 @@ Object { "pollEnabled": true, "pollInterval": "PT3S", "pollIntervalErrorMultiplier": 10, - "timeout": "PT2M", + "timeout": "PT4M", }, "roles": Object { "allow": Array [ @@ -82,7 +82,7 @@ Object { "pollEnabled": true, "pollInterval": "PT3S", "pollIntervalErrorMultiplier": 10, - "timeout": "PT2M", + "timeout": "PT4M", }, "roles": Object { "allow": Array [ diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index c5ec1a7c22c8d..fc6ed9ae07390 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -42,7 +42,7 @@ const QueueSchema = schema.object({ }), pollIntervalErrorMultiplier: schema.number({ defaultValue: 10 }), timeout: schema.oneOf([schema.number(), schema.duration()], { - defaultValue: moment.duration({ minutes: 2 }), + defaultValue: moment.duration({ minutes: 4 }), }), }); diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts index a654d94822485..30b867d114446 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts @@ -24,7 +24,7 @@ import { defaultLifecyclePolicy } from '../../common/assets/lifecycle_policies/d import type { IndexInfo } from './index_info'; const INSTALLATION_TIMEOUT = 20 * 60 * 1000; // 20 minutes - +const TOTAL_FIELDS_LIMIT = 1900; interface ConstructorOptions { getResourceName(relativeName: string): string; getClusterClient: () => Promise; @@ -169,10 +169,32 @@ export class ResourceInstaller { // Find all concrete indices for all namespaces of the index. const concreteIndices = await this.fetchConcreteIndices(aliases, backingIndices); + // Update total field limit setting of found indices + await Promise.all(concreteIndices.map((item) => this.updateTotalFieldLimitSetting(item))); // Update mappings of the found indices. await Promise.all(concreteIndices.map((item) => this.updateAliasWriteIndexMapping(item))); } + private async updateTotalFieldLimitSetting({ index, alias }: ConcreteIndexInfo) { + const { logger, getClusterClient } = this.options; + const clusterClient = await getClusterClient(); + + try { + await clusterClient.indices.putSettings({ + index, + body: { + 'index.mapping.total_fields.limit': TOTAL_FIELDS_LIMIT, + }, + }); + return; + } catch (err) { + logger.error( + `Failed to PUT index.mapping.total_fields.limit settings for alias ${alias}: ${err.message}` + ); + throw err; + } + } + // NOTE / IMPORTANT: Please note this will update the mappings of backing indices but // *not* the settings. This is due to the fact settings can be classed as dynamic and static, // and static updates will fail on an index that isn't closed. New settings *will* be applied as part @@ -350,7 +372,7 @@ export class ResourceInstaller { name: ilmPolicyName, rollover_alias: primaryNamespacedAlias, }, - 'index.mapping.total_fields.limit': 1900, + 'index.mapping.total_fields.limit': TOTAL_FIELDS_LIMIT, auto_expand_replicas: '0-1', }, mappings: { diff --git a/x-pack/plugins/saved_objects_tagging/common/constants.ts b/x-pack/plugins/saved_objects_tagging/common/constants.ts index acd9800e03ce5..c65e52e2ff04b 100644 --- a/x-pack/plugins/saved_objects_tagging/common/constants.ts +++ b/x-pack/plugins/saved_objects_tagging/common/constants.ts @@ -20,4 +20,13 @@ export const tagManagementSectionId = 'tags'; /** * The list of saved object types that are currently supporting tagging. */ -export const taggableTypes = ['dashboard', 'visualization', 'map', 'lens', 'search']; +export const taggableTypes = [ + 'dashboard', + 'visualization', + 'map', + 'lens', + 'search', + 'osquery-pack', + 'osquery-pack-asset', + 'osquery-saved-query', +]; diff --git a/x-pack/plugins/saved_objects_tagging/server/usage/schema.ts b/x-pack/plugins/saved_objects_tagging/server/usage/schema.ts index 5f0c23a54f9e5..9f516c953cab1 100644 --- a/x-pack/plugins/saved_objects_tagging/server/usage/schema.ts +++ b/x-pack/plugins/saved_objects_tagging/server/usage/schema.ts @@ -23,5 +23,8 @@ export const tagUsageCollectorSchema: MakeSchemaFrom = { visualization: perTypeSchema, map: perTypeSchema, search: perTypeSchema, + 'osquery-pack': perTypeSchema, + 'osquery-pack-asset': perTypeSchema, + 'osquery-saved-query': perTypeSchema, }, }; diff --git a/x-pack/plugins/screenshotting/README.md b/x-pack/plugins/screenshotting/README.md index 3a3ea87448e64..04b7d07f223c4 100644 --- a/x-pack/plugins/screenshotting/README.md +++ b/x-pack/plugins/screenshotting/README.md @@ -89,9 +89,9 @@ Option | Required | Default | Description `layout` | no | `{}` | Page layout parameters describing characteristics of the capturing screenshot (e.g., dimensions, zoom, etc.). `request` | no | _none_ | Kibana Request reference to extract headers from. `timeouts` | no | _none_ | Timeouts for each phase of the screenshot. -`timeouts.openUrl` | no | `60000` | The timeout in milliseconds to allow the Chromium browser to wait for the "Loading…" screen to dismiss and find the initial data for the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. -`timeouts.renderComplete` | no | `30000` | The timeout in milliseconds to allow the Chromium browser to wait for all visualizations to fetch and render the data. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. -`timeouts.waitForElements` | no | `30000` | The timeout in milliseconds to allow the Chromium browser to wait for all visualization panels to load on the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. +`timeouts.openUrl` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for the "Loading…" screen to dismiss and find the initial data for the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. +`timeouts.renderComplete` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for all visualizations to fetch and render the data. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. +`timeouts.waitForElements` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for all visualization panels to load on the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. `urls` | no | `[]` | The list or URL to take screenshots of. Every item can either be a string or a tuple containing a URL and a context. The contextual data can be gathered using the screenshot mode plugin. Mutually exclusive with the `expression` parameter. #### `diagnose(flags?: string[]): Observable` diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts b/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts index 3bdef53bc6a68..590d8668e4874 100644 --- a/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts +++ b/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts @@ -12,7 +12,7 @@ import { } from '@kbn/screenshot-mode-plugin/server'; import { truncate } from 'lodash'; import open from 'opn'; -import puppeteer, { ElementHandle, EvaluateFn, Page, SerializableOrJSHandle } from 'puppeteer'; +import puppeteer, { ElementHandle, Page, EvaluateFunc } from 'puppeteer'; import { Subject } from 'rxjs'; import { parse as parseUrl } from 'url'; import { getDisallowedOutgoingUrlError } from '.'; @@ -23,6 +23,16 @@ import { allowRequest } from '../network_policy'; import { stripUnsafeHeaders } from './strip_unsafe_headers'; import { getFooterTemplate, getHeaderTemplate } from './templates'; +declare module 'puppeteer' { + interface Page { + _client(): CDPSession; + } + + interface Target { + _targetId: string; + } +} + export type Context = Record; export interface ElementPosition { @@ -50,9 +60,9 @@ interface WaitForSelectorOpts { timeout: number; } -interface EvaluateOpts { - fn: EvaluateFn; - args: SerializableOrJSHandle[]; +interface EvaluateOpts { + fn: EvaluateFunc; + args: unknown[]; } interface EvaluateMetaOpts { @@ -117,7 +127,7 @@ export class HeadlessChromiumDriver { this.interceptedCount = 0; /** - * Integrate with the screenshot mode plugin contract by calling this function before any other + * Integrate with the screenshot mode plugin contract by calling this function before whatever other * scripts have run on the browser page. */ await this.page.evaluateOnNewDocument(this.screenshotMode.setScreenshotModeEnabled); @@ -283,10 +293,14 @@ export class HeadlessChromiumDriver { return undefined; } - evaluate({ fn, args = [] }: EvaluateOpts, meta: EvaluateMetaOpts, logger: Logger): Promise { + evaluate( + { fn, args = [] }: EvaluateOpts, + meta: EvaluateMetaOpts, + logger: Logger + ): Promise { logger.debug(`evaluate ${meta.context}`); - return this.page.evaluate(fn, ...args); + return this.page.evaluate(fn as EvaluateFunc, ...args) as Promise; } public async waitForSelector( @@ -307,16 +321,20 @@ export class HeadlessChromiumDriver { return response; } - public async waitFor({ + public async waitFor({ fn, args, timeout, }: { - fn: EvaluateFn; - args: SerializableOrJSHandle[]; + fn: EvaluateFunc; + args: unknown[]; timeout: number; }): Promise { - await this.page.waitForFunction(fn, { timeout, polling: WAIT_FOR_DELAY_MS }, ...args); + await this.page.waitForFunction( + fn as EvaluateFunc, + { timeout, polling: WAIT_FOR_DELAY_MS }, + ...args + ); } /** @@ -345,8 +363,8 @@ export class HeadlessChromiumDriver { return; } - // FIXME: retrieve the client in open() and pass in the client - const client = this.page.client(); + // FIXME: retrieve the client in open() and pass in the client? + const client = this.page._client(); // We have to reach into the Chrome Devtools Protocol to apply headers as using // puppeteer's API will cause map tile requests to hang indefinitely: @@ -437,12 +455,12 @@ export class HeadlessChromiumDriver { // In order to get the inspector running, we have to know the page's internal ID (again, private) // in order to construct the final debugging URL. + const client = this.page._client(); const target = this.page.target(); - const client = await target.createCDPSession(); + const targetId = target._targetId; await client.send('Debugger.enable'); await client.send('Debugger.pause'); - const targetId = target._targetId; const wsEndpoint = this.page.browser().wsEndpoint(); const { port } = parseUrl(wsEndpoint); diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts b/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts index bc001470a8e6e..984fa0470d216 100644 --- a/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts +++ b/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts @@ -293,16 +293,14 @@ export class HeadlessChromiumDriverFactory { */ private async getErrorMessage(message: ConsoleMessage): Promise { for (const arg of message.args()) { - const errorMessage = await arg - .executionContext() - .evaluate((_arg: unknown) => { - /* !! We are now in the browser context !! */ - if (_arg instanceof Error) { - return _arg.message; - } - return undefined; - /* !! End of browser context !! */ - }, arg); + const errorMessage = await arg.evaluate((_arg: unknown) => { + /* !! We are now in the browser context !! */ + if (_arg instanceof Error) { + return _arg.message; + } + return undefined; + /* !! End of browser context !! */ + }, arg); if (errorMessage) { return errorMessage; } diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/paths.ts b/x-pack/plugins/screenshotting/server/browsers/chromium/paths.ts index 1a04574155c1e..a04308c27dd8e 100644 --- a/x-pack/plugins/screenshotting/server/browsers/chromium/paths.ts +++ b/x-pack/plugins/screenshotting/server/browsers/chromium/paths.ts @@ -14,11 +14,12 @@ export interface PackageInfo { archiveChecksum: string; binaryChecksum: string; binaryRelativePath: string; - revision: 901912 | 901913; isPreInstalled: boolean; location: 'custom' | 'common'; } +const REVISION = 1036745; + enum BaseUrl { // see https://www.chromium.org/getting-involved/download-chromium common = 'https://commondatastorage.googleapis.com/chromium-browser-snapshots', @@ -44,58 +45,53 @@ export class ChromiumArchivePaths { platform: 'darwin', architecture: 'x64', archiveFilename: 'chrome-mac.zip', - archiveChecksum: '229fd88c73c5878940821875f77578e4', - binaryChecksum: 'b0e5ca009306b14e41527000139852e5', + archiveChecksum: '5afc0d49865d55b69ea1ff65b9cc5794', + binaryChecksum: '4a7a663b2656d66ce975b00a30df3ab4', binaryRelativePath: 'chrome-mac/Chromium.app/Contents/MacOS/Chromium', location: 'common', archivePath: 'Mac', - revision: 901912, isPreInstalled: false, }, { platform: 'darwin', architecture: 'arm64', archiveFilename: 'chrome-mac.zip', - archiveChecksum: 'ecf7aa509c8e2545989ebb9711e35384', - binaryChecksum: 'b5072b06ffd2d2af4fea7012914da09f', + archiveChecksum: '5afc0d49865d55b69ea1ff65b9cc5794', + binaryChecksum: '4a7a663b2656d66ce975b00a30df3ab4', binaryRelativePath: 'chrome-mac/Chromium.app/Contents/MacOS/Chromium', location: 'common', archivePath: 'Mac_Arm', - revision: 901913, // NOTE: 901912 is not available isPreInstalled: false, }, { platform: 'linux', architecture: 'x64', - archiveFilename: 'chromium-70f5d88-locales-linux_x64.zip', - archiveChecksum: '759bda5e5d32533cb136a85e37c0d102', - binaryChecksum: '82e80f9727a88ba3836ce230134bd126', + archiveFilename: 'chromium-749e738-locales-linux_x64.zip', + archiveChecksum: '09ba194e6c720397728fbec3d3895b0b', + binaryChecksum: 'df1c957f41dcca8e33369b1d255406c2', binaryRelativePath: 'headless_shell-linux_x64/headless_shell', location: 'custom', - revision: 901912, isPreInstalled: true, }, { platform: 'linux', architecture: 'arm64', - archiveFilename: 'chromium-70f5d88-locales-linux_arm64.zip', - archiveChecksum: '33613b8dc5212c0457210d5a37ea4b43', - binaryChecksum: '29e943fbee6d87a217abd6cb6747058e', + archiveFilename: 'chromium-749e738-locales-linux_arm64.zip', + archiveChecksum: '1f535b1c2875d471829c6ff128a13262', + binaryChecksum: 'ca6b91d0ba8a65712554572dabc66968', binaryRelativePath: 'headless_shell-linux_arm64/headless_shell', location: 'custom', - revision: 901912, isPreInstalled: true, }, { platform: 'win32', architecture: 'x64', archiveFilename: 'chrome-win.zip', - archiveChecksum: '861bb8b7b8406a6934a87d3cbbce61d9', - binaryChecksum: 'ffa0949471e1b9a57bc8f8633fca9c7b', + archiveChecksum: '42db052673414b89d8cb45657c1a6aeb', + binaryChecksum: '1b6eef775198ffd48fb9669ac0c818f7', binaryRelativePath: path.join('chrome-win', 'chrome.exe'), location: 'common', archivePath: 'Win', - revision: 901912, isPreInstalled: true, }, ]; @@ -118,7 +114,7 @@ export class ChromiumArchivePaths { public getDownloadUrl(p: PackageInfo) { if (isCommonPackage(p)) { - return `${BaseUrl.common}/${p.archivePath}/${p.revision}/${p.archiveFilename}`; + return `${BaseUrl.common}/${p.archivePath}/${REVISION}/${p.archiveFilename}`; } return BaseUrl.custom + '/' + p.archiveFilename; // revision is not used for URL if package is a custom build } diff --git a/x-pack/plugins/screenshotting/server/browsers/download/index.test.ts b/x-pack/plugins/screenshotting/server/browsers/download/index.test.ts index 74a80cf10b58b..21f55bfc93e93 100644 --- a/x-pack/plugins/screenshotting/server/browsers/download/index.test.ts +++ b/x-pack/plugins/screenshotting/server/browsers/download/index.test.ts @@ -88,11 +88,11 @@ describe('ensureDownloaded', () => { expect.arrayContaining([ 'chrome-mac.zip', 'chrome-win.zip', - 'chromium-70f5d88-locales-linux_x64.zip', + 'chromium-749e738-locales-linux_x64.zip', ]) ); expect(readdirSync(path.resolve(`${paths.archivesPath}/arm64`))).toEqual( - expect.arrayContaining(['chrome-mac.zip', 'chromium-70f5d88-locales-linux_arm64.zip']) + expect.arrayContaining(['chrome-mac.zip', 'chromium-749e738-locales-linux_arm64.zip']) ); }); diff --git a/x-pack/plugins/screenshotting/server/config/schema.test.ts b/x-pack/plugins/screenshotting/server/config/schema.test.ts index c2febf5906249..bb68e8e938ace 100644 --- a/x-pack/plugins/screenshotting/server/config/schema.test.ts +++ b/x-pack/plugins/screenshotting/server/config/schema.test.ts @@ -22,8 +22,8 @@ describe('ConfigSchema', () => { "capture": Object { "timeouts": Object { "openUrl": "PT1M", - "renderComplete": "PT30S", - "waitForElements": "PT30S", + "renderComplete": "PT2M", + "waitForElements": "PT1M", }, "zoom": 2, }, @@ -82,8 +82,8 @@ describe('ConfigSchema', () => { "capture": Object { "timeouts": Object { "openUrl": "PT1M", - "renderComplete": "PT30S", - "waitForElements": "PT30S", + "renderComplete": "PT2M", + "waitForElements": "PT1M", }, "zoom": 2, }, diff --git a/x-pack/plugins/screenshotting/server/config/schema.ts b/x-pack/plugins/screenshotting/server/config/schema.ts index 4900a5c9d775e..724f84ea3c811 100644 --- a/x-pack/plugins/screenshotting/server/config/schema.ts +++ b/x-pack/plugins/screenshotting/server/config/schema.ts @@ -50,7 +50,7 @@ export const ConfigSchema = schema.object({ schema.boolean({ defaultValue: false }), schema.maybe(schema.never()) ), - disableSandbox: schema.maybe(schema.boolean()), // default value is dynamic in createConfig$ + disableSandbox: schema.maybe(schema.boolean()), // default value is dynamic in createConfig proxy: schema.object({ enabled: schema.boolean({ defaultValue: false }), server: schema.conditional( @@ -74,10 +74,10 @@ export const ConfigSchema = schema.object({ defaultValue: moment.duration({ minutes: 1 }), }), waitForElements: schema.oneOf([schema.number(), schema.duration()], { - defaultValue: moment.duration({ seconds: 30 }), + defaultValue: moment.duration({ minutes: 1 }), }), renderComplete: schema.oneOf([schema.number(), schema.duration()], { - defaultValue: moment.duration({ seconds: 30 }), + defaultValue: moment.duration({ minutes: 2 }), }), }), zoom: schema.number({ defaultValue: 2 }), diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.ts b/x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.ts index 9d66f58c308d3..ff1c9c4d2bb3e 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.ts @@ -47,14 +47,18 @@ export const getElementPositionAndAttributes = async ( ); const { screenshot: screenshotSelector } = layout.selectors; // data-shared-items-container + const screenshotAttributes = { title: 'data-title', description: 'data-description' }; + let elementsPositionAndAttributes: ElementsPositionAndAttribute[] | null; try { - elementsPositionAndAttributes = await browser.evaluate( + elementsPositionAndAttributes = await browser.evaluate< + [typeof screenshotSelector, typeof screenshotAttributes], + ElementsPositionAndAttribute[] | null + >( { fn: (selector, attributes) => { const elements = Array.from(document.querySelectorAll(selector)); const results: ElementsPositionAndAttribute[] = []; - for (const element of elements) { const boundingClientRect = element.getBoundingClientRect() as DOMRect; results.push({ @@ -65,21 +69,18 @@ export const getElementPositionAndAttributes = async ( width: boundingClientRect.width, height: boundingClientRect.height, }, - scroll: { - x: window.scrollX, - y: window.scrollY, - }, + scroll: { x: window.scrollX, y: window.scrollY }, }, - attributes: Object.keys(attributes).reduce((result: AttributesMap, key) => { - const attribute = attributes[key]; + attributes: Object.keys(attributes).reduce((result, key) => { + const attribute = attributes[key as keyof typeof attributes]; result[key] = element.getAttribute(attribute); return result; - }, {} as AttributesMap), + }, {}), }); } return results; }, - args: [screenshotSelector, { title: 'data-title', description: 'data-description' }], + args: [screenshotSelector, screenshotAttributes], }, { context: CONTEXT_ELEMENTATTRIBUTES }, kbnLogger diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.ts b/x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.ts index 0e4da2fe5cf6a..ce84c9e213861 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.ts @@ -39,7 +39,7 @@ export const getNumberOfItems = async ( // returns the value of the `itemsCountAttribute` if it's there, otherwise // we just count the number of `itemSelector`: the number of items already rendered - itemsCount = await browser.evaluate( + itemsCount = await browser.evaluate( { fn: (selector, countAttribute) => { const elementWithCount = document.querySelector(`[${countAttribute}]`); diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_render_errors.ts b/x-pack/plugins/screenshotting/server/screenshots/get_render_errors.ts index 44b92ceddbc8d..b18fc0dbff44f 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/get_render_errors.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/get_render_errors.ts @@ -25,7 +25,7 @@ export const getRenderErrors = async ( let errorsFound: undefined | string[]; try { - errorsFound = await browser.evaluate( + errorsFound = await browser.evaluate( { fn: (errorSelector, errorAttribute) => { const visualizations: Element[] = Array.from(document.querySelectorAll(errorSelector)); diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_time_range.ts b/x-pack/plugins/screenshotting/server/screenshots/get_time_range.ts index f9272fd27ac95..85f284d368707 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/get_time_range.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/get_time_range.ts @@ -21,7 +21,7 @@ export const getTimeRange = async ( 'read' ); - const timeRange = await browser.evaluate( + const timeRange = await browser.evaluate( { fn: (durationAttribute) => { const durationElement = document.querySelector(`[${durationAttribute}]`); diff --git a/x-pack/plugins/screenshotting/server/screenshots/index.ts b/x-pack/plugins/screenshotting/server/screenshots/index.ts index 0c6c6f409f848..c45a0583ffe72 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/index.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/index.ts @@ -201,8 +201,8 @@ export class Screenshots { { timeouts: { openUrl: 60000, - waitForElements: 30000, - renderComplete: 30000, + waitForElements: 60000, + renderComplete: 120000, }, urls: [], } diff --git a/x-pack/plugins/screenshotting/server/screenshots/inject_css.ts b/x-pack/plugins/screenshotting/server/screenshots/inject_css.ts index 41426e893ce58..5afa4b6c62df0 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/inject_css.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/inject_css.ts @@ -34,7 +34,7 @@ export const injectCustomCss = async ( const buffer = await fsp.readFile(filePath); try { - await browser.evaluate( + await browser.evaluate( { fn: (css) => { const node = document.createElement('style'); diff --git a/x-pack/plugins/screenshotting/server/screenshots/wait_for_render.ts b/x-pack/plugins/screenshotting/server/screenshots/wait_for_render.ts index ed4ad83736d42..74ac35e2f9148 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/wait_for_render.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/wait_for_render.ts @@ -21,7 +21,7 @@ export const waitForRenderComplete = async ( 'wait' ); - await browser.evaluate( + await browser.evaluate( { fn: async (selector) => { const visualizations: NodeListOf = document.querySelectorAll(selector); diff --git a/x-pack/plugins/screenshotting/server/screenshots/wait_for_visualizations.ts b/x-pack/plugins/screenshotting/server/screenshots/wait_for_visualizations.ts index cf49fbe7dc798..15b02a92749b2 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/wait_for_visualizations.ts +++ b/x-pack/plugins/screenshotting/server/screenshots/wait_for_visualizations.ts @@ -53,7 +53,7 @@ export const waitForVisualizations = async ( kbnLogger.debug(`waiting for ${toEqual} rendered elements to be in the DOM`); try { - await browser.waitFor({ + await browser.waitFor({ fn: getCompletedItemsCount, args: [{ renderCompleteSelector, context: CONTEXT_WAITFORELEMENTSTOBEINDOM, count: toEqual }], timeout, diff --git a/x-pack/plugins/security/public/components/use_badge.test.tsx b/x-pack/plugins/security/public/components/use_badge.test.tsx new file mode 100644 index 0000000000000..f5d3c28e5f0b2 --- /dev/null +++ b/x-pack/plugins/security/public/components/use_badge.test.tsx @@ -0,0 +1,77 @@ +/* + * 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 { renderHook } from '@testing-library/react-hooks'; +import React from 'react'; + +import { coreMock } from '@kbn/core/public/mocks'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; + +import type { ChromeBadge } from './use_badge'; +import { useBadge } from './use_badge'; + +describe('useBadge', () => { + it('should add badge to chrome', async () => { + const coreStart = coreMock.createStart(); + const badge: ChromeBadge = { + text: 'text', + tooltip: 'text', + }; + renderHook(useBadge, { + initialProps: badge, + wrapper: ({ children }) => ( + {children} + ), + }); + + expect(coreStart.chrome.setBadge).toHaveBeenLastCalledWith(badge); + }); + + it('should remove badge from chrome on unmount', async () => { + const coreStart = coreMock.createStart(); + const badge: ChromeBadge = { + text: 'text', + tooltip: 'text', + }; + const { unmount } = renderHook(useBadge, { + initialProps: badge, + wrapper: ({ children }) => ( + {children} + ), + }); + + expect(coreStart.chrome.setBadge).toHaveBeenLastCalledWith(badge); + + unmount(); + + expect(coreStart.chrome.setBadge).toHaveBeenLastCalledWith(); + }); + + it('should update chrome when badge changes', async () => { + const coreStart = coreMock.createStart(); + const badge1: ChromeBadge = { + text: 'text', + tooltip: 'text', + }; + const { rerender } = renderHook(useBadge, { + initialProps: badge1, + wrapper: ({ children }) => ( + {children} + ), + }); + + expect(coreStart.chrome.setBadge).toHaveBeenLastCalledWith(badge1); + + const badge2: ChromeBadge = { + text: 'text2', + tooltip: 'text2', + }; + rerender(badge2); + + expect(coreStart.chrome.setBadge).toHaveBeenLastCalledWith(badge2); + }); +}); diff --git a/x-pack/plugins/security/public/components/use_badge.ts b/x-pack/plugins/security/public/components/use_badge.ts new file mode 100644 index 0000000000000..cd5a8d3620a2f --- /dev/null +++ b/x-pack/plugins/security/public/components/use_badge.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DependencyList } from 'react'; +import { useEffect } from 'react'; + +import type { ChromeBadge } from '@kbn/core-chrome-browser'; +import type { CoreStart } from '@kbn/core/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; + +export type { ChromeBadge }; + +/** + * Renders a badge in the Kibana chrome. + * @param badge Params of the badge or `undefined` to render no badge. + * @param badge.iconType Icon type of the badge shown in the Kibana chrome. + * @param badge.text Title of tooltip displayed when hovering the badge. + * @param badge.tooltip Description of tooltip displayed when hovering the badge. + * @param deps If present, badge will be updated or removed if the values in the list change. + */ +export function useBadge( + badge: ChromeBadge | undefined, + deps: DependencyList = [badge?.iconType, badge?.text, badge?.tooltip] +) { + const { services } = useKibana(); + + useEffect(() => { + if (badge) { + services.chrome.setBadge(badge); + return () => services.chrome.setBadge(); + } + }, deps); // eslint-disable-line react-hooks/exhaustive-deps +} diff --git a/x-pack/plugins/security/public/components/use_capabilities.test.tsx b/x-pack/plugins/security/public/components/use_capabilities.test.tsx new file mode 100644 index 0000000000000..b5eca83a8d53e --- /dev/null +++ b/x-pack/plugins/security/public/components/use_capabilities.test.tsx @@ -0,0 +1,47 @@ +/* + * 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 { renderHook } from '@testing-library/react-hooks'; +import React from 'react'; + +import { coreMock } from '@kbn/core/public/mocks'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; + +import { useCapabilities } from './use_capabilities'; + +describe('useCapabilities', () => { + it('should return capabilities', async () => { + const coreStart = coreMock.createStart(); + + const { result } = renderHook(useCapabilities, { + wrapper: ({ children }) => ( + {children} + ), + }); + + expect(result.current).toEqual(coreStart.application.capabilities); + }); + + it('should return capabilities scoped by feature', async () => { + const coreStart = coreMock.createStart(); + coreStart.application.capabilities = { + ...coreStart.application.capabilities, + users: { + save: true, + }, + }; + + const { result } = renderHook(useCapabilities, { + initialProps: 'users', + wrapper: ({ children }) => ( + {children} + ), + }); + + expect(result.current).toEqual({ save: true }); + }); +}); diff --git a/x-pack/plugins/security/public/components/use_capabilities.ts b/x-pack/plugins/security/public/components/use_capabilities.ts new file mode 100644 index 0000000000000..cdf54e2700a52 --- /dev/null +++ b/x-pack/plugins/security/public/components/use_capabilities.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 type { Capabilities } from '@kbn/core-capabilities-common'; +import type { CoreStart } from '@kbn/core/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; + +type FeatureCapabilities = Capabilities[string]; + +/** + * Returns capabilities for a specific feature, or alternatively the entire capabilities object. + * @param featureId ID of feature + */ +export function useCapabilities(): Capabilities; +export function useCapabilities( + featureId: string +): T; +export function useCapabilities( + featureId?: string +) { + const { services } = useKibana(); + + if (featureId) { + return services.application.capabilities[featureId] as T; + } + + return services.application.capabilities; +} diff --git a/x-pack/plugins/security/public/management/badges/readonly_badge.tsx b/x-pack/plugins/security/public/management/badges/readonly_badge.tsx new file mode 100644 index 0000000000000..9f41ed350e158 --- /dev/null +++ b/x-pack/plugins/security/public/management/badges/readonly_badge.tsx @@ -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 { i18n } from '@kbn/i18n'; + +import { useBadge } from '../../components/use_badge'; +import { useCapabilities } from '../../components/use_capabilities'; + +export interface ReadonlyBadgeProps { + featureId: string; + tooltip: string; +} + +export const ReadonlyBadge = ({ featureId, tooltip }: ReadonlyBadgeProps) => { + const { save } = useCapabilities(featureId); + useBadge( + save + ? undefined + : { + iconType: 'glasses', + text: i18n.translate('xpack.security.management.readonlyBadge.text', { + defaultMessage: 'Read only', + }), + tooltip, + }, + [save] + ); + return null; +}; diff --git a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx index 525df66251057..329b4bfc28b54 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx @@ -22,12 +22,26 @@ jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ describe('CreateUserPage', () => { jest.setTimeout(15_000); + const coreStart = coreMock.createStart(); const theme$ = themeServiceMock.createTheme$(); + let history = createMemoryHistory({ initialEntries: ['/create'] }); + const authc = securityMock.createSetup().authc; + + beforeEach(() => { + history = createMemoryHistory({ initialEntries: ['/create'] }); + authc.getCurrentUser.mockClear(); + coreStart.http.delete.mockClear(); + coreStart.http.get.mockClear(); + coreStart.http.post.mockClear(); + coreStart.application.capabilities = { + ...coreStart.application.capabilities, + users: { + save: true, + }, + }; + }); it('creates user when submitting form and redirects back', async () => { - const coreStart = coreMock.createStart(); - const history = createMemoryHistory({ initialEntries: ['/create'] }); - const authc = securityMock.createSetup().authc; coreStart.http.post.mockResolvedValue({}); const { findByRole, findByLabelText } = render( @@ -57,11 +71,26 @@ describe('CreateUserPage', () => { }); }); - it('validates form', async () => { - const coreStart = coreMock.createStart(); - const history = createMemoryHistory({ initialEntries: ['/create'] }); - const authc = securityMock.createSetup().authc; + it('redirects back when viewing with readonly privileges', async () => { + coreStart.application.capabilities = { + ...coreStart.application.capabilities, + users: { + save: false, + }, + }; + render( + + + + ); + + await waitFor(() => { + expect(history.location.pathname).toBe('/'); + }); + }); + + it('validates form', async () => { coreStart.http.get.mockResolvedValueOnce([]); coreStart.http.get.mockResolvedValueOnce([ { diff --git a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx index 52b2988ca5f83..d72732cfd99ed 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx @@ -7,17 +7,25 @@ import { EuiPageHeader, EuiSpacer } from '@elastic/eui'; import type { FunctionComponent } from 'react'; -import React from 'react'; +import React, { useEffect } from 'react'; import { useHistory } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useCapabilities } from '../../../components/use_capabilities'; import { UserForm } from './user_form'; export const CreateUserPage: FunctionComponent = () => { const history = useHistory(); + const readOnly = !useCapabilities('users').save; const backToUsers = () => history.push('/'); + useEffect(() => { + if (readOnly) { + backToUsers(); + } + }, [readOnly]); // eslint-disable-line react-hooks/exhaustive-deps + return ( <> { coreStart.http.post.mockClear(); coreStart.notifications.toasts.addDanger.mockClear(); coreStart.notifications.toasts.addSuccess.mockClear(); + coreStart.application.capabilities = { + ...coreStart.application.capabilities, + users: { + save: true, + }, + }; }); it('warns when viewing deactivated user', async () => { @@ -125,4 +131,29 @@ describe('EditUserPage', () => { await findByText(/Role .deprecated_role. is deprecated. Use .new_role. instead/i); }); + + it('disables form when viewing with readonly privileges', async () => { + coreStart.http.get.mockResolvedValueOnce(userMock); + coreStart.http.get.mockResolvedValueOnce([]); + coreStart.application.capabilities = { + ...coreStart.application.capabilities, + users: { + save: false, + }, + }; + + const { findByRole, findAllByRole } = render( + + + + ); + + await findByRole('button', { name: 'Back to users' }); + + const fields = await findAllByRole('textbox'); + expect(fields.length).toBeGreaterThanOrEqual(1); + fields.forEach((field) => { + expect(field).toHaveProperty('disabled', true); + }); + }); }); diff --git a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx index bdbae4dc22a1c..9a3c3f8153b8a 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx @@ -30,6 +30,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { getUserDisplayName } from '../../../../common/model'; +import { useCapabilities } from '../../../components/use_capabilities'; import { UserAPIClient } from '../user_api_client'; import { isUserDeprecated, isUserReserved } from '../user_utils'; import { ChangePasswordModal } from './change_password_modal'; @@ -57,6 +58,7 @@ export const EditUserPage: FunctionComponent = ({ username }) [services.http] ); const [action, setAction] = useState('none'); + const readOnly = !useCapabilities('users').save; const backToUsers = () => history.push('/'); @@ -155,181 +157,186 @@ export const EditUserPage: FunctionComponent = ({ username }) defaultValues={user} onCancel={backToUsers} onSuccess={backToUsers} + disabled={readOnly} /> - {action === 'changePassword' ? ( - setAction('none')} - onSuccess={() => setAction('none')} - /> - ) : action === 'disableUser' ? ( - setAction('none')} - onSuccess={() => { - setAction('none'); - getUser(); - }} - /> - ) : action === 'enableUser' ? ( - setAction('none')} - onSuccess={() => { - setAction('none'); - getUser(); - }} - /> - ) : action === 'deleteUser' ? ( - setAction('none')} - onSuccess={backToUsers} - /> - ) : undefined} - - - - - - - - - - - - - - - - - - setAction('changePassword')} - size="s" - data-test-subj="editUserChangePasswordButton" - > - - - - - - - - {user.enabled === false ? ( - - - - - - - - - - - - - - setAction('enableUser')} - size="s" - data-test-subj="editUserEnableUserButton" - > - - - - - - ) : ( - - - - - - - - - - - - - - setAction('disableUser')} - size="s" - data-test-subj="editUserDisableUserButton" - > - - - - - - )} - - {!isReservedUser && ( + {readOnly ? undefined : ( <> + {action === 'changePassword' ? ( + setAction('none')} + onSuccess={() => setAction('none')} + /> + ) : action === 'disableUser' ? ( + setAction('none')} + onSuccess={() => { + setAction('none'); + getUser(); + }} + /> + ) : action === 'enableUser' ? ( + setAction('none')} + onSuccess={() => { + setAction('none'); + getUser(); + }} + /> + ) : action === 'deleteUser' ? ( + setAction('none')} + onSuccess={backToUsers} + /> + ) : undefined} + + + setAction('deleteUser')} + onClick={() => setAction('changePassword')} size="s" - color="danger" - data-test-subj="editUserDeleteUserButton" + data-test-subj="editUserChangePasswordButton" > + + + {user.enabled === false ? ( + + + + + + + + + + + + + + setAction('enableUser')} + size="s" + data-test-subj="editUserEnableUserButton" + > + + + + + + ) : ( + + + + + + + + + + + + + + setAction('disableUser')} + size="s" + data-test-subj="editUserDisableUserButton" + > + + + + + + )} + + {!isReservedUser && ( + <> + + + + + + + + + + + + + + + setAction('deleteUser')} + size="s" + color="danger" + data-test-subj="editUserDeleteUserButton" + > + + + + + + + )} )} diff --git a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx index 83cf8dae89416..41c29ab773868 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx @@ -56,6 +56,7 @@ export interface UserFormProps { defaultValues?: UserFormValues; onCancel(): void; onSuccess?(): void; + disabled?: boolean; } const defaultDefaultValues: UserFormValues = { @@ -73,6 +74,7 @@ export const UserForm: FunctionComponent = ({ defaultValues = defaultDefaultValues, onSuccess, onCancel, + disabled = false, }) => { const { services } = useKibana(); @@ -269,7 +271,7 @@ export const UserForm: FunctionComponent = ({ value={form.values.username} isLoading={form.isValidating} isInvalid={form.touched.username && !!form.errors.username} - disabled={!isNewUser} + disabled={disabled || !isNewUser} onChange={eventHandlers.onChange} onBlur={eventHandlers.onBlur} /> @@ -291,6 +293,7 @@ export const UserForm: FunctionComponent = ({ isInvalid={form.touched.full_name && !!form.errors.full_name} onChange={eventHandlers.onChange} onBlur={eventHandlers.onBlur} + disabled={disabled} />
    = ({ isInvalid={form.touched.email && !!form.errors.email} onChange={eventHandlers.onChange} onBlur={eventHandlers.onBlur} + disabled={disabled} /> @@ -349,6 +353,7 @@ export const UserForm: FunctionComponent = ({ autoComplete="new-password" onChange={eventHandlers.onChange} onBlur={eventHandlers.onBlur} + disabled={disabled} />
    = ({ autoComplete="new-password" onChange={eventHandlers.onChange} onBlur={eventHandlers.onBlur} + disabled={disabled} /> @@ -423,12 +429,12 @@ export const UserForm: FunctionComponent = ({ selectedRoleNames={selectedRoleNames} onChange={(value) => form.setValue('roles', value)} isLoading={rolesState.loading} - isDisabled={isReservedUser} + isDisabled={disabled || isReservedUser} />
    - {isReservedUser ? ( + {disabled || isReservedUser ? ( diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx index 99de5391c0416..3c133b3628b43 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx @@ -31,7 +31,7 @@ describe('UsersGridPage', () => { coreStart = coreMock.createStart(); }); - it('renders the list of users', async () => { + it('renders the list of users and create button', async () => { const apiClientMock = userAPIClientMock.create(); apiClientMock.getUsers.mockImplementation(() => { return Promise.resolve([ @@ -71,6 +71,7 @@ describe('UsersGridPage', () => { expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); expect(wrapper.find('EuiTableRow')).toHaveLength(2); expect(findTestSubject(wrapper, 'userDisabled')).toHaveLength(0); + expect(findTestSubject(wrapper, 'createUserButton')).toHaveLength(1); }); it('renders the loading indication on the table when fetching user with data', async () => { @@ -375,6 +376,46 @@ describe('UsersGridPage', () => { }, ]); }); + + it('hides controls when `readOnly` is enabled', async () => { + const apiClientMock = userAPIClientMock.create(); + apiClientMock.getUsers.mockImplementation(() => { + return Promise.resolve([ + { + username: 'foo', + email: 'foo@bar.net', + full_name: 'foo bar', + roles: ['kibana_user'], + enabled: true, + }, + { + username: 'reserved', + email: 'reserved@bar.net', + full_name: '', + roles: ['superuser'], + enabled: true, + metadata: { + _reserved: true, + }, + }, + ]); + }); + + const wrapper = mountWithIntl( + + ); + + await waitForRender(wrapper); + + expect(findTestSubject(wrapper, 'createUserButton')).toHaveLength(0); + }); }); async function waitForRender(wrapper: ReactWrapper) { diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx index 748cd8527742b..0649de83749cd 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx @@ -40,6 +40,7 @@ interface Props { notifications: NotificationsStart; history: ScopedHistory; navigateToApp: ApplicationStart['navigateToApp']; + readOnly?: boolean; } interface State { @@ -55,6 +56,10 @@ interface State { } export class UsersGridPage extends Component { + static defaultProps: Partial = { + readOnly: false, + }; + constructor(props: Props) { super(props); this.state = { @@ -69,7 +74,6 @@ export class UsersGridPage extends Component { isTableLoading: false, }; } - public componentDidMount() { this.loadUsersAndRoles(); } @@ -231,19 +235,23 @@ export class UsersGridPage extends Component { defaultMessage="Users" /> } - rightSideItems={[ - - - , - ]} + rightSideItems={ + this.props.readOnly + ? undefined + : [ + + + , + ] + } /> @@ -266,7 +274,7 @@ export class UsersGridPage extends Component { })} rowHeader="username" columns={columns} - selection={selectionConfig} + selection={this.props.readOnly ? undefined : selectionConfig} pagination={pagination} items={this.state.visibleUsers} loading={this.state.isTableLoading} diff --git a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx index ec7b1d19226ba..dd5495cd8bd1d 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx @@ -22,9 +22,14 @@ describe('usersManagementApp', () => { const coreStartMock = coreMock.createStart(); getStartServices.mockResolvedValue([coreStartMock, {}, {}]); const { authc } = securityMock.createSetup(); - const setBreadcrumbs = jest.fn(); const history = scopedHistoryMock.create({ pathname: '/create' }); + coreStartMock.application.capabilities = { + ...coreStartMock.application.capabilities, + users: { + save: true, + }, + }; let unmount: Unmount = noop; await act(async () => { diff --git a/x-pack/plugins/security/public/management/users/users_management_app.tsx b/x-pack/plugins/security/public/management/users/users_management_app.tsx index de7a4110a3f3f..a8a13bb72dc6a 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.tsx @@ -28,6 +28,7 @@ import { } from '../../components/breadcrumb'; import { AuthenticationProvider } from '../../components/use_current_user'; import type { PluginStartDependencies } from '../../plugin'; +import { ReadonlyBadge } from '../badges/readonly_badge'; import { tryDecodeURIComponent } from '../url_utils'; interface CreateParams { @@ -72,6 +73,12 @@ export const usersManagementApp = Object.freeze({ authc={authc} onChange={createBreadcrumbsChangeHandler(coreStart.chrome, setBreadcrumbs)} > + diff --git a/x-pack/plugins/security/server/features/security_features.ts b/x-pack/plugins/security/server/features/security_features.ts index b741d8091518d..396f2d1640e1f 100644 --- a/x-pack/plugins/security/server/features/security_features.ts +++ b/x-pack/plugins/security/server/features/security_features.ts @@ -16,6 +16,10 @@ const userManagementFeature: ElasticsearchFeatureConfig = { privileges: [ { requiredClusterPrivileges: ['manage_security'], + ui: ['save'], + }, + { + requiredClusterPrivileges: ['read_security'], ui: [], }, ], diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts index a268c2e0c8f25..76d90f23a2e83 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts @@ -25,7 +25,7 @@ import { userProfileMock } from '../../common/model/user_profile.mock'; import { authorizationMock } from '../authorization/index.mock'; import { securityMock } from '../mocks'; import { sessionMock } from '../session_management/session.mock'; -import { UserProfileService } from './user_profile_service'; +import { prefixCommaSeparatedValues, UserProfileService } from './user_profile_service'; const logger = loggingSystemMock.createLogger(); describe('UserProfileService', () => { @@ -245,7 +245,7 @@ describe('UserProfileService', () => { } as unknown as SecurityGetUserProfileResponse); const startContract = userProfileService.start(mockStartParams); - await expect(startContract.getCurrent({ request: mockRequest, dataPath: '*' })).resolves + await expect(startContract.getCurrent({ request: mockRequest, dataPath: 'one,two' })).resolves .toMatchInlineSnapshot(` Object { "data": Object { @@ -277,7 +277,7 @@ describe('UserProfileService', () => { mockStartParams.clusterClient.asInternalUser.security.getUserProfile ).toHaveBeenCalledWith({ uid: 'UID', - data: 'kibana.*', + data: 'kibana.one,kibana.two', }); }); }); @@ -556,8 +556,8 @@ describe('UserProfileService', () => { } as unknown as SecurityGetUserProfileResponse); const startContract = userProfileService.start(mockStartParams); - await expect(startContract.bulkGet({ uids: new Set(['UID-1']), dataPath: '*' })).resolves - .toMatchInlineSnapshot(` + await expect(startContract.bulkGet({ uids: new Set(['UID-1']), dataPath: 'one,two' })) + .resolves.toMatchInlineSnapshot(` Array [ Object { "data": Object { @@ -580,7 +580,7 @@ describe('UserProfileService', () => { mockStartParams.clusterClient.asInternalUser.security.getUserProfile ).toHaveBeenCalledWith({ uid: 'UID-1', - data: 'kibana.*', + data: 'kibana.one,kibana.two', }); }); @@ -683,7 +683,7 @@ describe('UserProfileService', () => { } as unknown as SecuritySuggestUserProfilesResponse); const startContract = userProfileService.start(mockStartParams); - await expect(startContract.suggest({ name: 'some', dataPath: '*' })).resolves + await expect(startContract.suggest({ name: 'some', dataPath: 'one,two' })).resolves .toMatchInlineSnapshot(` Array [ Object { @@ -708,7 +708,44 @@ describe('UserProfileService', () => { ).toHaveBeenCalledWith({ name: 'some', size: 10, - data: 'kibana.*', + data: 'kibana.one,kibana.two', + }); + expect(mockAuthz.checkUserProfilesPrivileges).not.toHaveBeenCalled(); + }); + + it('should request data if uid hints are specified', async () => { + mockStartParams.clusterClient.asInternalUser.security.suggestUserProfiles.mockResolvedValue({ + profiles: [ + userProfileMock.createWithSecurity({ + uid: 'UID-1', + }), + ], + } as unknown as SecuritySuggestUserProfilesResponse); + + const startContract = userProfileService.start(mockStartParams); + await expect(startContract.suggest({ hint: { uids: ['UID-1'] } })).resolves + .toMatchInlineSnapshot(` + Array [ + Object { + "data": Object {}, + "enabled": true, + "uid": "UID-1", + "user": Object { + "email": "some@email", + "full_name": undefined, + "username": "some-username", + }, + }, + ] + `); + expect( + mockStartParams.clusterClient.asInternalUser.security.suggestUserProfiles + ).toHaveBeenCalledTimes(1); + expect( + mockStartParams.clusterClient.asInternalUser.security.suggestUserProfiles + ).toHaveBeenCalledWith({ + size: 10, + hint: { uids: ['UID-1'] }, }); expect(mockAuthz.checkUserProfilesPrivileges).not.toHaveBeenCalled(); }); @@ -788,7 +825,7 @@ describe('UserProfileService', () => { startContract.suggest({ name: 'some', size: 3, - dataPath: '*', + dataPath: 'one,two', requiredPrivileges: { spaceId: 'some-space', privileges: { kibana: ['privilege-1', 'privilege-2'] }, @@ -842,7 +879,7 @@ describe('UserProfileService', () => { ).toHaveBeenCalledWith({ name: 'some', size: 10, - data: 'kibana.*', + data: 'kibana.one,kibana.two', }); expect(mockAuthz.checkUserProfilesPrivileges).toHaveBeenCalledTimes(1); @@ -891,7 +928,7 @@ describe('UserProfileService', () => { startContract.suggest({ name: 'some', size: 11, - dataPath: '*', + dataPath: 'one,two', requiredPrivileges: { spaceId: 'some-space', privileges: { kibana: ['privilege-1', 'privilege-2'] }, @@ -933,7 +970,7 @@ describe('UserProfileService', () => { ).toHaveBeenCalledWith({ name: 'some', size: 22, - data: 'kibana.*', + data: 'kibana.one,kibana.two', }); expect(mockAuthz.checkUserProfilesPrivileges).toHaveBeenCalledTimes(3); @@ -992,7 +1029,7 @@ describe('UserProfileService', () => { startContract.suggest({ name: 'some', size: 2, - dataPath: '*', + dataPath: 'one,two', requiredPrivileges: { spaceId: 'some-space', privileges: { kibana: ['privilege-1', 'privilege-2'] }, @@ -1034,7 +1071,7 @@ describe('UserProfileService', () => { ).toHaveBeenCalledWith({ name: 'some', size: 10, - data: 'kibana.*', + data: 'kibana.one,kibana.two', }); expect(mockAuthz.checkUserProfilesPrivileges).toHaveBeenCalledTimes(1); @@ -1049,3 +1086,19 @@ describe('UserProfileService', () => { }); }); }); + +describe('prefixCommaSeparatedValues', () => { + it('should prefix each value', () => { + expect(prefixCommaSeparatedValues('one,two,three', '_')).toBe('_.one,_.two,_.three'); + }); + + it('should trim whitespace', () => { + expect(prefixCommaSeparatedValues('one , two, three ', '_')).toBe('_.one,_.two,_.three'); + }); + + it('should ignore empty values', () => { + expect(prefixCommaSeparatedValues('', '_')).toBe(''); + expect(prefixCommaSeparatedValues(' ', '_')).toBe(''); + expect(prefixCommaSeparatedValues(' ,, ', '_')).toBe(''); + }); +}); diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.ts index 76948a1af9a73..8babcaae4f90a 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.ts @@ -155,7 +155,19 @@ export interface UserProfileSuggestParams { * Query string used to match name-related fields in user profiles. The following fields are treated as * name-related: username, full_name and email. */ - name: string; + name?: string; + + /** + * Extra search criteria to improve relevance of the suggestion result. A profile matching the + * specified hint is ranked higher in the response. But not-matching the hint does not exclude a + * profile from the response as long as it matches the `name` field query. + */ + hint?: { + /** + * A list of Profile UIDs to match against. + */ + uids: string[]; + }; /** * Desired number of suggestion to return. The default value is 10. @@ -322,7 +334,7 @@ export class UserProfileService { // @ts-expect-error Invalid response format. body = (await clusterClient.asInternalUser.security.getUserProfile({ uid: userSession.userProfileId, - data: dataPath ? `${KIBANA_DATA_ROOT}.${dataPath}` : undefined, + data: dataPath ? prefixCommaSeparatedValues(dataPath, KIBANA_DATA_ROOT) : undefined, })) as { profiles: SecurityUserProfileWithMetadata[] }; } catch (error) { this.logger.error( @@ -360,7 +372,7 @@ export class UserProfileService { // @ts-expect-error Invalid response format. const body = (await clusterClient.asInternalUser.security.getUserProfile({ uid: [...uids].join(','), - data: dataPath ? `${KIBANA_DATA_ROOT}.${dataPath}` : undefined, + data: dataPath ? prefixCommaSeparatedValues(dataPath, KIBANA_DATA_ROOT) : undefined, })) as { profiles: SecurityUserProfileWithMetadata[] }; return body.profiles.map((rawUserProfile) => parseUserProfile(rawUserProfile)); @@ -402,7 +414,7 @@ export class UserProfileService { throw Error("Current license doesn't support user profile collaboration APIs."); } - const { name, size = DEFAULT_SUGGESTIONS_COUNT, dataPath, requiredPrivileges } = params; + const { name, hint, size = DEFAULT_SUGGESTIONS_COUNT, dataPath, requiredPrivileges } = params; if (size > MAX_SUGGESTIONS_COUNT) { throw Error( `Can return up to ${MAX_SUGGESTIONS_COUNT} suggestions, but ${size} suggestions were requested.` @@ -422,9 +434,10 @@ export class UserProfileService { const body = await clusterClient.asInternalUser.security.suggestUserProfiles({ name, size: numberOfResultsToRequest, + hint, // If fetching data turns out to be a performance bottleneck, we can try to fetch data // only for the profiles that pass privileges check as a separate bulkGet request. - data: dataPath ? `${KIBANA_DATA_ROOT}.${dataPath}` : undefined, + data: dataPath ? prefixCommaSeparatedValues(dataPath, KIBANA_DATA_ROOT) : undefined, }); const filteredProfiles = @@ -504,3 +517,21 @@ export class UserProfileService { return filteredProfiles; } } + +/** + * Returns string of comma separated values prefixed with `prefix`. + * @param str String of comma separated values + * @param prefix Prefix to use prepend to each value + */ +export function prefixCommaSeparatedValues(str: string, prefix: string) { + return str + .split(',') + .reduce((accumulator, value) => { + const trimmedValue = value.trim(); + if (trimmedValue) { + accumulator.push(`${prefix}.${trimmedValue}`); + } + return accumulator; + }, []) + .join(','); +} diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 7b2c4e034a963..65c5757a1b1bb 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -260,16 +260,12 @@ export const UPDATE_OR_CREATE_LEGACY_ACTIONS = '/internal/api/detection/legacy/n * Detection engine routes */ export const DETECTION_ENGINE_URL = '/api/detection_engine' as const; -export const DETECTION_ENGINE_RULES_URL = `${DETECTION_ENGINE_URL}/rules` as const; -export const DETECTION_ENGINE_PREPACKAGED_URL = - `${DETECTION_ENGINE_RULES_URL}/prepackaged` as const; export const DETECTION_ENGINE_PRIVILEGES_URL = `${DETECTION_ENGINE_URL}/privileges` as const; export const DETECTION_ENGINE_INDEX_URL = `${DETECTION_ENGINE_URL}/index` as const; +export const DETECTION_ENGINE_RULES_URL = `${DETECTION_ENGINE_URL}/rules` as const; export const DETECTION_ENGINE_RULES_URL_FIND = `${DETECTION_ENGINE_RULES_URL}/_find` as const; export const DETECTION_ENGINE_TAGS_URL = `${DETECTION_ENGINE_URL}/tags` as const; -export const DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL = - `${DETECTION_ENGINE_RULES_URL}/prepackaged/_status` as const; export const DETECTION_ENGINE_RULES_BULK_ACTION = `${DETECTION_ENGINE_RULES_URL}/_bulk_action` as const; export const DETECTION_ENGINE_RULES_PREVIEW = `${DETECTION_ENGINE_RULES_URL}/preview` as const; @@ -300,13 +296,9 @@ export const RISK_SCORE_DELETE_STORED_SCRIPT = `${INTERNAL_RISK_SCORE_URL}/store * Internal detection engine routes */ export const INTERNAL_DETECTION_ENGINE_URL = '/internal/detection_engine' as const; -export const INTERNAL_DETECTION_ENGINE_RULES_URL = '/internal/detection_engine/rules' as const; -export const DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL = - `${INTERNAL_DETECTION_ENGINE_URL}/fleet/integrations/installed` as const; export const DETECTION_ENGINE_ALERTS_INDEX_URL = `${INTERNAL_DETECTION_ENGINE_URL}/signal/index` as const; -export const DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL = - `${INTERNAL_DETECTION_ENGINE_RULES_URL}/exceptions/_find_references` as const; + /** * Telemetry detection endpoint for any previews requested of what data we are * providing through UI/UX and for e2e tests. @@ -456,6 +448,7 @@ export const NEW_FEATURES_TOUR_STORAGE_KEYS = { export const RULE_DETAILS_EXECUTION_LOG_TABLE_SHOW_METRIC_COLUMNS_STORAGE_KEY = 'securitySolution.ruleDetails.ruleExecutionLog.showMetrics.v8.2'; +// TODO: https://github.com/elastic/kibana/pull/142950 /** * Error codes that can be thrown during _bulk_action API dry_run call and be processed and displayed to end user */ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/get_installed_integrations_response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/api/get_installed_integrations/response_schema.ts similarity index 80% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/get_installed_integrations_response_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/api/get_installed_integrations/response_schema.ts index 882fc3d81828a..d970fb7061a44 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/get_installed_integrations_response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/api/get_installed_integrations/response_schema.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { InstalledIntegrationArray } from '../common'; +import type { InstalledIntegrationArray } from '../../model/installed_integrations'; export interface GetInstalledIntegrationsResponse { installed_integrations: InstalledIntegrationArray; diff --git a/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/api/urls.ts b/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/api/urls.ts new file mode 100644 index 0000000000000..b1216d855284e --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/api/urls.ts @@ -0,0 +1,11 @@ +/* + * 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 { INTERNAL_DETECTION_ENGINE_URL as INTERNAL_URL } from '../../../constants'; + +export const GET_INSTALLED_INTEGRATIONS_URL = + `${INTERNAL_URL}/fleet/integrations/installed` as const; diff --git a/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/index.ts b/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/index.ts new file mode 100644 index 0000000000000..e79ebecbdb1cd --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/index.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export * from './api/get_installed_integrations/response_schema'; +export * from './api/urls'; + +export * from './model/installed_integrations'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/installed_integrations.ts b/x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/model/installed_integrations.ts similarity index 100% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/common/installed_integrations.ts rename to x-pack/plugins/security_solution/common/detection_engine/fleet_integrations/model/installed_integrations.ts diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_status_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/response_schema.test.ts similarity index 78% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_status_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/response_schema.test.ts index 8997ecadb36b6..e721e6f41cc19 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_status_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/response_schema.test.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; -import type { PrePackagedRulesAndTimelinesStatusSchema } from './prepackaged_rules_status_schema'; -import { prePackagedRulesAndTimelinesStatusSchema } from './prepackaged_rules_status_schema'; +import { pipe } from 'fp-ts/lib/pipeable'; import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -describe('prepackaged_rules_schema', () => { +import { GetPrebuiltRulesAndTimelinesStatusResponse } from './response_schema'; + +describe('Get prebuilt rules and timelines status response schema', () => { test('it should validate an empty prepackaged response with defaults', () => { - const payload: PrePackagedRulesAndTimelinesStatusSchema = { + const payload: GetPrebuiltRulesAndTimelinesStatusResponse = { rules_installed: 0, rules_not_installed: 0, rules_not_updated: 0, @@ -22,7 +22,7 @@ describe('prepackaged_rules_schema', () => { timelines_not_installed: 0, timelines_not_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesStatusSchema.decode(payload); + const decoded = GetPrebuiltRulesAndTimelinesStatusResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -31,7 +31,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should not validate an extra invalid field added', () => { - const payload: PrePackagedRulesAndTimelinesStatusSchema & { invalid_field: string } = { + const payload: GetPrebuiltRulesAndTimelinesStatusResponse & { invalid_field: string } = { rules_installed: 0, rules_not_installed: 0, rules_not_updated: 0, @@ -41,7 +41,7 @@ describe('prepackaged_rules_schema', () => { timelines_not_installed: 0, timelines_not_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesStatusSchema.decode(payload); + const decoded = GetPrebuiltRulesAndTimelinesStatusResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -50,7 +50,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response with a negative "rules_installed" number', () => { - const payload: PrePackagedRulesAndTimelinesStatusSchema = { + const payload: GetPrebuiltRulesAndTimelinesStatusResponse = { rules_installed: -1, rules_not_installed: 0, rules_not_updated: 0, @@ -59,7 +59,7 @@ describe('prepackaged_rules_schema', () => { timelines_not_installed: 0, timelines_not_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesStatusSchema.decode(payload); + const decoded = GetPrebuiltRulesAndTimelinesStatusResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -70,7 +70,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response with a negative "rules_not_installed"', () => { - const payload: PrePackagedRulesAndTimelinesStatusSchema = { + const payload: GetPrebuiltRulesAndTimelinesStatusResponse = { rules_installed: 0, rules_not_installed: -1, rules_not_updated: 0, @@ -79,7 +79,7 @@ describe('prepackaged_rules_schema', () => { timelines_not_installed: 0, timelines_not_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesStatusSchema.decode(payload); + const decoded = GetPrebuiltRulesAndTimelinesStatusResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -90,7 +90,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response with a negative "rules_not_updated"', () => { - const payload: PrePackagedRulesAndTimelinesStatusSchema = { + const payload: GetPrebuiltRulesAndTimelinesStatusResponse = { rules_installed: 0, rules_not_installed: 0, rules_not_updated: -1, @@ -99,7 +99,7 @@ describe('prepackaged_rules_schema', () => { timelines_not_installed: 0, timelines_not_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesStatusSchema.decode(payload); + const decoded = GetPrebuiltRulesAndTimelinesStatusResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -110,7 +110,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response with a negative "rules_custom_installed"', () => { - const payload: PrePackagedRulesAndTimelinesStatusSchema = { + const payload: GetPrebuiltRulesAndTimelinesStatusResponse = { rules_installed: 0, rules_not_installed: 0, rules_not_updated: 0, @@ -119,7 +119,7 @@ describe('prepackaged_rules_schema', () => { timelines_not_installed: 0, timelines_not_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesStatusSchema.decode(payload); + const decoded = GetPrebuiltRulesAndTimelinesStatusResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -130,7 +130,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response if "rules_installed" is not there', () => { - const payload: PrePackagedRulesAndTimelinesStatusSchema = { + const payload: GetPrebuiltRulesAndTimelinesStatusResponse = { rules_installed: 0, rules_not_installed: 0, rules_not_updated: 0, @@ -141,7 +141,7 @@ describe('prepackaged_rules_schema', () => { }; // @ts-expect-error delete payload.rules_installed; - const decoded = prePackagedRulesAndTimelinesStatusSchema.decode(payload); + const decoded = GetPrebuiltRulesAndTimelinesStatusResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); diff --git a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/response_schema.ts new file mode 100644 index 0000000000000..f5c26b81682a1 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/response_schema.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 * as t from 'io-ts'; +import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; + +export type GetPrebuiltRulesAndTimelinesStatusResponse = t.TypeOf< + typeof GetPrebuiltRulesAndTimelinesStatusResponse +>; +export const GetPrebuiltRulesAndTimelinesStatusResponse = t.exact( + t.type({ + rules_custom_installed: PositiveInteger, + rules_installed: PositiveInteger, + rules_not_installed: PositiveInteger, + rules_not_updated: PositiveInteger, + + timelines_installed: PositiveInteger, + timelines_not_installed: PositiveInteger, + timelines_not_updated: PositiveInteger, + }) +); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/response_schema.test.ts similarity index 76% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/response_schema.test.ts index 393a071d21b32..6833a5891a2c2 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/response_schema.test.ts @@ -5,21 +5,21 @@ * 2.0. */ -import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; -import type { PrePackagedRulesAndTimelinesSchema } from './prepackaged_rules_schema'; -import { prePackagedRulesAndTimelinesSchema } from './prepackaged_rules_schema'; +import { pipe } from 'fp-ts/lib/pipeable'; import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -describe('prepackaged_rules_schema', () => { +import { InstallPrebuiltRulesAndTimelinesResponse } from './response_schema'; + +describe('Install prebuilt rules and timelines response schema', () => { test('it should validate an empty prepackaged response with defaults', () => { - const payload: PrePackagedRulesAndTimelinesSchema = { + const payload: InstallPrebuiltRulesAndTimelinesResponse = { rules_installed: 0, rules_updated: 0, timelines_installed: 0, timelines_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesSchema.decode(payload); + const decoded = InstallPrebuiltRulesAndTimelinesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -28,14 +28,14 @@ describe('prepackaged_rules_schema', () => { }); test('it should not validate an extra invalid field added', () => { - const payload: PrePackagedRulesAndTimelinesSchema & { invalid_field: string } = { + const payload: InstallPrebuiltRulesAndTimelinesResponse & { invalid_field: string } = { rules_installed: 0, rules_updated: 0, invalid_field: 'invalid', timelines_installed: 0, timelines_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesSchema.decode(payload); + const decoded = InstallPrebuiltRulesAndTimelinesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -44,13 +44,13 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response with a negative "rules_installed" number', () => { - const payload: PrePackagedRulesAndTimelinesSchema = { + const payload: InstallPrebuiltRulesAndTimelinesResponse = { rules_installed: -1, rules_updated: 0, timelines_installed: 0, timelines_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesSchema.decode(payload); + const decoded = InstallPrebuiltRulesAndTimelinesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -61,13 +61,13 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response with a negative "rules_updated"', () => { - const payload: PrePackagedRulesAndTimelinesSchema = { + const payload: InstallPrebuiltRulesAndTimelinesResponse = { rules_installed: 0, rules_updated: -1, timelines_installed: 0, timelines_updated: 0, }; - const decoded = prePackagedRulesAndTimelinesSchema.decode(payload); + const decoded = InstallPrebuiltRulesAndTimelinesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -78,7 +78,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response if "rules_installed" is not there', () => { - const payload: PrePackagedRulesAndTimelinesSchema = { + const payload: InstallPrebuiltRulesAndTimelinesResponse = { rules_installed: 0, rules_updated: 0, timelines_installed: 0, @@ -86,7 +86,7 @@ describe('prepackaged_rules_schema', () => { }; // @ts-expect-error delete payload.rules_installed; - const decoded = prePackagedRulesAndTimelinesSchema.decode(payload); + const decoded = InstallPrebuiltRulesAndTimelinesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -97,7 +97,7 @@ describe('prepackaged_rules_schema', () => { }); test('it should NOT validate an empty prepackaged response if "rules_updated" is not there', () => { - const payload: PrePackagedRulesAndTimelinesSchema = { + const payload: InstallPrebuiltRulesAndTimelinesResponse = { rules_installed: 0, rules_updated: 0, timelines_installed: 0, @@ -105,7 +105,7 @@ describe('prepackaged_rules_schema', () => { }; // @ts-expect-error delete payload.rules_updated; - const decoded = prePackagedRulesAndTimelinesSchema.decode(payload); + const decoded = InstallPrebuiltRulesAndTimelinesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); diff --git a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/response_schema.ts new file mode 100644 index 0000000000000..7da2d6b1fae03 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/response_schema.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 * as t from 'io-ts'; +import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; + +export type InstallPrebuiltRulesAndTimelinesResponse = t.TypeOf< + typeof InstallPrebuiltRulesAndTimelinesResponse +>; +export const InstallPrebuiltRulesAndTimelinesResponse = t.exact( + t.type({ + rules_installed: PositiveInteger, + rules_updated: PositiveInteger, + + timelines_installed: PositiveInteger, + timelines_updated: PositiveInteger, + }) +); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/urls.ts similarity index 53% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/urls.ts index 538348dcc3275..449960916f239 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/urls.ts @@ -5,8 +5,7 @@ * 2.0. */ -import * as t from 'io-ts'; -import { updateRulesSchema } from './rule_schemas'; +import { DETECTION_ENGINE_RULES_URL as RULES } from '../../../constants'; -export const updateRulesBulkSchema = t.array(updateRulesSchema); -export type UpdateRulesBulkSchema = t.TypeOf; +export const PREBUILT_RULES_URL = `${RULES}/prepackaged` as const; +export const PREBUILT_RULES_STATUS_URL = `${RULES}/prepackaged/_status` as const; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_bulk_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/index.ts similarity index 53% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_bulk_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/index.ts index e877737885925..5ec8f617f1546 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_bulk_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/index.ts @@ -5,9 +5,8 @@ * 2.0. */ -import * as t from 'io-ts'; +export * from './api/get_prebuilt_rules_and_timelines_status/response_schema'; +export * from './api/install_prebuilt_rules_and_timelines/response_schema'; +export * from './api/urls'; -import { createRulesSchema } from './rule_schemas'; - -export const createRulesBulkSchema = t.array(createRulesSchema); -export type CreateRulesBulkSchema = t.TypeOf; +export * from './model/prebuilt_rule'; diff --git a/x-pack/plugins/apm/common/rules/apm_rule_registry_settings.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/mocks.ts similarity index 81% rename from x-pack/plugins/apm/common/rules/apm_rule_registry_settings.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/mocks.ts index 1257db4e6a4d3..2850442ce975c 100644 --- a/x-pack/plugins/apm/common/rules/apm_rule_registry_settings.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/mocks.ts @@ -5,6 +5,4 @@ * 2.0. */ -export const apmRuleRegistrySettings = { - name: 'apm', -}; +export * from './model/prebuilt_rule.mock'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.mock.ts similarity index 83% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.mock.ts index 841e0aa5a13da..d81f23cde9966 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.mock.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { AddPrepackagedRulesSchema } from './add_prepackaged_rules_schema'; +import type { PrebuiltRuleToInstall } from './prebuilt_rule'; -export const getAddPrepackagedRulesSchemaMock = (): AddPrepackagedRulesSchema => ({ +export const getPrebuiltRuleMock = (): PrebuiltRuleToInstall => ({ description: 'some description', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', @@ -19,7 +19,7 @@ export const getAddPrepackagedRulesSchemaMock = (): AddPrepackagedRulesSchema => version: 1, }); -export const getAddPrepackagedThreatMatchRulesSchemaMock = (): AddPrepackagedRulesSchema => ({ +export const getPrebuiltThreatMatchRuleMock = (): PrebuiltRuleToInstall => ({ description: 'some description', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.test.ts similarity index 75% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.test.ts index 091ce8bd10fa3..4d08c9391fab8 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.test.ts @@ -5,23 +5,20 @@ * 2.0. */ -import type { AddPrepackagedRulesSchema } from './add_prepackaged_rules_schema'; -import { addPrepackagedRulesSchema } from './add_prepackaged_rules_schema'; - -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; -import { - getAddPrepackagedRulesSchemaMock, - getAddPrepackagedThreatMatchRulesSchemaMock, -} from './add_prepackaged_rules_schema.mock'; -import { getListArrayMock } from '../types/lists.mock'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListArrayMock } from '../../schemas/types/lists.mock'; + +import { PrebuiltRuleToInstall } from './prebuilt_rule'; +import { getPrebuiltRuleMock, getPrebuiltThreatMatchRuleMock } from './prebuilt_rule.mock'; -describe('add prepackaged rules schema', () => { +describe('Prebuilt rule schema', () => { test('empty objects do not validate', () => { - const payload: Partial = {}; + const payload: Partial = {}; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -46,12 +43,12 @@ describe('add prepackaged rules schema', () => { }); test('made up values do not validate', () => { - const payload: AddPrepackagedRulesSchema & { madeUp: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall & { madeUp: string } = { + ...getPrebuiltRuleMock(), madeUp: 'hi', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); @@ -59,11 +56,11 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -85,12 +82,12 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -109,13 +106,13 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -134,14 +131,14 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', to: 'now', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -160,7 +157,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, name] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -168,7 +165,7 @@ describe('add prepackaged rules schema', () => { name: 'some-name', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -184,7 +181,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, name, severity] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -193,7 +190,7 @@ describe('add prepackaged rules schema', () => { severity: 'low', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -206,7 +203,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -216,7 +213,7 @@ describe('add prepackaged rules schema', () => { type: 'query', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -227,7 +224,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -238,7 +235,7 @@ describe('add prepackaged rules schema', () => { type: 'query', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -249,7 +246,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -261,7 +258,7 @@ describe('add prepackaged rules schema', () => { index: ['index-1'], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -272,7 +269,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, query, index, interval, version] does validate', () => { - const payload: AddPrepackagedRulesSchema = { + const payload: PrebuiltRuleToInstall = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -287,14 +284,14 @@ describe('add prepackaged rules schema', () => { version: 1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.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 = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -309,7 +306,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -319,7 +316,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, version] does validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -335,14 +332,14 @@ describe('add prepackaged rules schema', () => { version: 1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.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 } = { + const payload: Partial & { output_index: string } = { rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -358,7 +355,7 @@ describe('add prepackaged rules schema', () => { language: 'kuery', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -368,7 +365,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, version] does validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -382,38 +379,38 @@ describe('add prepackaged rules schema', () => { version: 1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can send in a namespace', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), namespace: 'a namespace', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can send in an empty array to threat', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), threat: [], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.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, filter, risk_score, output_index, threat] does validate', () => { - const payload: AddPrepackagedRulesSchema = { + const payload: PrebuiltRuleToInstall = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -444,31 +441,31 @@ describe('add prepackaged rules schema', () => { version: 1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('allows references to be sent as valid', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), references: ['index-1'], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('immutable cannot be set in a pre-packaged rule', () => { - const payload: AddPrepackagedRulesSchema & { immutable: boolean } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall & { immutable: boolean } = { + ...getPrebuiltRuleMock(), immutable: true, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['invalid keys "immutable"']); @@ -476,11 +473,11 @@ describe('add prepackaged rules schema', () => { }); test('rule_id is required', () => { - const payload: AddPrepackagedRulesSchema = getAddPrepackagedRulesSchemaMock(); + const payload: PrebuiltRuleToInstall = getPrebuiltRuleMock(); // @ts-expect-error delete payload.rule_id; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -490,12 +487,12 @@ describe('add prepackaged rules schema', () => { }); test('references cannot be numbers', () => { - const payload: Omit & { references: number[] } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { references: number[] } = { + ...getPrebuiltRuleMock(), references: [5], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "references"']); @@ -503,12 +500,12 @@ describe('add prepackaged rules schema', () => { }); test('indexes cannot be numbers', () => { - const payload: Omit & { index: number[] } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { index: number[] } = { + ...getPrebuiltRuleMock(), index: [5], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "index"']); @@ -517,23 +514,23 @@ describe('add prepackaged rules schema', () => { test('saved_query type can have filters with it', () => { const payload = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), filters: [], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('filters cannot be a string', () => { - const payload: Omit & { filters: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { filters: string } = { + ...getPrebuiltRuleMock(), filters: 'some string', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -544,11 +541,11 @@ describe('add prepackaged rules schema', () => { test('language validates with kuery', () => { const payload = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), language: 'kuery', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -556,23 +553,23 @@ describe('add prepackaged rules schema', () => { test('language validates with lucene', () => { const payload = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), language: 'lucene', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('language does not validate with something made up', () => { - const payload: Omit & { language: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { language: string } = { + ...getPrebuiltRuleMock(), language: 'something-made-up', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -582,12 +579,12 @@ describe('add prepackaged rules schema', () => { }); test('max_signals cannot be negative', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), max_signals: -1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -597,12 +594,12 @@ describe('add prepackaged rules schema', () => { }); test('max_signals cannot be zero', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), max_signals: 0, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.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"']); @@ -610,36 +607,36 @@ describe('add prepackaged rules schema', () => { }); test('max_signals can be 1', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), max_signals: 1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can optionally send in an array of tags', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), tags: ['tag_1', 'tag_2'], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot send in an array of tags that are numbers', () => { - const payload: Omit & { tags: number[] } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { tags: number[] } = { + ...getPrebuiltRuleMock(), tags: [0, 1, 2], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -651,10 +648,10 @@ describe('add prepackaged rules schema', () => { }); test('You cannot send in an array of threat that are missing "framework"', () => { - const payload: Omit & { - threat: Array>>; + const payload: Omit & { + threat: Array>>; } = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), threat: [ { tactic: { @@ -673,7 +670,7 @@ describe('add prepackaged rules schema', () => { ], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -683,10 +680,10 @@ describe('add prepackaged rules schema', () => { }); test('You cannot send in an array of threat that are missing "tactic"', () => { - const payload: Omit & { - threat: Array>>; + const payload: Omit & { + threat: Array>>; } = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), threat: [ { framework: 'fake', @@ -701,7 +698,7 @@ describe('add prepackaged rules schema', () => { ], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -711,10 +708,10 @@ describe('add prepackaged rules schema', () => { }); test('You can send in an array of threat that are missing "technique"', () => { - const payload: Omit & { - threat: Array>>; + const payload: Omit & { + threat: Array>>; } = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), threat: [ { framework: 'fake', @@ -727,33 +724,33 @@ describe('add prepackaged rules schema', () => { ], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can optionally send in an array of false positives', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), false_positives: ['false_1', 'false_2'], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot send in an array of false positives that are numbers', () => { - const payload: Omit & { + const payload: Omit & { false_positives: number[]; } = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), false_positives: [5, 4], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -763,12 +760,12 @@ describe('add prepackaged rules schema', () => { expect(message.schema).toEqual({}); }); test('You cannot set the risk_score to 101', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), risk_score: 101, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -778,12 +775,12 @@ describe('add prepackaged rules schema', () => { }); test('You cannot set the risk_score to -1', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), risk_score: -1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.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"']); @@ -791,50 +788,50 @@ describe('add prepackaged rules schema', () => { }); test('You can set the risk_score to 0', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), risk_score: 0, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can set the risk_score to 100', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), risk_score: 100, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can set meta to any object you want', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), meta: { somethingMadeUp: { somethingElse: true }, }, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot create meta as a string', () => { - const payload: Omit & { meta: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { meta: string } = { + ...getPrebuiltRuleMock(), meta: 'should not work', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -844,25 +841,25 @@ describe('add prepackaged rules schema', () => { }); test('validates with timeline_id and timeline_title', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), timeline_id: 'timeline-id', timeline_title: 'timeline-title', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { - const payload: Omit & { severity: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { severity: string } = { + ...getPrebuiltRuleMock(), severity: 'junk', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "junk" supplied to "severity"']); @@ -870,12 +867,12 @@ describe('add prepackaged rules schema', () => { }); test('You cannot send in an array of actions that are missing "group"', () => { - const payload: Omit = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit = { + ...getPrebuiltRuleMock(), actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -885,12 +882,12 @@ describe('add prepackaged rules schema', () => { }); test('You cannot send in an array of actions that are missing "id"', () => { - const payload: Omit = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit = { + ...getPrebuiltRuleMock(), actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -900,12 +897,12 @@ describe('add prepackaged rules schema', () => { }); test('You cannot send in an array of actions that are missing "action_type_id"', () => { - const payload: Omit = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit = { + ...getPrebuiltRuleMock(), actions: [{ group: 'group', id: 'id', params: {} }], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -915,12 +912,12 @@ describe('add prepackaged rules schema', () => { }); test('You cannot send in an array of actions that are missing "params"', () => { - const payload: Omit = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit = { + ...getPrebuiltRuleMock(), actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -930,8 +927,8 @@ describe('add prepackaged rules schema', () => { }); test('You cannot send in an array of actions that are including "actionTypeId"', () => { - const payload: Omit = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit = { + ...getPrebuiltRuleMock(), actions: [ { group: 'group', @@ -942,7 +939,7 @@ describe('add prepackaged rules schema', () => { ], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -953,38 +950,38 @@ describe('add prepackaged rules schema', () => { describe('note', () => { test('You can set note to a string', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), note: '# documentation markdown here', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can set note to an empty string', () => { - const payload: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), note: '', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot create note as an object', () => { - const payload: Omit & { note: {} } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit & { note: {} } = { + ...getPrebuiltRuleMock(), note: { somethingHere: 'something else', }, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -994,7 +991,7 @@ describe('add prepackaged rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note] does validate', () => { - const payload: AddPrepackagedRulesSchema = { + const payload: PrebuiltRuleToInstall = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1009,7 +1006,7 @@ describe('add prepackaged rules schema', () => { version: 1, }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1018,7 +1015,7 @@ describe('add prepackaged rules schema', () => { describe('exception_list', () => { test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, version, and exceptions_list] does validate', () => { - const payload: AddPrepackagedRulesSchema = { + const payload: PrebuiltRuleToInstall = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1035,14 +1032,14 @@ describe('add prepackaged rules schema', () => { exceptions_list: getListArrayMock(), }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.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, filter, risk_score, note, version, and empty exceptions_list] does validate', () => { - const payload: AddPrepackagedRulesSchema = { + const payload: PrebuiltRuleToInstall = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1059,7 +1056,7 @@ describe('add prepackaged rules schema', () => { exceptions_list: [], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1083,7 +1080,7 @@ describe('add prepackaged rules schema', () => { exceptions_list: [{ id: 'uuid_here', namespace_type: 'not a namespace type' }], }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1095,7 +1092,7 @@ describe('add prepackaged rules schema', () => { }); 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', () => { - const payload: AddPrepackagedRulesSchema = { + const payload: PrebuiltRuleToInstall = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1111,7 +1108,7 @@ describe('add prepackaged rules schema', () => { note: '# some markdown', }; - const decoded = addPrepackagedRulesSchema.decode(payload); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1120,8 +1117,8 @@ describe('add prepackaged rules schema', () => { describe('threat_mapping', () => { test('You can set a threat query, index, mapping, filters on a pre-packaged rule', () => { - const payload = getAddPrepackagedThreatMatchRulesSchemaMock(); - const decoded = addPrepackagedRulesSchema.decode(payload); + const payload = getPrebuiltThreatMatchRuleMock(); + const decoded = PrebuiltRuleToInstall.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.ts similarity index 53% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.ts index a836fc2ba2c10..e46615ee992b7 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule.ts @@ -6,23 +6,33 @@ */ import * as t from 'io-ts'; - -import { version } from '@kbn/securitysolution-io-ts-types'; - -import { rule_id, RelatedIntegrationArray, RequiredFieldArray, SetupGuide } from '../common'; -import { baseCreateParams, createTypeSpecific } from './rule_schemas'; +import { + RelatedIntegrationArray, + RequiredFieldArray, + SetupGuide, + RuleSignatureId, + RuleVersion, + BaseCreateProps, + TypeSpecificCreateProps, +} from '../../rule_schema'; /** * Big differences between this schema and the createRulesSchema * - rule_id is required here * - version is a required field that must exist */ -export const addPrepackagedRulesSchema = t.intersection([ - baseCreateParams, - createTypeSpecific, - // version is required in addPrepackagedRulesSchema, so this supercedes the defaultable +export type PrebuiltRuleToInstall = t.TypeOf; +export const PrebuiltRuleToInstall = t.intersection([ + BaseCreateProps, + TypeSpecificCreateProps, + // version is required in PrebuiltRuleToInstall, so this supercedes the defaultable // version in baseParams - t.exact(t.type({ rule_id, version })), + t.exact( + t.type({ + rule_id: RuleSignatureId, + version: RuleVersion, + }) + ), t.exact( t.partial({ related_integrations: RelatedIntegrationArray, @@ -31,4 +41,3 @@ export const addPrepackagedRulesSchema = t.intersection([ }) ), ]); -export type AddPrepackagedRulesSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_type_dependents.test.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule_validate_type_dependents.test.ts similarity index 74% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_type_dependents.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule_validate_type_dependents.test.ts index f9fd09d0a956b..33021d0fc9a1e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_type_dependents.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule_validate_type_dependents.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { AddPrepackagedRulesSchema } from './add_prepackaged_rules_schema'; -import { addPrepackagedRuleValidateTypeDependents } from './add_prepackaged_rules_type_dependents'; -import { getAddPrepackagedRulesSchemaMock } from './add_prepackaged_rules_schema.mock'; +import type { PrebuiltRuleToInstall } from './prebuilt_rule'; +import { addPrepackagedRuleValidateTypeDependents } from './prebuilt_rule_validate_type_dependents'; +import { getPrebuiltRuleMock } from './prebuilt_rule.mock'; -describe('add_prepackaged_rules_type_dependents', () => { +describe('addPrepackagedRuleValidateTypeDependents', () => { test('You cannot omit timeline_title when timeline_id is present', () => { - const schema: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const schema: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), timeline_id: '123', }; delete schema.timeline_title; @@ -21,8 +21,8 @@ describe('add_prepackaged_rules_type_dependents', () => { }); test('You cannot have empty string for timeline_title when timeline_id is present', () => { - const schema: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const schema: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), timeline_id: '123', timeline_title: '', }; @@ -31,8 +31,8 @@ describe('add_prepackaged_rules_type_dependents', () => { }); test('You cannot have timeline_title with an empty timeline_id', () => { - const schema: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const schema: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), timeline_id: '', timeline_title: 'some-title', }; @@ -41,8 +41,8 @@ describe('add_prepackaged_rules_type_dependents', () => { }); test('You cannot have timeline_title without timeline_id', () => { - const schema: AddPrepackagedRulesSchema = { - ...getAddPrepackagedRulesSchemaMock(), + const schema: PrebuiltRuleToInstall = { + ...getPrebuiltRuleMock(), timeline_title: 'some-title', }; delete schema.timeline_id; @@ -52,33 +52,33 @@ describe('add_prepackaged_rules_type_dependents', () => { test('threshold.value is required and has to be bigger than 0 when type is threshold and validates with it', () => { const schema = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), type: 'threshold', threshold: { field: '', value: -1, }, }; - const errors = addPrepackagedRuleValidateTypeDependents(schema as AddPrepackagedRulesSchema); + const errors = addPrepackagedRuleValidateTypeDependents(schema as PrebuiltRuleToInstall); expect(errors).toEqual(['"threshold.value" has to be bigger than 0']); }); test('threshold.field should contain 3 items or less', () => { const schema = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), type: 'threshold', threshold: { field: ['field-1', 'field-2', 'field-3', 'field-4'], value: 1, }, }; - const errors = addPrepackagedRuleValidateTypeDependents(schema as AddPrepackagedRulesSchema); + const errors = addPrepackagedRuleValidateTypeDependents(schema as PrebuiltRuleToInstall); expect(errors).toEqual(['Number of fields must be 3 or less']); }); test('threshold.cardinality[0].field should not be in threshold.field', () => { const schema = { - ...getAddPrepackagedRulesSchemaMock(), + ...getPrebuiltRuleMock(), type: 'threshold', threshold: { field: ['field-1', 'field-2', 'field-3'], @@ -91,7 +91,7 @@ describe('add_prepackaged_rules_type_dependents', () => { ], }, }; - const errors = addPrepackagedRuleValidateTypeDependents(schema as AddPrepackagedRulesSchema); + const errors = addPrepackagedRuleValidateTypeDependents(schema as PrebuiltRuleToInstall); expect(errors).toEqual(['Cardinality of a field that is being aggregated on is always 1']); }); }); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_type_dependents.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule_validate_type_dependents.ts similarity index 79% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_type_dependents.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule_validate_type_dependents.ts index c2595163b83be..3d9264b3f0556 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_type_dependents.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/prebuilt_rule_validate_type_dependents.ts @@ -5,9 +5,13 @@ * 2.0. */ -import type { AddPrepackagedRulesSchema } from './add_prepackaged_rules_schema'; +import type { PrebuiltRuleToInstall } from './prebuilt_rule'; -export const validateTimelineId = (rule: AddPrepackagedRulesSchema): string[] => { +export const addPrepackagedRuleValidateTypeDependents = (rule: PrebuiltRuleToInstall): string[] => { + return [...validateTimelineId(rule), ...validateTimelineTitle(rule), ...validateThreshold(rule)]; +}; + +const validateTimelineId = (rule: PrebuiltRuleToInstall): string[] => { if (rule.timeline_id != null) { if (rule.timeline_title == null) { return ['when "timeline_id" exists, "timeline_title" must also exist']; @@ -20,7 +24,7 @@ export const validateTimelineId = (rule: AddPrepackagedRulesSchema): string[] => return []; }; -export const validateTimelineTitle = (rule: AddPrepackagedRulesSchema): string[] => { +const validateTimelineTitle = (rule: PrebuiltRuleToInstall): string[] => { if (rule.timeline_title != null) { if (rule.timeline_id == null) { return ['when "timeline_title" exists, "timeline_id" must also exist']; @@ -33,7 +37,7 @@ export const validateTimelineTitle = (rule: AddPrepackagedRulesSchema): string[] return []; }; -export const validateThreshold = (rule: AddPrepackagedRulesSchema): string[] => { +const validateThreshold = (rule: PrebuiltRuleToInstall): string[] => { const errors: string[] = []; if (rule.type === 'threshold') { if (!rule.threshold) { @@ -55,9 +59,3 @@ export const validateThreshold = (rule: AddPrepackagedRulesSchema): string[] => } return errors; }; - -export const addPrepackagedRuleValidateTypeDependents = ( - rule: AddPrepackagedRulesSchema -): string[] => { - return [...validateTimelineId(rule), ...validateTimelineTitle(rule), ...validateThreshold(rule)]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rule_exception_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/create_rule_exceptions/request_schema.test.ts similarity index 62% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rule_exception_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/create_rule_exceptions/request_schema.test.ts index b76d8cd7cfe4a..93b4e9f128a7b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rule_exception_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/create_rule_exceptions/request_schema.test.ts @@ -5,19 +5,47 @@ * 2.0. */ -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; -import { createRuleExceptionsSchema } from './create_rule_exception_schema'; -import type { CreateRuleExceptionSchema } from './create_rule_exception_schema'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; import { getCreateExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; +import { + CreateRuleExceptionsRequestBody, + CreateRuleExceptionsRequestParams, +} from './request_schema'; + +describe('CreateRuleExceptionsRequestParams', () => { + test('empty objects do not validate', () => { + const payload: Partial = {}; + + const decoded = CreateRuleExceptionsRequestParams.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('validates string for id', () => { + const payload: Partial = { + id: '4656dc92-5832-11ea-8e2d-0242ac130003', + }; + + const decoded = CreateRuleExceptionsRequestParams.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual({ + id: '4656dc92-5832-11ea-8e2d-0242ac130003', + }); + }); +}); -describe('createRuleExceptionsSchema', () => { +describe('CreateRuleExceptionsRequestBody', () => { test('empty objects do not validate', () => { - const payload: CreateRuleExceptionSchema = {} as CreateRuleExceptionSchema; + const payload: CreateRuleExceptionsRequestBody = {} as CreateRuleExceptionsRequestBody; - const decoded = createRuleExceptionsSchema.decode(payload); + const decoded = CreateRuleExceptionsRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -27,7 +55,7 @@ describe('createRuleExceptionsSchema', () => { }); test('items without list_id validate', () => { - const payload: CreateRuleExceptionSchema = { + const payload: CreateRuleExceptionsRequestBody = { items: [ { description: 'Exception item for rule default exception list', @@ -45,12 +73,12 @@ describe('createRuleExceptionsSchema', () => { ], }; - const decoded = createRuleExceptionsSchema.decode(payload); + const decoded = CreateRuleExceptionsRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as CreateRuleExceptionSchema).items[0]).toEqual( + expect((message.schema as CreateRuleExceptionsRequestBody).items[0]).toEqual( expect.objectContaining({ comments: [], description: 'Exception item for rule default exception list', @@ -73,9 +101,9 @@ describe('createRuleExceptionsSchema', () => { test('items with list_id do not validate', () => { const payload = { items: [getCreateExceptionListItemSchemaMock()], - } as unknown as CreateRuleExceptionSchema; + } as unknown as CreateRuleExceptionsRequestBody; - const decoded = createRuleExceptionsSchema.decode(payload); + const decoded = CreateRuleExceptionsRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -85,7 +113,7 @@ describe('createRuleExceptionsSchema', () => { }); test('made up parameters do not validate', () => { - const payload: Partial & { madeUp: string } = { + const payload: Partial & { madeUp: string } = { items: [ { description: 'Exception item for rule default exception list', @@ -104,7 +132,7 @@ describe('createRuleExceptionsSchema', () => { madeUp: 'invalid value', }; - const decoded = createRuleExceptionsSchema.decode(payload); + const decoded = CreateRuleExceptionsRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/create_rule_exceptions/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/create_rule_exceptions/request_schema.ts new file mode 100644 index 0000000000000..e5777f9725383 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/create_rule_exceptions/request_schema.ts @@ -0,0 +1,46 @@ +/* + * 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 type { CreateRuleExceptionListItemSchemaDecoded } from '@kbn/securitysolution-io-ts-list-types'; +import { createRuleExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import type { RequiredKeepUndefined } from '@kbn/osquery-plugin/common/types'; + +import { RuleObjectId } from '../../../rule_schema'; + +/** + * URL path parameters of the API route. + */ +export type CreateRuleExceptionsRequestParams = t.TypeOf; +export const CreateRuleExceptionsRequestParams = t.exact( + t.type({ + id: RuleObjectId, + }) +); + +export type CreateRuleExceptionsRequestParamsDecoded = CreateRuleExceptionsRequestParams; + +/** + * Request body parameters of the API route. + */ +export type CreateRuleExceptionsRequestBody = t.TypeOf; +export const CreateRuleExceptionsRequestBody = t.exact( + t.type({ + items: t.array(createRuleExceptionListItemSchema), + }) +); + +/** + * This type is used after a decode since some things are defaults after a decode. + */ +export type CreateRuleExceptionsRequestBodyDecoded = Omit< + RequiredKeepUndefined, + 'items' +> & { + items: CreateRuleExceptionListItemSchemaDecoded[]; +}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_exception_list_references_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/request_schema.test.ts similarity index 92% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_exception_list_references_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/request_schema.test.ts index 60b7fd9141b29..644924e362d08 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_exception_list_references_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/request_schema.test.ts @@ -6,10 +6,10 @@ */ import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; -import { findExceptionReferencesOnRuleSchema } from './find_exception_list_references_schema'; -import type { FindExceptionReferencesOnRuleSchema } from './find_exception_list_references_schema'; +import { findExceptionReferencesOnRuleSchema } from './request_schema'; +import type { FindExceptionReferencesOnRuleSchema } from './request_schema'; -describe('find_exception_list_references_schema', () => { +describe('Find exception list references schema', () => { test('validates all fields', () => { const payload: FindExceptionReferencesOnRuleSchema = { ids: 'abc,def', diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_exception_list_references_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/request_schema.ts similarity index 100% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_exception_list_references_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/request_schema.ts diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/find_exception_list_references_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/response_schema.test.ts similarity index 97% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/find_exception_list_references_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/response_schema.test.ts index d8ab3d64fe783..c899ad46c3628 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/find_exception_list_references_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/response_schema.test.ts @@ -6,17 +6,17 @@ */ import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; +import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; import { exceptionListRuleReferencesSchema, rulesReferencedByExceptionListsSchema, -} from './find_exception_list_references_schema'; +} from './response_schema'; import type { ExceptionListRuleReferencesSchema, RulesReferencedByExceptionListsSchema, -} from './find_exception_list_references_schema'; -import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; +} from './response_schema'; -describe('find_exception_list_references_schema', () => { +describe('Find exception list references response schema', () => { describe('exceptionListRuleReferencesSchema', () => { test('validates all fields', () => { const payload: ExceptionListRuleReferencesSchema = { diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/find_exception_list_references_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/response_schema.ts similarity index 89% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/find_exception_list_references_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/response_schema.ts index 2bdcd0ba4cc2b..32589e2d165ea 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/find_exception_list_references_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/find_exception_references/response_schema.ts @@ -6,16 +6,14 @@ */ import * as t from 'io-ts'; - import { exceptionListSchema, listArray, list_id } from '@kbn/securitysolution-io-ts-list-types'; - -import { rule_id, id, name } from '../common/schemas'; +import { RuleName, RuleObjectId, RuleSignatureId } from '../../../rule_schema'; export const ruleReferenceRuleInfoSchema = t.exact( t.type({ - name, - id, - rule_id, + name: RuleName, + id: RuleObjectId, + rule_id: RuleSignatureId, exception_lists: listArray, }) ); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/urls.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/urls.ts new file mode 100644 index 0000000000000..1cc8e2ded7483 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/api/urls.ts @@ -0,0 +1,17 @@ +/* + * 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 { + DETECTION_ENGINE_RULES_URL as PUBLIC_RULES_URL, + INTERNAL_DETECTION_ENGINE_URL as INTERNAL_URL, +} from '../../../constants'; + +const INTERNAL_RULES_URL = `${INTERNAL_URL}/rules`; + +export const CREATE_RULE_EXCEPTIONS_URL = `${PUBLIC_RULES_URL}/{id}/exceptions`; +export const DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL = + `${INTERNAL_RULES_URL}/exceptions/_find_references` as const; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/index.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/index.ts new file mode 100644 index 0000000000000..d4b2fa83a4c58 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions/index.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export * from './api/create_rule_exceptions/request_schema'; +export * from './api/find_exception_references/request_schema'; +export * from './api/find_exception_references/response_schema'; +export * from './api/urls'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.mock.ts similarity index 75% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.mock.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.mock.ts index 1768acc8dfbfa..548d8b571660e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.mock.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { BulkAction, BulkActionEditType } from './perform_bulk_action_schema'; -import type { PerformBulkActionSchema } from './perform_bulk_action_schema'; +import { BulkAction, BulkActionEditType } from './request_schema'; +import type { PerformBulkActionRequestBody } from './request_schema'; -export const getPerformBulkActionSchemaMock = (): PerformBulkActionSchema => ({ +export const getPerformBulkActionSchemaMock = (): PerformBulkActionRequestBody => ({ query: '', ids: undefined, action: BulkAction.disable, }); -export const getPerformBulkActionEditSchemaMock = (): PerformBulkActionSchema => ({ +export const getPerformBulkActionEditSchemaMock = (): PerformBulkActionRequestBody => ({ query: '', ids: undefined, action: BulkAction.edit, diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.test.ts similarity index 94% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.test.ts index e8b276fa44ace..63de1d45ec3cb 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.test.ts @@ -5,26 +5,21 @@ * 2.0. */ -import type { PerformBulkActionSchema } from './perform_bulk_action_schema'; -import { - performBulkActionSchema, - BulkAction, - BulkActionEditType, -} from './perform_bulk_action_schema'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; import { left } from 'fp-ts/lib/Either'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { PerformBulkActionRequestBody, BulkAction, BulkActionEditType } from './request_schema'; const retrieveValidationMessage = (payload: unknown) => { - const decoded = performBulkActionSchema.decode(payload); + const decoded = PerformBulkActionRequestBody.decode(payload); const checked = exactCheck(payload, decoded); return foldLeftRight(checked); }; -describe('perform_bulk_action_schema', () => { +describe('Perform bulk action request schema', () => { describe('cases common to every bulk action', () => { // missing query means it will request for all rules test('valid request: missing query', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: undefined, action: BulkAction.enable, }; @@ -35,7 +30,7 @@ describe('perform_bulk_action_schema', () => { }); test('invalid request: missing action', () => { - const payload: Omit = { + const payload: Omit = { query: 'name: test', }; const message = retrieveValidationMessage(payload); @@ -48,7 +43,7 @@ describe('perform_bulk_action_schema', () => { }); test('invalid request: unknown action', () => { - const payload: Omit & { action: 'unknown' } = { + const payload: Omit & { action: 'unknown' } = { query: 'name: test', action: 'unknown', }; @@ -87,7 +82,7 @@ describe('perform_bulk_action_schema', () => { describe('bulk enable', () => { test('valid request', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.enable, }; @@ -99,7 +94,7 @@ describe('perform_bulk_action_schema', () => { describe('bulk disable', () => { test('valid request', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.disable, }; @@ -111,7 +106,7 @@ describe('perform_bulk_action_schema', () => { describe('bulk export', () => { test('valid request', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.export, }; @@ -123,7 +118,7 @@ describe('perform_bulk_action_schema', () => { describe('bulk delete', () => { test('valid request', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.delete, }; @@ -135,7 +130,7 @@ describe('perform_bulk_action_schema', () => { describe('bulk duplicate', () => { test('valid request', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.duplicate, }; @@ -271,7 +266,7 @@ describe('perform_bulk_action_schema', () => { }); test('valid request: set_index_patterns edit action', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [{ type: BulkActionEditType.set_index_patterns, value: ['logs-*'] }], @@ -284,7 +279,7 @@ describe('perform_bulk_action_schema', () => { }); test('valid request: add_index_patterns edit action', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [{ type: BulkActionEditType.add_index_patterns, value: ['logs-*'] }], @@ -297,7 +292,7 @@ describe('perform_bulk_action_schema', () => { }); test('valid request: delete_index_patterns edit action', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [ @@ -356,7 +351,7 @@ describe('perform_bulk_action_schema', () => { }); test('valid request: set_timeline edit action', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [ @@ -408,7 +403,7 @@ describe('perform_bulk_action_schema', () => { }, }, ], - } as PerformBulkActionSchema; + } as PerformBulkActionRequestBody; const message = retrieveValidationMessage(payload); @@ -434,7 +429,7 @@ describe('perform_bulk_action_schema', () => { }, }, ], - } as PerformBulkActionSchema; + } as PerformBulkActionRequestBody; const message = retrieveValidationMessage(payload); @@ -460,7 +455,7 @@ describe('perform_bulk_action_schema', () => { }, }, ], - } as PerformBulkActionSchema; + } as PerformBulkActionRequestBody; const message = retrieveValidationMessage(payload); @@ -475,7 +470,7 @@ describe('perform_bulk_action_schema', () => { }); test('valid request: set_schedule edit action', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [ @@ -487,7 +482,7 @@ describe('perform_bulk_action_schema', () => { }, }, ], - } as PerformBulkActionSchema; + } as PerformBulkActionRequestBody; const message = retrieveValidationMessage(payload); @@ -590,7 +585,7 @@ describe('perform_bulk_action_schema', () => { }); test('valid request: add_rule_actions edit action', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [ @@ -621,7 +616,7 @@ describe('perform_bulk_action_schema', () => { }); test('valid request: set_rule_actions edit action', () => { - const payload: PerformBulkActionSchema = { + const payload: PerformBulkActionRequestBody = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.ts similarity index 59% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.ts index 0140e5f8d9262..6e5248075b7dc 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema.ts @@ -6,15 +6,21 @@ */ import * as t from 'io-ts'; -import { NonEmptyArray, TimeDuration, enumeration } from '@kbn/securitysolution-io-ts-types'; +import { NonEmptyArray, TimeDuration } from '@kbn/securitysolution-io-ts-types'; import { - action_group as actionGroup, - action_params as actionParams, - action_id as actionId, + RuleActionGroup, + RuleActionId, + RuleActionParams, } from '@kbn/securitysolution-io-ts-alerting-types'; -import { queryOrUndefined, tags, index, timeline_id, timeline_title } from '../common/schemas'; +import { + IndexPatternArray, + RuleQuery, + RuleTagArray, + TimelineTemplateId, + TimelineTemplateTitle, +} from '../../../../rule_schema'; export enum BulkAction { 'enable' = 'enable', @@ -25,8 +31,6 @@ export enum BulkAction { 'edit' = 'edit', } -export const bulkAction = enumeration('BulkAction', BulkAction); - export enum BulkActionEditType { 'add_tags' = 'add_tags', 'delete_tags' = 'delete_tags', @@ -40,7 +44,8 @@ export enum BulkActionEditType { 'set_schedule' = 'set_schedule', } -export const throttleForBulkActions = t.union([ +export type ThrottleForBulkActions = t.TypeOf; +export const ThrottleForBulkActions = t.union([ t.literal('rule'), TimeDuration({ allowedDurations: [ @@ -50,88 +55,81 @@ export const throttleForBulkActions = t.union([ ], }), ]); -export type ThrottleForBulkActions = t.TypeOf; -const bulkActionEditPayloadTags = t.type({ +type BulkActionEditPayloadTags = t.TypeOf; +const BulkActionEditPayloadTags = t.type({ type: t.union([ t.literal(BulkActionEditType.add_tags), t.literal(BulkActionEditType.delete_tags), t.literal(BulkActionEditType.set_tags), ]), - value: tags, + value: RuleTagArray, }); -export type BulkActionEditPayloadTags = t.TypeOf; - -const bulkActionEditPayloadIndexPatterns = t.intersection([ +type BulkActionEditPayloadIndexPatterns = t.TypeOf; +const BulkActionEditPayloadIndexPatterns = t.intersection([ t.type({ type: t.union([ t.literal(BulkActionEditType.add_index_patterns), t.literal(BulkActionEditType.delete_index_patterns), t.literal(BulkActionEditType.set_index_patterns), ]), - value: index, + value: IndexPatternArray, }), t.exact(t.partial({ overwrite_data_views: t.boolean })), ]); -export type BulkActionEditPayloadIndexPatterns = t.TypeOf< - typeof bulkActionEditPayloadIndexPatterns ->; - -const bulkActionEditPayloadTimeline = t.type({ +type BulkActionEditPayloadTimeline = t.TypeOf; +const BulkActionEditPayloadTimeline = t.type({ type: t.literal(BulkActionEditType.set_timeline), value: t.type({ - timeline_id, - timeline_title, + timeline_id: TimelineTemplateId, + timeline_title: TimelineTemplateTitle, }), }); -export type BulkActionEditPayloadTimeline = t.TypeOf; - /** * per rulesClient.bulkEdit rules actions operation contract (x-pack/plugins/alerting/server/rules_client/rules_client.ts) * normalized rule action object is expected (NormalizedAlertAction) as value for the edit operation */ -const normalizedRuleAction = t.exact( +type NormalizedRuleAction = t.TypeOf; +const NormalizedRuleAction = t.exact( t.type({ - group: actionGroup, - id: actionId, - params: actionParams, + group: RuleActionGroup, + id: RuleActionId, + params: RuleActionParams, }) ); -const bulkActionEditPayloadRuleActions = t.type({ +export type BulkActionEditPayloadRuleActions = t.TypeOf; +export const BulkActionEditPayloadRuleActions = t.type({ type: t.union([ t.literal(BulkActionEditType.add_rule_actions), t.literal(BulkActionEditType.set_rule_actions), ]), value: t.type({ - throttle: throttleForBulkActions, - actions: t.array(normalizedRuleAction), + throttle: ThrottleForBulkActions, + actions: t.array(NormalizedRuleAction), }), }); -export type BulkActionEditPayloadRuleActions = t.TypeOf; - -const bulkActionEditPayloadSchedule = t.type({ +type BulkActionEditPayloadSchedule = t.TypeOf; +const BulkActionEditPayloadSchedule = t.type({ type: t.literal(BulkActionEditType.set_schedule), value: t.type({ interval: TimeDuration({ allowedUnits: ['s', 'm', 'h'] }), lookback: TimeDuration({ allowedUnits: ['s', 'm', 'h'] }), }), }); -export type BulkActionEditPayloadSchedule = t.TypeOf; - -export const bulkActionEditPayload = t.union([ - bulkActionEditPayloadTags, - bulkActionEditPayloadIndexPatterns, - bulkActionEditPayloadTimeline, - bulkActionEditPayloadRuleActions, - bulkActionEditPayloadSchedule, -]); -export type BulkActionEditPayload = t.TypeOf; +export type BulkActionEditPayload = t.TypeOf; +export const BulkActionEditPayload = t.union([ + BulkActionEditPayloadTags, + BulkActionEditPayloadIndexPatterns, + BulkActionEditPayloadTimeline, + BulkActionEditPayloadRuleActions, + BulkActionEditPayloadSchedule, +]); /** * actions that modify rules attributes @@ -149,10 +147,14 @@ export type BulkActionEditForRuleParams = | BulkActionEditPayloadTimeline | BulkActionEditPayloadSchedule; -export const performBulkActionSchema = t.intersection([ +/** + * Request body parameters of the API route. + */ +export type PerformBulkActionRequestBody = t.TypeOf; +export const PerformBulkActionRequestBody = t.intersection([ t.exact( t.type({ - query: queryOrUndefined, + query: t.union([RuleQuery, t.undefined]), }) ), t.exact(t.partial({ ids: NonEmptyArray(t.string) })), @@ -171,16 +173,18 @@ export const performBulkActionSchema = t.intersection([ t.exact( t.type({ action: t.literal(BulkAction.edit), - [BulkAction.edit]: NonEmptyArray(bulkActionEditPayload), + [BulkAction.edit]: NonEmptyArray(BulkActionEditPayload), }) ), ]), ]); -export const performBulkActionQuerySchema = t.exact( +/** + * Query string parameters of the API route. + */ +export type PerformBulkActionRequestQuery = t.TypeOf; +export const PerformBulkActionRequestQuery = t.exact( t.partial({ dry_run: t.union([t.literal('true'), t.literal('false')]), }) ); - -export type PerformBulkActionSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_bulk_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_create_rules/request_schema.test.ts similarity index 77% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_bulk_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_create_rules/request_schema.test.ts index 5155b593583f9..d2c297d401edb 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_bulk_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_create_rules/request_schema.test.ts @@ -5,19 +5,18 @@ * 2.0. */ -import type { CreateRulesBulkSchema } from './create_rules_bulk_schema'; -import { createRulesBulkSchema } from './create_rules_bulk_schema'; +import { BulkCreateRulesRequestBody } from './request_schema'; import { exactCheck, foldLeftRight, formatErrors } from '@kbn/securitysolution-io-ts-utils'; -import { getCreateRulesSchemaMock } from './rule_schemas.mock'; +import { getCreateRulesSchemaMock } from '../../../../../rule_schema/mocks'; // only the basics of testing are here. // see: rule_schemas.test.ts for the bulk of the validation tests // this just wraps createRulesSchema in an array -describe('create_rules_bulk_schema', () => { +describe('Bulk create rules request schema', () => { test('can take an empty array and validate it', () => { - const payload: CreateRulesBulkSchema = []; + const payload: BulkCreateRulesRequestBody = []; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(output.errors).toEqual([]); @@ -27,7 +26,7 @@ describe('create_rules_bulk_schema', () => { test('made up values do not validate for a single element', () => { const payload: Array<{ madeUp: string }> = [{ madeUp: 'hi' }]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toContain( @@ -44,9 +43,9 @@ describe('create_rules_bulk_schema', () => { }); test('single array element does validate', () => { - const payload: CreateRulesBulkSchema = [getCreateRulesSchemaMock()]; + const payload: BulkCreateRulesRequestBody = [getCreateRulesSchemaMock()]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -54,9 +53,12 @@ describe('create_rules_bulk_schema', () => { }); test('two array elements do validate', () => { - const payload: CreateRulesBulkSchema = [getCreateRulesSchemaMock(), getCreateRulesSchemaMock()]; + const payload: BulkCreateRulesRequestBody = [ + getCreateRulesSchemaMock(), + getCreateRulesSchemaMock(), + ]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -67,9 +69,9 @@ describe('create_rules_bulk_schema', () => { const singleItem = getCreateRulesSchemaMock(); // @ts-expect-error delete singleItem.risk_score; - const payload: CreateRulesBulkSchema = [singleItem]; + const payload: BulkCreateRulesRequestBody = [singleItem]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -83,9 +85,9 @@ describe('create_rules_bulk_schema', () => { const secondItem = getCreateRulesSchemaMock(); // @ts-expect-error delete secondItem.risk_score; - const payload: CreateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -99,9 +101,9 @@ describe('create_rules_bulk_schema', () => { const secondItem = getCreateRulesSchemaMock(); // @ts-expect-error delete singleItem.risk_score; - const payload: CreateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -117,9 +119,9 @@ describe('create_rules_bulk_schema', () => { delete singleItem.risk_score; // @ts-expect-error delete secondItem.risk_score; - const payload: CreateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -134,9 +136,9 @@ describe('create_rules_bulk_schema', () => { madeUpValue: 'something', }; const secondItem = getCreateRulesSchemaMock(); - const payload: CreateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); @@ -149,9 +151,9 @@ describe('create_rules_bulk_schema', () => { ...getCreateRulesSchemaMock(), madeUpValue: 'something', }; - const payload: CreateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); @@ -167,9 +169,9 @@ describe('create_rules_bulk_schema', () => { ...getCreateRulesSchemaMock(), madeUpValue: 'something', }; - const payload: CreateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue,madeUpValue"']); @@ -180,7 +182,7 @@ describe('create_rules_bulk_schema', () => { const badSeverity = { ...getCreateRulesSchemaMock(), severity: 'madeup' }; const payload = [badSeverity]; - const decoded = createRulesBulkSchema.decode(payload); + 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"']); @@ -188,11 +190,11 @@ describe('create_rules_bulk_schema', () => { }); test('You can set "note" to a string', () => { - const payload: CreateRulesBulkSchema = [ + const payload: BulkCreateRulesRequestBody = [ { ...getCreateRulesSchemaMock(), note: '# test markdown' }, ]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -200,9 +202,9 @@ describe('create_rules_bulk_schema', () => { }); test('You can set "note" to an empty string', () => { - const payload: CreateRulesBulkSchema = [{ ...getCreateRulesSchemaMock(), note: '' }]; + const payload: BulkCreateRulesRequestBody = [{ ...getCreateRulesSchemaMock(), note: '' }]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -219,7 +221,7 @@ describe('create_rules_bulk_schema', () => { }, ]; - const decoded = createRulesBulkSchema.decode(payload); + const decoded = BulkCreateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_create_rules/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_create_rules/request_schema.ts new file mode 100644 index 0000000000000..846da78b4cbba --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_create_rules/request_schema.ts @@ -0,0 +1,15 @@ +/* + * 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 '../../../../../rule_schema'; + +/** + * 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/detection_engine/schemas/request/query_rules_bulk_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_delete_rules/request_schema.test.ts similarity index 73% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_bulk_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_delete_rules/request_schema.test.ts index dfbb168f24520..6a709db317109 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_bulk_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_delete_rules/request_schema.test.ts @@ -5,18 +5,17 @@ * 2.0. */ -import type { QueryRulesBulkSchema } from './query_rules_bulk_schema'; -import { queryRulesBulkSchema } from './query_rules_bulk_schema'; import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; +import { BulkDeleteRulesRequestBody } from './request_schema'; // only the basics of testing are here. // see: query_rules_schema.test.ts for the bulk of the validation tests // this just wraps queryRulesSchema in an array -describe('query_rules_bulk_schema', () => { +describe('Bulk delete rules request schema', () => { test('can take an empty array and validate it', () => { - const payload: QueryRulesBulkSchema = []; + const payload: BulkDeleteRulesRequestBody = []; - const decoded = queryRulesBulkSchema.decode(payload); + const decoded = BulkDeleteRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -24,13 +23,13 @@ describe('query_rules_bulk_schema', () => { }); test('non uuid being supplied to id does not validate', () => { - const payload: QueryRulesBulkSchema = [ + const payload: BulkDeleteRulesRequestBody = [ { id: '1', }, ]; - const decoded = queryRulesBulkSchema.decode(payload); + 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"']); @@ -38,14 +37,14 @@ describe('query_rules_bulk_schema', () => { }); test('both rule_id and id being supplied do validate', () => { - const payload: QueryRulesBulkSchema = [ + const payload: BulkDeleteRulesRequestBody = [ { rule_id: '1', id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f', }, ]; - const decoded = queryRulesBulkSchema.decode(payload); + const decoded = BulkDeleteRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -53,12 +52,12 @@ describe('query_rules_bulk_schema', () => { }); test('only id validates with two elements', () => { - const payload: QueryRulesBulkSchema = [ + const payload: BulkDeleteRulesRequestBody = [ { id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }, { id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }, ]; - const decoded = queryRulesBulkSchema.decode(payload); + const decoded = BulkDeleteRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -66,9 +65,11 @@ describe('query_rules_bulk_schema', () => { }); test('only rule_id validates', () => { - const payload: QueryRulesBulkSchema = [{ rule_id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }]; + const payload: BulkDeleteRulesRequestBody = [ + { rule_id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }, + ]; - const decoded = queryRulesBulkSchema.decode(payload); + const decoded = BulkDeleteRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -76,12 +77,12 @@ describe('query_rules_bulk_schema', () => { }); test('only rule_id validates with two elements', () => { - const payload: QueryRulesBulkSchema = [ + const payload: BulkDeleteRulesRequestBody = [ { rule_id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }, { rule_id: '2' }, ]; - const decoded = queryRulesBulkSchema.decode(payload); + const decoded = BulkDeleteRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -89,12 +90,12 @@ describe('query_rules_bulk_schema', () => { }); test('both id and rule_id validates with two separate elements', () => { - const payload: QueryRulesBulkSchema = [ + const payload: BulkDeleteRulesRequestBody = [ { id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }, { rule_id: '2' }, ]; - const decoded = queryRulesBulkSchema.decode(payload); + const decoded = BulkDeleteRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_delete_rules/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_delete_rules/request_schema.ts new file mode 100644 index 0000000000000..e290b57b4c404 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_delete_rules/request_schema.ts @@ -0,0 +1,15 @@ +/* + * 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 '../../crud/read_rule/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/detection_engine/schemas/request/patch_rules_bulk_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_patch_rules/request_schema.test.ts similarity index 72% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_bulk_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_patch_rules/request_schema.test.ts index 1b9b1f92faf2f..3d466d7d23894 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_bulk_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_patch_rules/request_schema.test.ts @@ -5,19 +5,18 @@ * 2.0. */ -import type { PatchRulesBulkSchema } from './patch_rules_bulk_schema'; -import { patchRulesBulkSchema } from './patch_rules_bulk_schema'; import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; -import type { PatchRulesSchema } from './patch_rules_schema'; +import type { PatchRuleRequestBody } from '../../crud/patch_rule/request_schema'; +import { BulkPatchRulesRequestBody } from './request_schema'; // only the basics of testing are here. // see: patch_rules_schema.test.ts for the bulk of the validation tests // this just wraps patchRulesSchema in an array -describe('patch_rules_bulk_schema', () => { +describe('Bulk patch rules request schema', () => { test('can take an empty array and validate it', () => { - const payload: PatchRulesBulkSchema = []; + const payload: BulkPatchRulesRequestBody = []; - const decoded = patchRulesBulkSchema.decode(payload); + const decoded = BulkPatchRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(output.errors).toEqual([]); @@ -25,9 +24,9 @@ describe('patch_rules_bulk_schema', () => { }); test('single array of [id] does validate', () => { - const payload: PatchRulesBulkSchema = [{ id: '4125761e-51da-4de9-a0c8-42824f532ddb' }]; + const payload: BulkPatchRulesRequestBody = [{ id: '4125761e-51da-4de9-a0c8-42824f532ddb' }]; - const decoded = patchRulesBulkSchema.decode(payload); + const decoded = BulkPatchRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -35,12 +34,12 @@ describe('patch_rules_bulk_schema', () => { }); test('two arrays of [id] validate', () => { - const payload: PatchRulesBulkSchema = [ + const payload: BulkPatchRulesRequestBody = [ { id: '4125761e-51da-4de9-a0c8-42824f532ddb' }, { id: '192f403d-b285-4251-9e8b-785fcfcf22e8' }, ]; - const decoded = patchRulesBulkSchema.decode(payload); + const decoded = BulkPatchRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -48,12 +47,12 @@ describe('patch_rules_bulk_schema', () => { }); test('can set "note" to be a string', () => { - const payload: PatchRulesBulkSchema = [ + const payload: BulkPatchRulesRequestBody = [ { id: '4125761e-51da-4de9-a0c8-42824f532ddb' }, { note: 'hi' }, ]; - const decoded = patchRulesBulkSchema.decode(payload); + const decoded = BulkPatchRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -61,12 +60,12 @@ describe('patch_rules_bulk_schema', () => { }); test('can set "note" to be an empty string', () => { - const payload: PatchRulesBulkSchema = [ + const payload: BulkPatchRulesRequestBody = [ { id: '4125761e-51da-4de9-a0c8-42824f532ddb' }, { note: '' }, ]; - const decoded = patchRulesBulkSchema.decode(payload); + const decoded = BulkPatchRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -74,12 +73,12 @@ describe('patch_rules_bulk_schema', () => { }); test('cannot set "note" to be anything other than a string', () => { - const payload: Array & { note?: object }> = [ + const payload: Array & { note?: object }> = [ { id: '4125761e-51da-4de9-a0c8-42824f532ddb' }, { note: { someprop: 'some value here' } }, ]; - const decoded = patchRulesBulkSchema.decode(payload); + const decoded = BulkPatchRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_patch_rules/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_patch_rules/request_schema.ts new file mode 100644 index 0000000000000..2dcd0c2a22d4b --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_patch_rules/request_schema.ts @@ -0,0 +1,15 @@ +/* + * 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 { PatchRuleRequestBody } from '../../crud/patch_rule/request_schema'; + +/** + * Request body parameters of the API route. + */ +export type BulkPatchRulesRequestBody = t.TypeOf; +export const BulkPatchRulesRequestBody = t.array(PatchRuleRequestBody); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_update_rules/request_schema.test.ts similarity index 74% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_update_rules/request_schema.test.ts index 416e43ccfa967..f2b3437273d01 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_update_rules/request_schema.test.ts @@ -5,20 +5,19 @@ * 2.0. */ -import type { UpdateRulesBulkSchema } from './update_rules_bulk_schema'; -import { updateRulesBulkSchema } from './update_rules_bulk_schema'; import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; -import { getUpdateRulesSchemaMock } from './rule_schemas.mock'; -import type { UpdateRulesSchema } from './rule_schemas'; +import type { RuleUpdateProps } from '../../../../../rule_schema'; +import { getUpdateRulesSchemaMock } from '../../../../../rule_schema/mocks'; +import { BulkUpdateRulesRequestBody } from './request_schema'; // only the basics of testing are here. // see: update_rules_schema.test.ts for the bulk of the validation tests // this just wraps updateRulesSchema in an array -describe('update_rules_bulk_schema', () => { +describe('Bulk update rules request schema', () => { test('can take an empty array and validate it', () => { - const payload: UpdateRulesBulkSchema = []; + const payload: BulkUpdateRulesRequestBody = []; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(output.errors).toEqual([]); @@ -28,7 +27,7 @@ describe('update_rules_bulk_schema', () => { test('made up values do not validate for a single element', () => { const payload: Array<{ madeUp: string }> = [{ madeUp: 'hi' }]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toContain( @@ -45,9 +44,9 @@ describe('update_rules_bulk_schema', () => { }); test('single array element does validate', () => { - const payload: UpdateRulesBulkSchema = [getUpdateRulesSchemaMock()]; + const payload: BulkUpdateRulesRequestBody = [getUpdateRulesSchemaMock()]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -55,9 +54,12 @@ describe('update_rules_bulk_schema', () => { }); test('two array elements do validate', () => { - const payload: UpdateRulesBulkSchema = [getUpdateRulesSchemaMock(), getUpdateRulesSchemaMock()]; + const payload: BulkUpdateRulesRequestBody = [ + getUpdateRulesSchemaMock(), + getUpdateRulesSchemaMock(), + ]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -68,9 +70,9 @@ describe('update_rules_bulk_schema', () => { const singleItem = getUpdateRulesSchemaMock(); // @ts-expect-error delete singleItem.risk_score; - const payload: UpdateRulesBulkSchema = [singleItem]; + const payload: BulkUpdateRulesRequestBody = [singleItem]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -84,9 +86,9 @@ describe('update_rules_bulk_schema', () => { const secondItem = getUpdateRulesSchemaMock(); // @ts-expect-error delete secondItem.risk_score; - const payload: UpdateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -100,9 +102,9 @@ describe('update_rules_bulk_schema', () => { const secondItem = getUpdateRulesSchemaMock(); // @ts-expect-error delete singleItem.risk_score; - const payload: UpdateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -118,9 +120,9 @@ describe('update_rules_bulk_schema', () => { delete singleItem.risk_score; // @ts-expect-error delete secondItem.risk_score; - const payload: UpdateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ @@ -130,14 +132,14 @@ describe('update_rules_bulk_schema', () => { }); test('two array elements where the first is invalid (extra key and value) but the second is valid will not validate', () => { - const singleItem: UpdateRulesSchema & { madeUpValue: string } = { + const singleItem: RuleUpdateProps & { madeUpValue: string } = { ...getUpdateRulesSchemaMock(), madeUpValue: 'something', }; const secondItem = getUpdateRulesSchemaMock(); const payload = [singleItem, secondItem]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); @@ -145,14 +147,14 @@ describe('update_rules_bulk_schema', () => { }); test('two array elements where the second is invalid (extra key and value) but the first is valid will not validate', () => { - const singleItem: UpdateRulesSchema = getUpdateRulesSchemaMock(); - const secondItem: UpdateRulesSchema & { madeUpValue: string } = { + const singleItem: RuleUpdateProps = getUpdateRulesSchemaMock(); + const secondItem: RuleUpdateProps & { madeUpValue: string } = { ...getUpdateRulesSchemaMock(), madeUpValue: 'something', }; - const payload: UpdateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); @@ -160,17 +162,17 @@ describe('update_rules_bulk_schema', () => { }); test('two array elements where both are invalid (extra key and value) will not validate', () => { - const singleItem: UpdateRulesSchema & { madeUpValue: string } = { + const singleItem: RuleUpdateProps & { madeUpValue: string } = { ...getUpdateRulesSchemaMock(), madeUpValue: 'something', }; - const secondItem: UpdateRulesSchema & { madeUpValue: string } = { + const secondItem: RuleUpdateProps & { madeUpValue: string } = { ...getUpdateRulesSchemaMock(), madeUpValue: 'something', }; - const payload: UpdateRulesBulkSchema = [singleItem, secondItem]; + const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue,madeUpValue"']); @@ -181,7 +183,7 @@ describe('update_rules_bulk_schema', () => { const badSeverity = { ...getUpdateRulesSchemaMock(), severity: 'madeup' }; const payload = [badSeverity]; - const decoded = updateRulesBulkSchema.decode(payload); + 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"']); @@ -189,11 +191,11 @@ describe('update_rules_bulk_schema', () => { }); test('You can set "namespace" to a string', () => { - const payload: UpdateRulesBulkSchema = [ + const payload: BulkUpdateRulesRequestBody = [ { ...getUpdateRulesSchemaMock(), namespace: 'a namespace' }, ]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -201,11 +203,11 @@ describe('update_rules_bulk_schema', () => { }); test('You can set "note" to a string', () => { - const payload: UpdateRulesBulkSchema = [ + const payload: BulkUpdateRulesRequestBody = [ { ...getUpdateRulesSchemaMock(), note: '# test markdown' }, ]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -213,9 +215,9 @@ describe('update_rules_bulk_schema', () => { }); test('You can set "note" to an empty string', () => { - const payload: UpdateRulesBulkSchema = [{ ...getUpdateRulesSchemaMock(), note: '' }]; + const payload: BulkUpdateRulesRequestBody = [{ ...getUpdateRulesSchemaMock(), note: '' }]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([]); @@ -232,7 +234,7 @@ describe('update_rules_bulk_schema', () => { }, ]; - const decoded = updateRulesBulkSchema.decode(payload); + const decoded = BulkUpdateRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const output = foldLeftRight(checked); expect(formatErrors(output.errors)).toEqual([ diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_update_rules/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_update_rules/request_schema.ts new file mode 100644 index 0000000000000..5409e7b2bda43 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/bulk_update_rules/request_schema.ts @@ -0,0 +1,15 @@ +/* + * 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 '../../../../../rule_schema'; + +/** + * 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/detection_engine/schemas/response/rules_bulk_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/response_schema.test.ts similarity index 70% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_bulk_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/response_schema.test.ts index 69e31522ef40a..044af119f99ec 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_bulk_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/response_schema.test.ts @@ -7,20 +7,19 @@ import { left } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; - -import type { RulesBulkSchema } from './rules_bulk_schema'; -import { rulesBulkSchema } from './rules_bulk_schema'; -import type { ErrorSchema } from './error_schema'; import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getRulesSchemaMock } from './rules_schema.mocks'; -import { getErrorSchemaMock } from './error_schema.mocks'; -import type { FullResponseSchema } from '../request'; +import type { RuleResponse } from '../../../../rule_schema'; +import { getRulesSchemaMock } from '../../../../rule_schema/mocks'; +import type { ErrorSchema } from '../../../../schemas/response/error_schema'; +import { getErrorSchemaMock } from '../../../../schemas/response/error_schema.mocks'; + +import { BulkCrudRulesResponse } from './response_schema'; -describe('prepackaged_rule_schema', () => { +describe('Bulk CRUD rules response schema', () => { test('it should validate a regular message and and error together with a uuid', () => { - const payload: RulesBulkSchema = [getRulesSchemaMock(), getErrorSchemaMock()]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [getRulesSchemaMock(), getErrorSchemaMock()]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -29,8 +28,8 @@ describe('prepackaged_rule_schema', () => { }); test('it should validate a regular message and and error together when the error has a non UUID', () => { - const payload: RulesBulkSchema = [getRulesSchemaMock(), getErrorSchemaMock('fake id')]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [getRulesSchemaMock(), getErrorSchemaMock('fake id')]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -39,8 +38,8 @@ describe('prepackaged_rule_schema', () => { }); test('it should validate an error', () => { - const payload: RulesBulkSchema = [getErrorSchemaMock('fake id')]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [getErrorSchemaMock('fake id')]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -52,8 +51,8 @@ describe('prepackaged_rule_schema', () => { const rule = getRulesSchemaMock(); // @ts-expect-error delete rule.name; - const payload: RulesBulkSchema = [rule]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [rule]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -68,8 +67,8 @@ describe('prepackaged_rule_schema', () => { const error = getErrorSchemaMock('fake id'); // @ts-expect-error delete error.error; - const payload: RulesBulkSchema = [error]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [error]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -80,10 +79,10 @@ describe('prepackaged_rule_schema', () => { }); test('it should NOT validate a type of "query" when it has extra data', () => { - const rule: FullResponseSchema & { invalid_extra_data?: string } = getRulesSchemaMock(); + const rule: RuleResponse & { invalid_extra_data?: string } = getRulesSchemaMock(); rule.invalid_extra_data = 'invalid_extra_data'; - const payload: RulesBulkSchema = [rule]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [rule]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -92,10 +91,10 @@ describe('prepackaged_rule_schema', () => { }); test('it should NOT validate a type of "query" when it has extra data next to a valid error', () => { - const rule: FullResponseSchema & { invalid_extra_data?: string } = getRulesSchemaMock(); + const rule: RuleResponse & { invalid_extra_data?: string } = getRulesSchemaMock(); rule.invalid_extra_data = 'invalid_extra_data'; - const payload: RulesBulkSchema = [getErrorSchemaMock(), rule]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [getErrorSchemaMock(), rule]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -107,8 +106,8 @@ describe('prepackaged_rule_schema', () => { type InvalidError = ErrorSchema & { invalid_extra_data?: string }; const error: InvalidError = getErrorSchemaMock(); error.invalid_extra_data = 'invalid'; - const payload: RulesBulkSchema = [error]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [error]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -120,8 +119,8 @@ describe('prepackaged_rule_schema', () => { type InvalidError = ErrorSchema & { invalid_extra_data?: string }; const error: InvalidError = getErrorSchemaMock(); error.invalid_extra_data = 'invalid'; - const payload: RulesBulkSchema = [getRulesSchemaMock(), error]; - const decoded = rulesBulkSchema.decode(payload); + const payload: BulkCrudRulesResponse = [getRulesSchemaMock(), error]; + const decoded = BulkCrudRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/response_schema.ts new file mode 100644 index 0000000000000..9a0144e2cf758 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/bulk_crud/response_schema.ts @@ -0,0 +1,14 @@ +/* + * 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 { RuleResponse } from '../../../../rule_schema'; +import { errorSchema } from '../../../../schemas/response/error_schema'; + +export type BulkCrudRulesResponse = t.TypeOf; +export const BulkCrudRulesResponse = t.array(t.union([RuleResponse, errorSchema])); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_type_dependents.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/create_rule/request_schema_validation.test.ts similarity index 68% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_type_dependents.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/create_rule/request_schema_validation.test.ts index 1fecd82cc2708..39ed8b028f054 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_type_dependents.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/create_rule/request_schema_validation.test.ts @@ -5,78 +5,81 @@ * 2.0. */ -import { getCreateRulesSchemaMock, getCreateThreatMatchRulesSchemaMock } from './rule_schemas.mock'; -import type { CreateRulesSchema } from './rule_schemas'; -import { createRuleValidateTypeDependents } from './create_rules_type_dependents'; +import type { RuleCreateProps } from '../../../../../rule_schema'; +import { + getCreateRulesSchemaMock, + getCreateThreatMatchRulesSchemaMock, +} from '../../../../../rule_schema/mocks'; +import { validateCreateRuleProps } from './request_schema_validation'; -describe('create_rules_type_dependents', () => { +describe('Create rule request schema, additional validation', () => { test('You cannot omit timeline_title when timeline_id is present', () => { - const schema: CreateRulesSchema = { + const schema: RuleCreateProps = { ...getCreateRulesSchemaMock(), timeline_id: '123', }; delete schema.timeline_title; - const errors = createRuleValidateTypeDependents(schema); + const errors = validateCreateRuleProps(schema); expect(errors).toEqual(['when "timeline_id" exists, "timeline_title" must also exist']); }); test('You cannot have empty string for timeline_title when timeline_id is present', () => { - const schema: CreateRulesSchema = { + const schema: RuleCreateProps = { ...getCreateRulesSchemaMock(), timeline_id: '123', timeline_title: '', }; - const errors = createRuleValidateTypeDependents(schema); + const errors = validateCreateRuleProps(schema); expect(errors).toEqual(['"timeline_title" cannot be an empty string']); }); test('You cannot have timeline_title with an empty timeline_id', () => { - const schema: CreateRulesSchema = { + const schema: RuleCreateProps = { ...getCreateRulesSchemaMock(), timeline_id: '', timeline_title: 'some-title', }; - const errors = createRuleValidateTypeDependents(schema); + const errors = validateCreateRuleProps(schema); expect(errors).toEqual(['"timeline_id" cannot be an empty string']); }); test('You cannot have timeline_title without timeline_id', () => { - const schema: CreateRulesSchema = { + const schema: RuleCreateProps = { ...getCreateRulesSchemaMock(), timeline_title: 'some-title', }; delete schema.timeline_id; - const errors = createRuleValidateTypeDependents(schema); + const errors = validateCreateRuleProps(schema); expect(errors).toEqual(['when "timeline_title" exists, "timeline_id" must also exist']); }); test('validates that both "items_per_search" and "concurrent_searches" works when together', () => { - const schema: CreateRulesSchema = { + const schema: RuleCreateProps = { ...getCreateThreatMatchRulesSchemaMock(), concurrent_searches: 10, items_per_search: 10, }; - const errors = createRuleValidateTypeDependents(schema); + const errors = validateCreateRuleProps(schema); expect(errors).toEqual([]); }); test('does NOT validate when only "items_per_search" is present', () => { - const schema: CreateRulesSchema = { + const schema: RuleCreateProps = { ...getCreateThreatMatchRulesSchemaMock(), items_per_search: 10, }; - const errors = createRuleValidateTypeDependents(schema); + const errors = validateCreateRuleProps(schema); expect(errors).toEqual([ 'when "items_per_search" exists, "concurrent_searches" must also exist', ]); }); test('does NOT validate when only "concurrent_searches" is present', () => { - const schema: CreateRulesSchema = { + const schema: RuleCreateProps = { ...getCreateThreatMatchRulesSchemaMock(), concurrent_searches: 10, }; - const errors = createRuleValidateTypeDependents(schema); + const errors = validateCreateRuleProps(schema); expect(errors).toEqual([ 'when "concurrent_searches" exists, "items_per_search" must also exist', ]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/create_rule/request_schema_validation.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/create_rule/request_schema_validation.ts new file mode 100644 index 0000000000000..fd2e4b06b63d6 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/create_rule/request_schema_validation.ts @@ -0,0 +1,79 @@ +/* + * 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 { RuleCreateProps } from '../../../../../rule_schema'; + +/** + * Additional validation that is implemented outside of the schema itself. + */ +export const validateCreateRuleProps = (props: RuleCreateProps): string[] => { + return [ + ...validateTimelineId(props), + ...validateTimelineTitle(props), + ...validateThreatMapping(props), + ...validateThreshold(props), + ]; +}; + +const validateTimelineId = (props: RuleCreateProps): string[] => { + if (props.timeline_id != null) { + if (props.timeline_title == null) { + return ['when "timeline_id" exists, "timeline_title" must also exist']; + } else if (props.timeline_id === '') { + return ['"timeline_id" cannot be an empty string']; + } else { + return []; + } + } + return []; +}; + +const validateTimelineTitle = (props: RuleCreateProps): string[] => { + if (props.timeline_title != null) { + if (props.timeline_id == null) { + return ['when "timeline_title" exists, "timeline_id" must also exist']; + } else if (props.timeline_title === '') { + return ['"timeline_title" cannot be an empty string']; + } else { + return []; + } + } + return []; +}; + +const validateThreatMapping = (props: RuleCreateProps): string[] => { + const errors: string[] = []; + if (props.type === 'threat_match') { + if (props.concurrent_searches != null && props.items_per_search == null) { + errors.push('when "concurrent_searches" exists, "items_per_search" must also exist'); + } + if (props.concurrent_searches == null && props.items_per_search != null) { + errors.push('when "items_per_search" exists, "concurrent_searches" must also exist'); + } + } + return errors; +}; + +const validateThreshold = (props: RuleCreateProps): string[] => { + const errors: string[] = []; + if (props.type === 'threshold') { + if (!props.threshold) { + errors.push('when "type" is "threshold", "threshold" is required'); + } else { + if ( + props.threshold.cardinality?.length && + props.threshold.field.includes(props.threshold.cardinality[0].field) + ) { + errors.push('Cardinality of a field that is being aggregated on is always 1'); + } + if (Array.isArray(props.threshold.field) && props.threshold.field.length > 3) { + errors.push('Number of fields must be 3 or less'); + } + } + } + return errors; +}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.mock.ts similarity index 81% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.mock.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.mock.ts index 1b3dab2e00691..285e773456d98 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.mock.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { PatchRulesSchema, ThresholdPatchSchema } from './patch_rules_schema'; +import type { PatchRuleRequestBody, ThresholdPatchRuleRequestBody } from './request_schema'; -export const getPatchRulesSchemaMock = (): PatchRulesSchema => ({ +export const getPatchRulesSchemaMock = (): PatchRuleRequestBody => ({ description: 'some description', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', @@ -18,7 +18,7 @@ export const getPatchRulesSchemaMock = (): PatchRulesSchema => ({ rule_id: 'rule-1', }); -export const getPatchThresholdRulesSchemaMock = (): ThresholdPatchSchema => ({ +export const getPatchThresholdRulesSchemaMock = (): ThresholdPatchRuleRequestBody => ({ description: 'some description', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.test.ts similarity index 80% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.test.ts index 2084f11ed4efa..36613736e3274 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.test.ts @@ -5,56 +5,56 @@ * 2.0. */ -import type { PatchRulesSchema } from './patch_rules_schema'; -import { patchRulesSchema } from './patch_rules_schema'; -import { getPatchRulesSchemaMock } from './patch_rules_schema.mock'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; -import { getListArrayMock } from '../types/lists.mock'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListArrayMock } from '../../../../../schemas/types/lists.mock'; +import { PatchRuleRequestBody } from './request_schema'; +import { getPatchRulesSchemaMock } from './request_schema.mock'; -describe('patch_rules_schema', () => { +describe('Patch rule request schema', () => { test('[id] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; expect(message.schema).toEqual(expected); }); test('[rule_id] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', }; expect(message.schema).toEqual(expected); }); test('[rule_id, description] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', }; @@ -62,16 +62,16 @@ describe('patch_rules_schema', () => { }); test('[id, description] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', }; @@ -79,16 +79,16 @@ describe('patch_rules_schema', () => { }); test('[id, risk_score] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', risk_score: 10, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', risk_score: 10, }; @@ -96,17 +96,17 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -115,18 +115,18 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', to: 'now', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -136,18 +136,18 @@ describe('patch_rules_schema', () => { }); test('[id, description, from, to] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', to: 'now', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -157,7 +157,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, name] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -165,11 +165,11 @@ describe('patch_rules_schema', () => { name: 'some-name', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -180,7 +180,7 @@ describe('patch_rules_schema', () => { }); test('[id, description, from, to, name] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -188,11 +188,11 @@ describe('patch_rules_schema', () => { name: 'some-name', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -203,7 +203,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, name, severity] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -212,11 +212,11 @@ describe('patch_rules_schema', () => { severity: 'low', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -228,7 +228,7 @@ describe('patch_rules_schema', () => { }); test('[id, description, from, to, name, severity] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -237,11 +237,11 @@ describe('patch_rules_schema', () => { severity: 'low', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -253,7 +253,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, name, severity, type] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -263,11 +263,11 @@ describe('patch_rules_schema', () => { type: 'query', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -280,7 +280,7 @@ describe('patch_rules_schema', () => { }); test('[id, description, from, to, name, severity, type] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -290,11 +290,11 @@ describe('patch_rules_schema', () => { type: 'query', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -307,7 +307,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, name, severity, type, interval] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -318,11 +318,11 @@ describe('patch_rules_schema', () => { type: 'query', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -336,7 +336,7 @@ describe('patch_rules_schema', () => { }); test('[id, description, from, to, name, severity, type, interval] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -347,11 +347,11 @@ describe('patch_rules_schema', () => { type: 'query', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -365,7 +365,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, query] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -378,11 +378,11 @@ describe('patch_rules_schema', () => { query: 'some query', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -398,7 +398,7 @@ describe('patch_rules_schema', () => { }); test('[id, description, from, to, index, name, severity, interval, type, query, language] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -411,11 +411,11 @@ describe('patch_rules_schema', () => { language: 'kuery', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -431,7 +431,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -439,11 +439,11 @@ describe('patch_rules_schema', () => { name: 'some-name', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -454,7 +454,7 @@ describe('patch_rules_schema', () => { }); test('[id, description, from, to, index, name, severity, type, filters] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -466,11 +466,11 @@ describe('patch_rules_schema', () => { filters: [], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -485,7 +485,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, index, name, severity, type, filters] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -497,11 +497,11 @@ describe('patch_rules_schema', () => { filters: [], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -516,7 +516,7 @@ describe('patch_rules_schema', () => { }); test('allows references to be sent as a valid value to patch with', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -531,11 +531,11 @@ describe('patch_rules_schema', () => { language: 'kuery', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', description: 'some description', from: 'now-5m', @@ -553,48 +553,48 @@ describe('patch_rules_schema', () => { }); test('does not default references to an array', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = patchRulesSchema.decode(payload); + 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 PatchRulesSchema).references).toEqual(undefined); + expect((message.schema as PatchRuleRequestBody).references).toEqual(undefined); }); test('does not default interval', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = patchRulesSchema.decode(payload); + 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 PatchRulesSchema).interval).toEqual(undefined); + expect((message.schema as PatchRuleRequestBody).interval).toEqual(undefined); }); test('does not default max_signals', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = patchRulesSchema.decode(payload); + 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 PatchRulesSchema).max_signals).toEqual(undefined); + expect((message.schema as PatchRuleRequestBody).max_signals).toEqual(undefined); }); test('references cannot be numbers', () => { - const payload: Omit & { references: number[] } = { + const payload: Omit & { references: number[] } = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', references: [5], }; - const decoded = patchRulesSchema.decode(payload); + 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"']); @@ -602,13 +602,13 @@ describe('patch_rules_schema', () => { }); test('indexes cannot be numbers', () => { - const payload: Omit & { index: number[] } = { + const payload: Omit & { index: number[] } = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', type: 'query', index: [5], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -619,16 +619,16 @@ describe('patch_rules_schema', () => { }); test('saved_id is not required when type is saved_query and will validate without it', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', type: 'saved_query', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', type: 'saved_query', }; @@ -642,7 +642,7 @@ describe('patch_rules_schema', () => { saved_id: 'some id', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -661,7 +661,7 @@ describe('patch_rules_schema', () => { filters: [], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -680,7 +680,7 @@ describe('patch_rules_schema', () => { language: 'kuery', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -699,7 +699,7 @@ describe('patch_rules_schema', () => { language: 'lucene', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -719,7 +719,7 @@ describe('patch_rules_schema', () => { language: 'something-made-up', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -735,7 +735,7 @@ describe('patch_rules_schema', () => { max_signals: -1, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -751,7 +751,7 @@ describe('patch_rules_schema', () => { max_signals: 0, }; - const decoded = patchRulesSchema.decode(payload); + 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"']); @@ -765,7 +765,7 @@ describe('patch_rules_schema', () => { max_signals: 1, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -778,16 +778,16 @@ describe('patch_rules_schema', () => { }); test('meta can be patched', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { ...getPatchRulesSchemaMock(), meta: { whateverYouWant: 'anything_at_all' }, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { ...getPatchRulesSchemaMock(), meta: { whateverYouWant: 'anything_at_all' }, }; @@ -795,12 +795,12 @@ describe('patch_rules_schema', () => { }); test('You cannot patch meta as a string', () => { - const payload: Omit & { meta: string } = { + const payload: Omit & { meta: string } = { ...getPatchRulesSchemaMock(), meta: 'should not work', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -810,12 +810,12 @@ describe('patch_rules_schema', () => { }); test('filters cannot be a string', () => { - const payload: Omit & { filters: string } = { + const payload: Omit & { filters: string } = { ...getPatchRulesSchemaMock(), filters: 'should not work', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -825,12 +825,12 @@ describe('patch_rules_schema', () => { }); test('name cannot be an empty string', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { ...getPatchRulesSchemaMock(), name: '', }; - const decoded = patchRulesSchema.decode(payload); + 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"']); @@ -838,12 +838,12 @@ describe('patch_rules_schema', () => { }); test('description cannot be an empty string', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { ...getPatchRulesSchemaMock(), description: '', }; - const decoded = patchRulesSchema.decode(payload); + 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"']); @@ -851,32 +851,32 @@ describe('patch_rules_schema', () => { }); test('threat is not defaulted to empty array on patch', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = patchRulesSchema.decode(payload); + 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 PatchRulesSchema).threat).toEqual(undefined); + expect((message.schema as PatchRuleRequestBody).threat).toEqual(undefined); }); test('threat is not defaulted to undefined on patch with empty array', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', threat: [], }; - const decoded = patchRulesSchema.decode(payload); + 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 PatchRulesSchema).threat).toEqual([]); + expect((message.schema as PatchRuleRequestBody).threat).toEqual([]); }); test('threat is valid when updated with all sub-objects', () => { - const threat: PatchRulesSchema['threat'] = [ + const threat: PatchRuleRequestBody['threat'] = [ { framework: 'fake', tactic: { @@ -893,12 +893,12 @@ describe('patch_rules_schema', () => { ], }, ]; - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', threat, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -906,7 +906,7 @@ describe('patch_rules_schema', () => { }); test('threat is invalid when updated with missing property framework', () => { - const threat: Omit = [ + const threat: Omit = [ { tactic: { id: 'fakeId', @@ -922,12 +922,12 @@ describe('patch_rules_schema', () => { ], }, ]; - const payload: Omit = { + const payload: Omit = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', threat, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -937,7 +937,7 @@ describe('patch_rules_schema', () => { }); test('threat is invalid when updated with missing tactic sub-object', () => { - const threat: Omit = [ + const threat: Omit = [ { framework: 'fake', technique: [ @@ -950,12 +950,12 @@ describe('patch_rules_schema', () => { }, ]; - const payload: Omit = { + const payload: Omit = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', threat, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -965,7 +965,7 @@ describe('patch_rules_schema', () => { }); test('threat is valid when updated with missing technique', () => { - const threat: Omit = [ + const threat: Omit = [ { framework: 'fake', tactic: { @@ -976,12 +976,12 @@ describe('patch_rules_schema', () => { }, ]; - const payload: Omit = { + const payload: Omit = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', threat, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -989,17 +989,17 @@ describe('patch_rules_schema', () => { }); test('validates with timeline_id and timeline_title', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { ...getPatchRulesSchemaMock(), timeline_id: 'some-id', timeline_title: 'some-title', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { ...getPatchRulesSchemaMock(), timeline_id: 'some-id', timeline_title: 'some-title', @@ -1008,12 +1008,12 @@ describe('patch_rules_schema', () => { }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { - const payload: Omit & { severity: string } = { + const payload: Omit & { severity: string } = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', severity: 'junk', }; - const decoded = patchRulesSchema.decode(payload); + 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"']); @@ -1022,7 +1022,7 @@ describe('patch_rules_schema', () => { describe('note', () => { test('[rule_id, description, from, to, index, name, severity, interval, type, note] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1035,11 +1035,11 @@ describe('patch_rules_schema', () => { note: '# some documentation markdown', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1055,16 +1055,16 @@ describe('patch_rules_schema', () => { }); test('note can be patched', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', note: '# new documentation markdown', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', note: '# new documentation markdown', }; @@ -1072,14 +1072,14 @@ describe('patch_rules_schema', () => { }); test('You cannot patch note as an object', () => { - const payload: Omit & { note: object } = { + const payload: Omit & { note: object } = { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', note: { someProperty: 'something else here', }, }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1090,12 +1090,12 @@ describe('patch_rules_schema', () => { }); test('You cannot send in an array of actions that are missing "group"', () => { - const payload: Omit = { + const payload: Omit = { ...getPatchRulesSchemaMock(), actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1105,12 +1105,12 @@ describe('patch_rules_schema', () => { }); test('You cannot send in an array of actions that are missing "id"', () => { - const payload: Omit = { + const payload: Omit = { ...getPatchRulesSchemaMock(), actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1120,12 +1120,12 @@ describe('patch_rules_schema', () => { }); test('You cannot send in an array of actions that are missing "params"', () => { - const payload: Omit = { + const payload: Omit = { ...getPatchRulesSchemaMock(), actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1135,7 +1135,7 @@ describe('patch_rules_schema', () => { }); test('You cannot send in an array of actions that are including "actionTypeId"', () => { - const payload: Omit = { + const payload: Omit = { ...getPatchRulesSchemaMock(), actions: [ { @@ -1147,7 +1147,7 @@ describe('patch_rules_schema', () => { ], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1158,7 +1158,7 @@ describe('patch_rules_schema', () => { describe('exception_list', () => { test('[rule_id, description, from, to, index, name, severity, interval, type, filters, note, and exceptions_list] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1173,11 +1173,11 @@ describe('patch_rules_schema', () => { exceptions_list: getListArrayMock(), }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1208,7 +1208,7 @@ describe('patch_rules_schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1224,11 +1224,11 @@ describe('patch_rules_schema', () => { exceptions_list: [], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1263,7 +1263,7 @@ describe('patch_rules_schema', () => { exceptions_list: [{ id: 'uuid_here', namespace_type: 'not a namespace type' }], }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1275,7 +1275,7 @@ describe('patch_rules_schema', () => { }); 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', () => { - const payload: PatchRulesSchema = { + const payload: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1290,11 +1290,11 @@ describe('patch_rules_schema', () => { note: '# some markdown', }; - const decoded = patchRulesSchema.decode(payload); + const decoded = PatchRuleRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRulesSchema = { + const expected: PatchRuleRequestBody = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.ts new file mode 100644 index 0000000000000..27a1f14687aa4 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema.ts @@ -0,0 +1,18 @@ +/* + * 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 { RulePatchProps, ThresholdRulePatchProps } from '../../../../../rule_schema'; + +/** + * 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 type ThresholdPatchRuleRequestBody = ThresholdRulePatchProps; +export const ThresholdPatchRuleRequestBody = ThresholdRulePatchProps; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema_validation.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema_validation.test.ts new file mode 100644 index 0000000000000..c00e3c38fb91b --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema_validation.test.ts @@ -0,0 +1,116 @@ +/* + * 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 { PatchRuleRequestBody, ThresholdPatchRuleRequestBody } from './request_schema'; +import { getPatchRulesSchemaMock, getPatchThresholdRulesSchemaMock } from './request_schema.mock'; +import { validatePatchRuleRequestBody } from './request_schema_validation'; + +describe('Patch rule request schema, additional validation', () => { + describe('validatePatchRuleRequestBody', () => { + test('You cannot omit timeline_title when timeline_id is present', () => { + const schema: PatchRuleRequestBody = { + ...getPatchRulesSchemaMock(), + timeline_id: '123', + }; + delete schema.timeline_title; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['when "timeline_id" exists, "timeline_title" must also exist']); + }); + + test('You cannot have empty string for timeline_title when timeline_id is present', () => { + const schema: PatchRuleRequestBody = { + ...getPatchRulesSchemaMock(), + timeline_id: '123', + timeline_title: '', + }; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['"timeline_title" cannot be an empty string']); + }); + + test('You cannot have timeline_title with an empty timeline_id', () => { + const schema: PatchRuleRequestBody = { + ...getPatchRulesSchemaMock(), + timeline_id: '', + timeline_title: 'some-title', + }; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['"timeline_id" cannot be an empty string']); + }); + + test('You cannot have timeline_title without timeline_id', () => { + const schema: PatchRuleRequestBody = { + ...getPatchRulesSchemaMock(), + timeline_title: 'some-title', + }; + delete schema.timeline_id; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['when "timeline_title" exists, "timeline_id" must also exist']); + }); + + test('You cannot have both an id and a rule_id', () => { + const schema: PatchRuleRequestBody = { + ...getPatchRulesSchemaMock(), + id: 'some-id', + rule_id: 'some-rule-id', + }; + const errors = validatePatchRuleRequestBody(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: PatchRuleRequestBody = { + ...getPatchRulesSchemaMock(), + }; + delete schema.id; + delete schema.rule_id; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['either "id" or "rule_id" must be set']); + }); + + test('threshold.value is required and has to be bigger than 0 when type is threshold and validates with it', () => { + const schema: ThresholdPatchRuleRequestBody = { + ...getPatchThresholdRulesSchemaMock(), + threshold: { + field: '', + value: -1, + }, + }; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['"threshold.value" has to be bigger than 0']); + }); + + test('threshold.field should contain 3 items or less', () => { + const schema: ThresholdPatchRuleRequestBody = { + ...getPatchThresholdRulesSchemaMock(), + threshold: { + field: ['field-1', 'field-2', 'field-3', 'field-4'], + value: 1, + }, + }; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['Number of fields must be 3 or less']); + }); + + test('threshold.cardinality[0].field should not be in threshold.field', () => { + const schema: ThresholdPatchRuleRequestBody = { + ...getPatchThresholdRulesSchemaMock(), + threshold: { + field: ['field-1', 'field-2', 'field-3'], + value: 1, + cardinality: [ + { + field: 'field-1', + value: 2, + }, + ], + }, + }; + const errors = validatePatchRuleRequestBody(schema); + expect(errors).toEqual(['Cardinality of a field that is being aggregated on is always 1']); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_type_dependents.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema_validation.ts similarity index 80% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_type_dependents.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema_validation.ts index 263f28e28ac30..72d10bf5e58de 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_type_dependents.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/patch_rule/request_schema_validation.ts @@ -5,9 +5,31 @@ * 2.0. */ -import type { PatchRulesSchema } from './patch_rules_schema'; +import type { PatchRuleRequestBody } from './request_schema'; -export const validateTimelineId = (rule: PatchRulesSchema): string[] => { +/** + * Additional validation that is implemented outside of the schema itself. + */ +export const validatePatchRuleRequestBody = (rule: PatchRuleRequestBody): string[] => { + return [ + ...validateId(rule), + ...validateTimelineId(rule), + ...validateTimelineTitle(rule), + ...validateThreshold(rule), + ]; +}; + +const validateId = (rule: PatchRuleRequestBody): 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) { + return ['either "id" or "rule_id" must be set']; + } else { + return []; + } +}; + +const validateTimelineId = (rule: PatchRuleRequestBody): string[] => { if (rule.timeline_id != null) { if (rule.timeline_title == null) { return ['when "timeline_id" exists, "timeline_title" must also exist']; @@ -20,7 +42,7 @@ export const validateTimelineId = (rule: PatchRulesSchema): string[] => { return []; }; -export const validateTimelineTitle = (rule: PatchRulesSchema): string[] => { +const validateTimelineTitle = (rule: PatchRuleRequestBody): string[] => { if (rule.timeline_title != null) { if (rule.timeline_id == null) { return ['when "timeline_title" exists, "timeline_id" must also exist']; @@ -33,17 +55,7 @@ export const validateTimelineTitle = (rule: PatchRulesSchema): string[] => { return []; }; -export const validateId = (rule: PatchRulesSchema): 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) { - return ['either "id" or "rule_id" must be set']; - } else { - return []; - } -}; - -export const validateThreshold = (rule: PatchRulesSchema): string[] => { +const validateThreshold = (rule: PatchRuleRequestBody): string[] => { const errors: string[] = []; if (rule.type === 'threshold') { if (!rule.threshold) { @@ -65,12 +77,3 @@ export const validateThreshold = (rule: PatchRulesSchema): string[] => { } return errors; }; - -export const patchRuleValidateTypeDependents = (rule: PatchRulesSchema): string[] => { - return [ - ...validateId(rule), - ...validateTimelineId(rule), - ...validateTimelineTitle(rule), - ...validateThreshold(rule), - ]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids.test.ts similarity index 72% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids.test.ts index faccffb1e6864..d5ba9b37ae65a 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids.test.ts @@ -5,17 +5,16 @@ * 2.0. */ -import type { QueryRulesSchema } from './query_rules_schema'; -import { queryRulesSchema } from './query_rules_schema'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; 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_rules_schema', () => { +describe('Query rule by IDs schema', () => { test('empty objects do validate', () => { - const payload: Partial = {}; + const payload: Partial = {}; - const decoded = queryRulesSchema.decode(payload); + const decoded = QueryRuleByIds.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids.ts similarity index 56% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids.ts index 704c2307181b9..d52d8c66125e6 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids.ts @@ -6,15 +6,12 @@ */ import * as t from 'io-ts'; +import { RuleObjectId, RuleSignatureId } from '../../../../../rule_schema'; -import { rule_id, id } from '../common/schemas'; - -export const queryRulesSchema = t.exact( +export type QueryRuleByIds = t.TypeOf; +export const QueryRuleByIds = t.exact( t.partial({ - rule_id, - id, + rule_id: RuleSignatureId, + id: RuleObjectId, }) ); - -export type QueryRulesSchema = t.TypeOf; -export type QueryRulesSchemaDecoded = QueryRulesSchema; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_type_dependents.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids_validation.test.ts similarity index 61% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_type_dependents.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids_validation.test.ts index 060fd189a40a9..1d0981df5f411 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_type_dependents.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids_validation.test.ts @@ -5,22 +5,22 @@ * 2.0. */ -import type { QueryRulesSchema } from './query_rules_schema'; -import { queryRuleValidateTypeDependents } from './query_rules_type_dependents'; +import type { QueryRuleByIds } from './query_rule_by_ids'; +import { validateQueryRuleByIds } from './query_rule_by_ids_validation'; -describe('query_rules_type_dependents', () => { +describe('Query rule by IDs schema, additional validation', () => { test('You cannot have both an id and a rule_id', () => { - const schema: QueryRulesSchema = { + const schema: QueryRuleByIds = { id: 'some-id', rule_id: 'some-rule-id', }; - const errors = queryRuleValidateTypeDependents(schema); + 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: QueryRulesSchema = {}; - const errors = queryRuleValidateTypeDependents(schema); + const schema: QueryRuleByIds = {}; + const errors = validateQueryRuleByIds(schema); expect(errors).toEqual(['either "id" or "rule_id" must be set']); }); }); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_type_dependents.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids_validation.ts similarity index 66% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_type_dependents.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids_validation.ts index a646d0e97f96a..4f0a7eedc71dd 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_type_dependents.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/read_rule/query_rule_by_ids_validation.ts @@ -5,9 +5,16 @@ * 2.0. */ -import type { QueryRulesSchema } from './query_rules_schema'; +import type { QueryRuleByIds } from './query_rule_by_ids'; -export const validateId = (rule: QueryRulesSchema): string[] => { +/** + * Additional validation that is implemented outside of the schema itself. + */ +export const validateQueryRuleByIds = (schema: QueryRuleByIds): string[] => { + return [...validateId(schema)]; +}; + +const validateId = (rule: QueryRuleByIds): 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) { @@ -16,7 +23,3 @@ export const validateId = (rule: QueryRulesSchema): string[] => { return []; } }; - -export const queryRuleValidateTypeDependents = (schema: QueryRulesSchema): string[] => { - return [...validateId(schema)]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_type_dependents.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/update_rule/request_schema_validation.test.ts similarity index 68% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_type_dependents.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/update_rule/request_schema_validation.test.ts index e2f5024418005..f6a8d0bb39340 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_type_dependents.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/update_rule/request_schema_validation.test.ts @@ -5,68 +5,68 @@ * 2.0. */ -import { getUpdateRulesSchemaMock } from './rule_schemas.mock'; -import type { UpdateRulesSchema } from './rule_schemas'; -import { updateRuleValidateTypeDependents } from './update_rules_type_dependents'; +import type { RuleUpdateProps } from '../../../../../rule_schema'; +import { getUpdateRulesSchemaMock } from '../../../../../rule_schema/mocks'; +import { validateUpdateRuleProps } from './request_schema_validation'; -describe('update_rules_type_dependents', () => { +describe('Update rule request schema, additional validation', () => { test('You cannot omit timeline_title when timeline_id is present', () => { - const schema: UpdateRulesSchema = { + const schema: RuleUpdateProps = { ...getUpdateRulesSchemaMock(), timeline_id: '123', }; delete schema.timeline_title; - const errors = updateRuleValidateTypeDependents(schema); + const errors = validateUpdateRuleProps(schema); expect(errors).toEqual(['when "timeline_id" exists, "timeline_title" must also exist']); }); test('You cannot have empty string for timeline_title when timeline_id is present', () => { - const schema: UpdateRulesSchema = { + const schema: RuleUpdateProps = { ...getUpdateRulesSchemaMock(), timeline_id: '123', timeline_title: '', }; - const errors = updateRuleValidateTypeDependents(schema); + const errors = validateUpdateRuleProps(schema); expect(errors).toEqual(['"timeline_title" cannot be an empty string']); }); test('You cannot have timeline_title with an empty timeline_id', () => { - const schema: UpdateRulesSchema = { + const schema: RuleUpdateProps = { ...getUpdateRulesSchemaMock(), timeline_id: '', timeline_title: 'some-title', }; - const errors = updateRuleValidateTypeDependents(schema); + const errors = validateUpdateRuleProps(schema); expect(errors).toEqual(['"timeline_id" cannot be an empty string']); }); test('You cannot have timeline_title without timeline_id', () => { - const schema: UpdateRulesSchema = { + const schema: RuleUpdateProps = { ...getUpdateRulesSchemaMock(), timeline_title: 'some-title', }; delete schema.timeline_id; - const errors = updateRuleValidateTypeDependents(schema); + const errors = validateUpdateRuleProps(schema); expect(errors).toEqual(['when "timeline_title" exists, "timeline_id" must also exist']); }); test('You cannot have both an id and a rule_id', () => { - const schema: UpdateRulesSchema = { + const schema: RuleUpdateProps = { ...getUpdateRulesSchemaMock(), id: 'some-id', rule_id: 'some-rule-id', }; - const errors = updateRuleValidateTypeDependents(schema); + const errors = validateUpdateRuleProps(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: UpdateRulesSchema = { + const schema: RuleUpdateProps = { ...getUpdateRulesSchemaMock(), }; delete schema.id; delete schema.rule_id; - const errors = updateRuleValidateTypeDependents(schema); + const errors = validateUpdateRuleProps(schema); expect(errors).toEqual(['either "id" or "rule_id" must be set']); }); }); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/update_rule/request_schema_validation.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/update_rule/request_schema_validation.ts new file mode 100644 index 0000000000000..09d1e1e7b0a99 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/crud/update_rule/request_schema_validation.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 type { RuleUpdateProps } from '../../../../../rule_schema'; + +/** + * Additional validation that is implemented outside of the schema itself. + */ +export const validateUpdateRuleProps = (props: RuleUpdateProps): string[] => { + return [ + ...validateId(props), + ...validateTimelineId(props), + ...validateTimelineTitle(props), + ...validateThreshold(props), + ]; +}; + +const validateId = (props: RuleUpdateProps): string[] => { + if (props.id != null && props.rule_id != null) { + return ['both "id" and "rule_id" cannot exist, choose one or the other']; + } else if (props.id == null && props.rule_id == null) { + return ['either "id" or "rule_id" must be set']; + } else { + return []; + } +}; + +const validateTimelineId = (props: RuleUpdateProps): string[] => { + if (props.timeline_id != null) { + if (props.timeline_title == null) { + return ['when "timeline_id" exists, "timeline_title" must also exist']; + } else if (props.timeline_id === '') { + return ['"timeline_id" cannot be an empty string']; + } else { + return []; + } + } + return []; +}; + +const validateTimelineTitle = (props: RuleUpdateProps): string[] => { + if (props.timeline_title != null) { + if (props.timeline_id == null) { + return ['when "timeline_title" exists, "timeline_id" must also exist']; + } else if (props.timeline_title === '') { + return ['"timeline_title" cannot be an empty string']; + } else { + return []; + } + } + return []; +}; + +const validateThreshold = (props: RuleUpdateProps): string[] => { + const errors: string[] = []; + if (props.type === 'threshold') { + if (!props.threshold) { + errors.push('when "type" is "threshold", "threshold" is required'); + } else { + if ( + props.threshold.cardinality?.length && + props.threshold.field.includes(props.threshold.cardinality[0].field) + ) { + errors.push('Cardinality of a field that is being aggregated on is always 1'); + } + if (Array.isArray(props.threshold.field) && props.threshold.field.length > 3) { + errors.push('Number of fields must be 3 or less'); + } + } + } + return errors; +}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/export_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/export_rules/request_schema.test.ts similarity index 72% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/export_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/export_rules/request_schema.test.ts index d2b29a5152e96..0e0ec3cbaca3b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/export_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/export_rules/request_schema.test.ts @@ -5,22 +5,19 @@ * 2.0. */ -import type { - ExportRulesSchema, - ExportRulesQuerySchema, - ExportRulesQuerySchemaDecoded, -} from './export_rules_schema'; -import { exportRulesQuerySchema, exportRulesSchema } from './export_rules_schema'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; 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 { ExportRulesRequestBody, ExportRulesRequestQuery } from './request_schema'; +import type { ExportRulesRequestQueryDecoded } from './request_schema'; -describe('create rules schema', () => { - describe('exportRulesSchema', () => { +describe('Export rules request schema', () => { + describe('ExportRulesRequestBody', () => { test('null value or absent values validate', () => { - const payload: Partial = null; + const payload: Partial = null; - const decoded = exportRulesSchema.decode(payload); + const decoded = ExportRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -30,7 +27,7 @@ describe('create rules schema', () => { test('empty object does not validate', () => { const payload = {}; - const decoded = exportRulesSchema.decode(payload); + const decoded = ExportRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -41,9 +38,9 @@ describe('create rules schema', () => { }); test('empty object array does validate', () => { - const payload: ExportRulesSchema = { objects: [] }; + const payload: ExportRulesRequestBody = { objects: [] }; - const decoded = exportRulesSchema.decode(payload); + const decoded = ExportRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -51,9 +48,9 @@ describe('create rules schema', () => { }); test('array with rule_id validates', () => { - const payload: ExportRulesSchema = { objects: [{ rule_id: 'test-1' }] }; + const payload: ExportRulesRequestBody = { objects: [{ rule_id: 'test-1' }] }; - const decoded = exportRulesSchema.decode(payload); + const decoded = ExportRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -61,11 +58,11 @@ describe('create rules schema', () => { }); test('array with id does not validate as we do not allow that on purpose since we export rule_id', () => { - const payload: Omit & { objects: [{ id: string }] } = { + const payload: Omit & { objects: [{ id: string }] } = { objects: [{ id: '4a7ff83d-3055-4bb2-ba68-587b9c6c15a4' }], }; - const decoded = exportRulesSchema.decode(payload); + const decoded = ExportRulesRequestBody.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -76,15 +73,15 @@ describe('create rules schema', () => { }); }); - describe('exportRulesQuerySchema', () => { + describe('ExportRulesRequestQuery', () => { test('default value for file_name is export.ndjson and default for exclude_export_details is false', () => { - const payload: Partial = {}; + const payload: Partial = {}; - const decoded = exportRulesQuerySchema.decode(payload); + const decoded = ExportRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: ExportRulesQuerySchemaDecoded = { + const expected: ExportRulesRequestQueryDecoded = { file_name: 'export.ndjson', exclude_export_details: false, }; @@ -93,15 +90,15 @@ describe('create rules schema', () => { }); test('file_name validates', () => { - const payload: ExportRulesQuerySchema = { + const payload: ExportRulesRequestQuery = { file_name: 'test.ndjson', }; - const decoded = exportRulesQuerySchema.decode(payload); + const decoded = ExportRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: ExportRulesQuerySchemaDecoded = { + const expected: ExportRulesRequestQueryDecoded = { file_name: 'test.ndjson', exclude_export_details: false, }; @@ -110,11 +107,11 @@ describe('create rules schema', () => { }); test('file_name does not validate with a number', () => { - const payload: Omit & { file_name: number } = { + const payload: Omit & { file_name: number } = { file_name: 10, }; - const decoded = exportRulesQuerySchema.decode(payload); + const decoded = ExportRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -124,15 +121,15 @@ describe('create rules schema', () => { }); test('exclude_export_details validates with a boolean true', () => { - const payload: ExportRulesQuerySchema = { + const payload: ExportRulesRequestQuery = { exclude_export_details: true, }; - const decoded = exportRulesQuerySchema.decode(payload); + const decoded = ExportRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - const expected: ExportRulesQuerySchemaDecoded = { + const expected: ExportRulesRequestQueryDecoded = { exclude_export_details: true, file_name: 'export.ndjson', }; @@ -140,13 +137,13 @@ describe('create rules schema', () => { }); test('exclude_export_details does not validate with a string', () => { - const payload: Omit & { + const payload: Omit & { exclude_export_details: string; } = { exclude_export_details: 'invalid string', }; - const decoded = exportRulesQuerySchema.decode(payload); + const decoded = ExportRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/export_rules/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/export_rules/request_schema.ts new file mode 100644 index 0000000000000..682e69e55d5a4 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/export_rules/request_schema.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 * as t from 'io-ts'; +import { DefaultExportFileName } from '@kbn/securitysolution-io-ts-alerting-types'; +import { DefaultStringBooleanFalse } from '@kbn/securitysolution-io-ts-types'; + +import type { FileName, ExcludeExportDetails } from '../../../../schemas/common/schemas'; +import { RuleSignatureId } from '../../../../rule_schema'; + +const ObjectsWithRuleId = t.array(t.exact(t.type({ rule_id: RuleSignatureId }))); + +/** + * Request body parameters of the API route. + */ +export type ExportRulesRequestBody = t.TypeOf; +export const ExportRulesRequestBody = t.union([ + t.exact(t.type({ objects: ObjectsWithRuleId })), + t.null, +]); + +/** + * Query string parameters of the API route. + */ +export type ExportRulesRequestQuery = t.TypeOf; +export const ExportRulesRequestQuery = t.exact( + t.partial({ file_name: DefaultExportFileName, exclude_export_details: DefaultStringBooleanFalse }) +); + +export type ExportRulesRequestQueryDecoded = Omit< + ExportRulesRequestQuery, + 'file_name' | 'exclude_export_details' +> & { + file_name: FileName; + exclude_export_details: ExcludeExportDetails; +}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema.test.ts similarity index 63% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema.test.ts index 41e765c8c268b..67a3d045d746d 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema.test.ts @@ -5,17 +5,17 @@ * 2.0. */ -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; -import type { FindRulesSchema } from './find_rules_schema'; -import { findRulesSchema } from './find_rules_schema'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { FindRulesRequestQuery } from './request_schema'; -describe('find_rules_schema', () => { +describe('Find rules request schema', () => { test('empty objects do validate', () => { - const payload: FindRulesSchema = {}; + const payload: FindRulesRequestQuery = {}; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -26,7 +26,7 @@ describe('find_rules_schema', () => { }); test('all values validate', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { per_page: 5, page: 1, sort_field: 'some field', @@ -35,7 +35,7 @@ describe('find_rules_schema', () => { sort_order: 'asc', }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -43,9 +43,11 @@ describe('find_rules_schema', () => { }); test('made up parameters do not validate', () => { - const payload: Partial & { madeUp: string } = { madeUp: 'invalid value' }; + const payload: Partial & { madeUp: string } = { + madeUp: 'invalid value', + }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); @@ -53,71 +55,71 @@ describe('find_rules_schema', () => { }); test('per_page validates', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { per_page: 5, }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).per_page).toEqual(payload.per_page); + expect((message.schema as FindRulesRequestQuery).per_page).toEqual(payload.per_page); }); test('page validates', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { page: 5, }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).page).toEqual(payload.page); + expect((message.schema as FindRulesRequestQuery).page).toEqual(payload.page); }); test('sort_field validates', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { sort_field: 'value', }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).sort_field).toEqual('value'); + expect((message.schema as FindRulesRequestQuery).sort_field).toEqual('value'); }); test('fields validates with a string', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { fields: ['some value'], }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).fields).toEqual(payload.fields); + expect((message.schema as FindRulesRequestQuery).fields).toEqual(payload.fields); }); test('fields validates with multiple strings', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { fields: ['some value 1', 'some value 2'], }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).fields).toEqual(payload.fields); + expect((message.schema as FindRulesRequestQuery).fields).toEqual(payload.fields); }); test('fields does not validate with a number', () => { - const payload: Omit & { fields: number } = { + const payload: Omit & { fields: number } = { fields: 5, }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "fields"']); @@ -125,43 +127,43 @@ describe('find_rules_schema', () => { }); test('per_page has a default of 20', () => { - const payload: FindRulesSchema = {}; + const payload: FindRulesRequestQuery = {}; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).per_page).toEqual(20); + expect((message.schema as FindRulesRequestQuery).per_page).toEqual(20); }); test('page has a default of 1', () => { - const payload: FindRulesSchema = {}; + const payload: FindRulesRequestQuery = {}; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).page).toEqual(1); + expect((message.schema as FindRulesRequestQuery).page).toEqual(1); }); test('filter works with a string', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { filter: 'some value 1', }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).filter).toEqual(payload.filter); + expect((message.schema as FindRulesRequestQuery).filter).toEqual(payload.filter); }); test('filter does not work with a number', () => { - const payload: Omit & { filter: number } = { + const payload: Omit & { filter: number } = { filter: 5, }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "filter"']); @@ -169,26 +171,26 @@ describe('find_rules_schema', () => { }); test('sort_order validates with desc and sort_field', () => { - const payload: FindRulesSchema = { + const payload: FindRulesRequestQuery = { sort_order: 'desc', sort_field: 'some field', }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as FindRulesSchema).sort_order).toEqual(payload.sort_order); - expect((message.schema as FindRulesSchema).sort_field).toEqual(payload.sort_field); + expect((message.schema as FindRulesRequestQuery).sort_order).toEqual(payload.sort_order); + expect((message.schema as FindRulesRequestQuery).sort_field).toEqual(payload.sort_field); }); test('sort_order does not validate with a string other than asc and desc', () => { - const payload: Omit & { sort_order: string } = { + const payload: Omit & { sort_order: string } = { sort_order: 'some other string', sort_field: 'some field', }; - const decoded = findRulesSchema.decode(payload); + const decoded = FindRulesRequestQuery.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema.ts similarity index 59% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema.ts index 39f0105a2a88f..9b321d443b2de 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema.ts @@ -6,12 +6,15 @@ */ import * as t from 'io-ts'; - import { DefaultPerPage, DefaultPage } from '@kbn/securitysolution-io-ts-alerting-types'; -import type { PerPage, Page } from '../common'; -import { queryFilter, fields, SortField, SortOrder } from '../common'; +import type { PerPage, Page } from '../../../../schemas/common'; +import { queryFilter, fields, SortField, SortOrder } from '../../../../schemas/common'; -export const findRulesSchema = t.exact( +/** + * Query string parameters of the API route. + */ +export type FindRulesRequestQuery = t.TypeOf; +export const FindRulesRequestQuery = t.exact( t.partial({ fields, filter: queryFilter, @@ -22,8 +25,7 @@ export const findRulesSchema = t.exact( }) ); -export type FindRulesSchema = t.TypeOf; -export type FindRulesSchemaDecoded = Omit & { +export type FindRulesRequestQueryDecoded = Omit & { page: Page; per_page: PerPage; }; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema_validation.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema_validation.test.ts new file mode 100644 index 0000000000000..862bf7cc1a350 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema_validation.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { FindRulesRequestQuery } from './request_schema'; +import { validateFindRulesRequestQuery } from './request_schema_validation'; + +describe('Find rules request schema, additional validation', () => { + describe('validateFindRulesRequestQuery', () => { + test('You can have an empty sort_field and empty sort_order', () => { + const schema: FindRulesRequestQuery = {}; + const errors = validateFindRulesRequestQuery(schema); + expect(errors).toEqual([]); + }); + + test('You can have both a sort_field and and a sort_order', () => { + const schema: FindRulesRequestQuery = { + sort_field: 'some field', + sort_order: 'asc', + }; + const errors = validateFindRulesRequestQuery(schema); + expect(errors).toEqual([]); + }); + + test('You cannot have sort_field without sort_order', () => { + const schema: FindRulesRequestQuery = { + sort_field: 'some field', + }; + const errors = validateFindRulesRequestQuery(schema); + expect(errors).toEqual([ + 'when "sort_order" and "sort_field" must exist together or not at all', + ]); + }); + + test('You cannot have sort_order without sort_field', () => { + const schema: FindRulesRequestQuery = { + sort_order: 'asc', + }; + const errors = validateFindRulesRequestQuery(schema); + expect(errors).toEqual([ + 'when "sort_order" and "sort_field" must exist together or not at all', + ]); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema_validation.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema_validation.ts new file mode 100644 index 0000000000000..a8ceb09dea5b4 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/find_rules/request_schema_validation.ts @@ -0,0 +1,27 @@ +/* + * 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 { FindRulesRequestQuery } from './request_schema'; + +/** + * Additional validation that is implemented outside of the schema itself. + */ +export const validateFindRulesRequestQuery = (query: FindRulesRequestQuery): string[] => { + return [...validateSortOrder(query)]; +}; + +const validateSortOrder = (query: FindRulesRequestQuery): string[] => { + if (query.sort_order != null || query.sort_field != null) { + if (query.sort_order == null || query.sort_field == null) { + return ['when "sort_order" and "sort_field" must exist together or not at all']; + } else { + return []; + } + } else { + return []; + } +}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/request_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/request_schema.test.ts new file mode 100644 index 0000000000000..bd63dd7472aaf --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/request_schema.test.ts @@ -0,0 +1,52 @@ +/* + * 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 { ImportRulesRequestBody } from './request_schema'; + +describe('Import rules schema', () => { + describe('ImportRulesRequestBody', () => { + test('does not validate with an empty object', () => { + const payload = {}; + + const decoded = ImportRulesRequestBody.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "file"', + ]); + expect(message.schema).toEqual({}); + }); + + test('does not validate with a made string', () => { + const payload: Omit & { madeUpKey: string } = { + madeUpKey: 'madeupstring', + }; + + const decoded = ImportRulesRequestBody.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "file"', + ]); + expect(message.schema).toEqual({}); + }); + + test('does validate with a file object', () => { + const payload: ImportRulesRequestBody = { file: {} }; + + const decoded = ImportRulesRequestBody.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rule_by_id_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/request_schema.ts similarity index 56% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rule_by_id_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/request_schema.ts index 44b9692e7977f..8f64df3ea71b1 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rule_by_id_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/request_schema.ts @@ -7,13 +7,12 @@ import * as t from 'io-ts'; -import { id } from '../common/schemas'; - -export const queryRuleByIdSchema = t.exact( +/** + * Request body parameters of the API route. + */ +export type ImportRulesRequestBody = t.TypeOf; +export const ImportRulesRequestBody = t.exact( t.type({ - id, + file: t.object, }) ); - -export type QueryRuleByIdSchema = t.TypeOf; -export type QueryRuleByIdSchemaDecoded = QueryRuleByIdSchema; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/import_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts similarity index 82% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/import_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts index db1fc33e9d44e..2f11e1a9c120f 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/import_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts @@ -8,15 +8,15 @@ import { pipe } from 'fp-ts/lib/pipeable'; import type { Either } from 'fp-ts/lib/Either'; import { left } from 'fp-ts/lib/Either'; -import type { ImportRulesSchema } from './import_rules_schema'; -import { importRulesSchema } from './import_rules_schema'; -import type { ErrorSchema } from './error_schema'; import type { Errors } from 'io-ts'; + import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import type { ErrorSchema } from '../../../../schemas/response/error_schema'; +import { ImportRulesResponse } from './response_schema'; -describe('import_rules_schema', () => { +describe('Import rules response schema', () => { test('it should validate an empty import response with no errors', () => { - const payload: ImportRulesSchema = { + const payload: ImportRulesResponse = { success: true, success_count: 0, rules_count: 0, @@ -25,7 +25,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -34,7 +34,7 @@ describe('import_rules_schema', () => { }); test('it should validate an empty import response with a single error', () => { - const payload: ImportRulesSchema = { + const payload: ImportRulesResponse = { success: false, success_count: 0, rules_count: 0, @@ -43,7 +43,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -52,7 +52,7 @@ describe('import_rules_schema', () => { }); test('it should validate an empty import response with a single exceptions error', () => { - const payload: ImportRulesSchema = { + const payload: ImportRulesResponse = { success: false, success_count: 0, rules_count: 0, @@ -61,7 +61,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -70,7 +70,7 @@ describe('import_rules_schema', () => { }); test('it should validate an empty import response with two errors', () => { - const payload: ImportRulesSchema = { + const payload: ImportRulesResponse = { success: false, success_count: 0, rules_count: 0, @@ -82,7 +82,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -91,7 +91,7 @@ describe('import_rules_schema', () => { }); test('it should validate an empty import response with two exception errors', () => { - const payload: ImportRulesSchema = { + const payload: ImportRulesResponse = { success: false, success_count: 0, rules_count: 0, @@ -103,7 +103,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -112,7 +112,7 @@ describe('import_rules_schema', () => { }); test('it should NOT validate a success_count that is a negative number', () => { - const payload: ImportRulesSchema = { + const payload: ImportRulesResponse = { success: false, success_count: -1, rules_count: 0, @@ -121,7 +121,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -132,7 +132,7 @@ describe('import_rules_schema', () => { }); test('it should NOT validate a exceptions_success_count that is a negative number', () => { - const payload: ImportRulesSchema = { + const payload: ImportRulesResponse = { success: false, success_count: 0, rules_count: 0, @@ -141,7 +141,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: -1, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -170,7 +170,7 @@ describe('import_rules_schema', () => { >; } >; - const payload: Omit & { success: string } = { + const payload: Omit & { success: string } = { success: 'hello', success_count: 0, rules_count: 0, @@ -179,7 +179,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded as UnsafeCastForTest); const message = pipe(checked, foldLeftRight); @@ -207,17 +207,18 @@ describe('import_rules_schema', () => { >; } >; - const payload: Omit & { exceptions_success: string } = - { - success: true, - success_count: 0, - rules_count: 0, - errors: [], - exceptions_errors: [], - exceptions_success: 'hello', - exceptions_success_count: 0, - }; - const decoded = importRulesSchema.decode(payload); + const payload: Omit & { + exceptions_success: string; + } = { + success: true, + success_count: 0, + rules_count: 0, + errors: [], + exceptions_errors: [], + exceptions_success: 'hello', + exceptions_success_count: 0, + }; + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded as UnsafeCastForTest); const message = pipe(checked, foldLeftRight); @@ -228,7 +229,7 @@ describe('import_rules_schema', () => { }); test('it should NOT validate a success an extra invalid field', () => { - const payload: ImportRulesSchema & { invalid_field: string } = { + const payload: ImportRulesResponse & { invalid_field: string } = { success: true, success_count: 0, rules_count: 0, @@ -238,7 +239,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -248,7 +249,7 @@ describe('import_rules_schema', () => { test('it should NOT validate an extra field in the second position of the errors array', () => { type InvalidError = ErrorSchema & { invalid_data?: string }; - const payload: Omit & { + const payload: Omit & { errors: InvalidError[]; } = { success: true, @@ -262,7 +263,7 @@ describe('import_rules_schema', () => { exceptions_success: true, exceptions_success_count: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = ImportRulesResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/import_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts similarity index 69% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/import_rules_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts index d577b2135d58d..77ccd0812c2c9 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/import_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts @@ -5,22 +5,19 @@ * 2.0. */ -import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; import * as t from 'io-ts'; +import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; +import { errorSchema } from '../../../../schemas/response/error_schema'; -import { success, success_count } from '../common/schemas'; -import { errorSchema } from './error_schema'; - -export const importRulesSchema = t.exact( +export type ImportRulesResponse = t.TypeOf; +export const ImportRulesResponse = t.exact( t.type({ exceptions_success: t.boolean, exceptions_success_count: PositiveInteger, exceptions_errors: t.array(errorSchema), rules_count: PositiveInteger, - success, - success_count, + success: t.boolean, + success_count: PositiveInteger, errors: t.array(errorSchema), }) ); - -export type ImportRulesSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts new file mode 100644 index 0000000000000..1fec1c76430eb --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts @@ -0,0 +1,6 @@ +/* + * 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. + */ diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/index.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/index.ts new file mode 100644 index 0000000000000..266a7e30d311c --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/index.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. + */ + +export * from './api/rules/bulk_crud/bulk_create_rules/request_schema'; +export * from './api/rules/bulk_crud/bulk_delete_rules/request_schema'; +export * from './api/rules/bulk_crud/bulk_patch_rules/request_schema'; +export * from './api/rules/bulk_crud/bulk_update_rules/request_schema'; +export * from './api/rules/bulk_crud/response_schema'; + +export * from './api/rules/crud/create_rule/request_schema_validation'; +export * from './api/rules/crud/patch_rule/request_schema_validation'; +export * from './api/rules/crud/patch_rule/request_schema'; +export * from './api/rules/crud/read_rule/query_rule_by_ids_validation'; +export * from './api/rules/crud/read_rule/query_rule_by_ids'; +export * from './api/rules/crud/update_rule/request_schema_validation'; + +export * from './api/rules/export_rules/request_schema'; +export * from './api/rules/find_rules/request_schema_validation'; +export * from './api/rules/find_rules/request_schema'; +export * from './api/rules/import_rules/request_schema'; +export * from './api/rules/import_rules/response_schema'; + +// TODO: https://github.com/elastic/kibana/pull/142950 +// export * from './api/urls'; + +export * from './model/export/export_rules_details_schema'; +export * from './model/import/rule_to_import_validation'; +export * from './model/import/rule_to_import'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/mocks.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/mocks.ts new file mode 100644 index 0000000000000..6827236f8dcbf --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/mocks.ts @@ -0,0 +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. + */ + +export * from './api/rules/bulk_actions/request_schema.mock'; +export * from './api/rules/crud/patch_rule/request_schema.mock'; + +export * from './model/export/export_rules_details_schema.mock'; +export * from './model/import/rule_to_import.mock'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.mock.ts similarity index 100% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.mock.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.mock.ts index 9b79238bef6c7..64b82abdb3755 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.mock.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { ExportRulesDetails } from './export_rules_details_schema'; -import type { ExportExceptionDetailsMock } from '@kbn/lists-plugin/common/schemas/response/exception_export_details_schema.mock'; import { getExceptionExportDetailsMock } from '@kbn/lists-plugin/common/schemas/response/exception_export_details_schema.mock'; +import type { ExportExceptionDetailsMock } from '@kbn/lists-plugin/common/schemas/response/exception_export_details_schema.mock'; +import type { ExportRulesDetails } from './export_rules_details_schema'; interface RuleDetailsMock { totalCount?: number; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.test.ts similarity index 100% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.test.ts diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.ts similarity index 96% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.ts index 05df728aa3f5c..85b423135566b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/export_rules_details_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.ts @@ -16,7 +16,7 @@ const createSchema = ( return t.intersection([t.exact(t.type(requiredFields)), t.exact(t.partial(optionalFields))]); }; -export const exportRulesDetails = { +const exportRulesDetails = { exported_count: t.number, exported_rules_count: t.number, missing_rules: t.array( diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.mock.ts similarity index 88% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.mock.ts index c469926104131..d1dc9e8ac4663 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.mock.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { ImportRulesSchema } from './import_rules_schema'; +import type { RuleToImport } from './rule_to_import'; -export const getImportRulesSchemaMock = (ruleId = 'rule-1'): ImportRulesSchema => ({ +export const getImportRulesSchemaMock = (ruleId = 'rule-1'): RuleToImport => ({ description: 'some description', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', @@ -18,7 +18,7 @@ export const getImportRulesSchemaMock = (ruleId = 'rule-1'): ImportRulesSchema = rule_id: ruleId, }); -export const getImportRulesWithIdSchemaMock = (ruleId = 'rule-1'): ImportRulesSchema => ({ +export const getImportRulesWithIdSchemaMock = (ruleId = 'rule-1'): RuleToImport => ({ id: '6afb8ce1-ea94-4790-8653-fd0b021d2113', description: 'some description', name: 'Query with a rule id', @@ -35,7 +35,7 @@ export const getImportRulesWithIdSchemaMock = (ruleId = 'rule-1'): ImportRulesSc * as we might import/export * @param rules Array of rule objects with which to generate rule JSON */ -export const rulesToNdJsonString = (rules: ImportRulesSchema[]) => { +export const rulesToNdJsonString = (rules: RuleToImport[]) => { return rules.map((rule) => JSON.stringify(rule)).join('\r\n'); }; @@ -49,7 +49,7 @@ export const ruleIdsToNdJsonString = (ruleIds: string[]) => { return rulesToNdJsonString(rules); }; -export const getImportThreatMatchRulesSchemaMock = (ruleId = 'rule-1'): ImportRulesSchema => ({ +export const getImportThreatMatchRulesSchemaMock = (ruleId = 'rule-1'): RuleToImport => ({ description: 'some description', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.test.ts similarity index 78% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.test.ts index 1c119e696e7b7..84478b4af27fe 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.test.ts @@ -5,22 +5,22 @@ * 2.0. */ -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; -import type { ImportRulesPayloadSchema, ImportRulesSchema } from './import_rules_schema'; -import { importRulesPayloadSchema, importRulesSchema } from './import_rules_schema'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListArrayMock } from '../../../schemas/types/lists.mock'; +import { RuleToImport } from './rule_to_import'; import { getImportRulesSchemaMock, getImportThreatMatchRulesSchemaMock, -} from './import_rules_schema.mock'; -import { getListArrayMock } from '../types/lists.mock'; +} from './rule_to_import.mock'; -describe('import rules schema', () => { +describe('RuleToImport', () => { test('empty objects do not validate', () => { - const payload: Partial = {}; + const payload: Partial = {}; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -42,12 +42,12 @@ describe('import rules schema', () => { }); test('made up values do not validate', () => { - const payload: ImportRulesSchema & { madeUp: string } = { + const payload: RuleToImport & { madeUp: string } = { ...getImportRulesSchemaMock(), madeUp: 'hi', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); @@ -55,11 +55,11 @@ describe('import rules schema', () => { }); test('[rule_id] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -78,12 +78,12 @@ describe('import rules schema', () => { }); test('[rule_id, description] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -99,13 +99,13 @@ describe('import rules schema', () => { }); test('[rule_id, description, from] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -121,14 +121,14 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', to: 'now', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -144,7 +144,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, name] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -152,7 +152,7 @@ describe('import rules schema', () => { name: 'some-name', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -165,7 +165,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, name, severity] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -174,7 +174,7 @@ describe('import rules schema', () => { severity: 'low', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toContain( @@ -184,7 +184,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -194,7 +194,7 @@ describe('import rules schema', () => { type: 'query', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -204,7 +204,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -215,7 +215,7 @@ describe('import rules schema', () => { type: 'query', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -225,7 +225,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -237,7 +237,7 @@ describe('import rules schema', () => { index: ['index-1'], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -247,7 +247,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, query, index, interval] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -261,14 +261,14 @@ describe('import rules schema', () => { interval: '5m', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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 = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -282,7 +282,7 @@ describe('import rules schema', () => { language: 'kuery', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -292,7 +292,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -307,14 +307,14 @@ describe('import rules schema', () => { language: 'kuery', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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 validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -330,14 +330,14 @@ describe('import rules schema', () => { language: 'kuery', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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, filter, risk_score] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -350,14 +350,14 @@ describe('import rules schema', () => { risk_score: 50, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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, filter, risk_score, output_index] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -371,26 +371,26 @@ describe('import rules schema', () => { type: 'query', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can send in an empty array to threat', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), threat: [], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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, filter, risk_score, output_index, threat] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -421,19 +421,19 @@ describe('import rules schema', () => { ], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('allows references to be sent as valid', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), references: ['index-1'], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -441,19 +441,19 @@ describe('import rules schema', () => { test('defaults references to an array if it is not sent in', () => { const { references, ...noReferences } = getImportRulesSchemaMock(); - const decoded = importRulesSchema.decode(noReferences); + const decoded = RuleToImport.decode(noReferences); const checked = exactCheck(noReferences, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('references cannot be numbers', () => { - const payload: Omit & { references: number[] } = { + const payload: Omit & { references: number[] } = { ...getImportRulesSchemaMock(), references: [5], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "references"']); @@ -461,12 +461,12 @@ describe('import rules schema', () => { }); test('indexes cannot be numbers', () => { - const payload: Omit & { index: number[] } = { + const payload: Omit & { index: number[] } = { ...getImportRulesSchemaMock(), index: [5], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "index"']); @@ -475,11 +475,11 @@ describe('import rules schema', () => { test('defaults interval to 5 min', () => { const { interval, ...noInterval } = getImportRulesSchemaMock(); - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...noInterval, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -488,11 +488,11 @@ describe('import rules schema', () => { test('defaults max signals to 100', () => { // eslint-disable-next-line @typescript-eslint/naming-convention const { max_signals, ...noMaxSignals } = getImportRulesSchemaMock(); - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...noMaxSignals, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -504,19 +504,19 @@ describe('import rules schema', () => { filters: [], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('filters cannot be a string', () => { - const payload: Omit & { filters: string } = { + const payload: Omit & { filters: string } = { ...getImportRulesSchemaMock(), filters: 'some string', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -531,7 +531,7 @@ describe('import rules schema', () => { language: 'kuery', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -543,19 +543,19 @@ describe('import rules schema', () => { language: 'lucene', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('language does not validate with something made up', () => { - const payload: Omit & { language: string } = { + const payload: Omit & { language: string } = { ...getImportRulesSchemaMock(), language: 'something-made-up', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -565,12 +565,12 @@ describe('import rules schema', () => { }); test('max_signals cannot be negative', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), max_signals: -1, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -580,12 +580,12 @@ describe('import rules schema', () => { }); test('max_signals cannot be zero', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), max_signals: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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"']); @@ -593,36 +593,36 @@ describe('import rules schema', () => { }); test('max_signals can be 1', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), max_signals: 1, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can optionally send in an array of tags', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), tags: ['tag_1', 'tag_2'], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot send in an array of tags that are numbers', () => { - const payload: Omit & { tags: number[] } = { + const payload: Omit & { tags: number[] } = { ...getImportRulesSchemaMock(), tags: [0, 1, 2], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -634,8 +634,8 @@ describe('import rules schema', () => { }); test('You cannot send in an array of threat that are missing "framework"', () => { - const payload: Omit & { - threat: Array>>; + const payload: Omit & { + threat: Array>>; } = { ...getImportRulesSchemaMock(), threat: [ @@ -656,7 +656,7 @@ describe('import rules schema', () => { ], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -666,8 +666,8 @@ describe('import rules schema', () => { }); test('You cannot send in an array of threat that are missing "tactic"', () => { - const payload: Omit & { - threat: Array>>; + const payload: Omit & { + threat: Array>>; } = { ...getImportRulesSchemaMock(), threat: [ @@ -684,7 +684,7 @@ describe('import rules schema', () => { ], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -694,8 +694,8 @@ describe('import rules schema', () => { }); test('You can send in an array of threat that are missing "technique"', () => { - const payload: Omit & { - threat: Array>>; + const payload: Omit & { + threat: Array>>; } = { ...getImportRulesSchemaMock(), threat: [ @@ -710,31 +710,31 @@ describe('import rules schema', () => { ], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can optionally send in an array of false positives', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), false_positives: ['false_1', 'false_2'], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot send in an array of false positives that are numbers', () => { - const payload: Omit & { false_positives: number[] } = { + const payload: Omit & { false_positives: number[] } = { ...getImportRulesSchemaMock(), false_positives: [5, 4], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -745,12 +745,12 @@ describe('import rules schema', () => { }); test('You cannot set the immutable to a number when trying to create a rule', () => { - const payload: Omit & { immutable: number } = { + const payload: Omit & { immutable: number } = { ...getImportRulesSchemaMock(), immutable: 5, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "immutable"']); @@ -758,24 +758,24 @@ describe('import rules schema', () => { }); test('You can optionally set the immutable to be false', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), immutable: false, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot set the immutable to be true', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), immutable: true, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -785,12 +785,12 @@ describe('import rules schema', () => { }); test('You cannot set the immutable to be a number', () => { - const payload: Omit & { immutable: number } = { + const payload: Omit & { immutable: number } = { ...getImportRulesSchemaMock(), immutable: 5, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "immutable"']); @@ -798,12 +798,12 @@ describe('import rules schema', () => { }); test('You cannot set the risk_score to 101', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), risk_score: 101, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -813,12 +813,12 @@ describe('import rules schema', () => { }); test('You cannot set the risk_score to -1', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), risk_score: -1, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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"']); @@ -826,50 +826,50 @@ describe('import rules schema', () => { }); test('You can set the risk_score to 0', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), risk_score: 0, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can set the risk_score to 100', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), risk_score: 100, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can set meta to any object you want', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), meta: { somethingMadeUp: { somethingElse: true }, }, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot create meta as a string', () => { - const payload: Omit & { meta: string } = { + const payload: Omit & { meta: string } = { ...getImportRulesSchemaMock(), meta: 'should not work', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -879,27 +879,27 @@ describe('import rules schema', () => { }); test('validates with timeline_id and timeline_title', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), timeline_id: 'timeline-id', timeline_title: 'timeline-title', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('rule_id is required and you cannot get by with just id', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), id: 'c4e80a0d-e20f-4efc-84c1-08112da5a612', }; // @ts-expect-error delete payload.rule_id; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -909,7 +909,7 @@ describe('import rules schema', () => { }); test('it validates with created_at, updated_at, created_by, updated_by values', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), created_at: '2020-01-09T06:15:24.749Z', updated_at: '2020-01-09T06:15:24.749Z', @@ -917,19 +917,19 @@ describe('import rules schema', () => { updated_by: 'Evan Hassanabad', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('it does not validate with epoch strings for created_at', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), created_at: '1578550728650', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -939,12 +939,12 @@ describe('import rules schema', () => { }); test('it does not validate with epoch strings for updated_at', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), updated_at: '1578550728650', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -953,51 +953,13 @@ describe('import rules schema', () => { expect(message.schema).toEqual({}); }); - describe('importRulesPayloadSchema', () => { - test('does not validate with an empty object', () => { - const payload = {}; - - const decoded = importRulesPayloadSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "file"', - ]); - expect(message.schema).toEqual({}); - }); - - test('does not validate with a made string', () => { - const payload: Omit & { madeUpKey: string } = { - madeUpKey: 'madeupstring', - }; - - const decoded = importRulesPayloadSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "file"', - ]); - expect(message.schema).toEqual({}); - }); - - test('does validate with a file object', () => { - const payload: ImportRulesPayloadSchema = { file: {} }; - - const decoded = importRulesPayloadSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - }); - test('The default for "from" will be "now-6m"', () => { const { from, ...noFrom } = getImportRulesSchemaMock(); - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...noFrom, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1005,23 +967,23 @@ describe('import rules schema', () => { test('The default for "to" will be "now"', () => { const { to, ...noTo } = getImportRulesSchemaMock(); - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...noTo, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { - const payload: Omit & { severity: string } = { + const payload: Omit & { severity: string } = { ...getImportRulesSchemaMock(), severity: 'junk', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "junk" supplied to "severity"']); @@ -1030,22 +992,23 @@ describe('import rules schema', () => { test('The default for "actions" will be an empty array', () => { const { actions, ...noActions } = getImportRulesSchemaMock(); - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...noActions, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); + test('You cannot send in an array of actions that are missing "group"', () => { - const payload: Omit = { + const payload: Omit = { ...getImportRulesSchemaMock(), actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1055,12 +1018,12 @@ describe('import rules schema', () => { }); test('You cannot send in an array of actions that are missing "id"', () => { - const payload: Omit = { + const payload: Omit = { ...getImportRulesSchemaMock(), actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1070,12 +1033,12 @@ describe('import rules schema', () => { }); test('You cannot send in an array of actions that are missing "action_type_id"', () => { - const payload: Omit = { + const payload: Omit = { ...getImportRulesSchemaMock(), actions: [{ group: 'group', id: 'id', params: {} }], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1085,12 +1048,12 @@ describe('import rules schema', () => { }); test('You cannot send in an array of actions that are missing "params"', () => { - const payload: Omit = { + const payload: Omit = { ...getImportRulesSchemaMock(), actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1100,7 +1063,7 @@ describe('import rules schema', () => { }); test('You cannot send in an array of actions that are including "actionTypeId"', () => { - const payload: Omit = { + const payload: Omit = { ...getImportRulesSchemaMock(), actions: [ { @@ -1112,7 +1075,7 @@ describe('import rules schema', () => { ], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1123,11 +1086,11 @@ describe('import rules schema', () => { test('The default for "throttle" will be null', () => { const { throttle, ...noThrottle } = getImportRulesSchemaMock(); - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...noThrottle, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1135,38 +1098,38 @@ describe('import rules schema', () => { describe('note', () => { test('You can set note to a string', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), note: '# documentation markdown here', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You can set note to an empty string', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { ...getImportRulesSchemaMock(), note: '', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('You cannot create note as an object', () => { - const payload: Omit & { note: {} } = { + const payload: Omit & { note: {} } = { ...getImportRulesSchemaMock(), note: { somethingHere: 'something else', }, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1176,7 +1139,7 @@ describe('import rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1190,7 +1153,7 @@ describe('import rules schema', () => { note: '# some markdown', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1199,7 +1162,7 @@ describe('import rules schema', () => { describe('exception_list', () => { test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and exceptions_list] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1215,14 +1178,14 @@ describe('import rules schema', () => { exceptions_list: getListArrayMock(), }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.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, filter, risk_score, note, and empty exceptions_list] does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1238,7 +1201,7 @@ describe('import rules schema', () => { exceptions_list: [], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1261,7 +1224,7 @@ describe('import rules schema', () => { exceptions_list: [{ id: 'uuid_here', namespace_type: 'not a namespace type' }], }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1273,7 +1236,7 @@ describe('import rules schema', () => { }); 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', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1288,7 +1251,7 @@ describe('import rules schema', () => { note: '# some markdown', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1298,7 +1261,7 @@ describe('import rules schema', () => { describe('threat_mapping', () => { test('You can set a threat query, index, mapping, filters on an imported rule', () => { const payload = getImportThreatMatchRulesSchemaMock(); - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1307,7 +1270,7 @@ describe('import rules schema', () => { describe('data_view_id', () => { test('Defined data_view_id and empty index does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1322,7 +1285,7 @@ describe('import rules schema', () => { interval: '5m', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1330,7 +1293,7 @@ describe('import rules schema', () => { // Both can be defined, but if a data_view_id is defined, rule will use that one test('Defined data_view_id and index does validate', () => { - const payload: ImportRulesSchema = { + const payload: RuleToImport = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1345,19 +1308,19 @@ describe('import rules schema', () => { interval: '5m', }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); }); test('data_view_id cannot be a number', () => { - const payload: Omit & { data_view_id: number } = { + const payload: Omit & { data_view_id: number } = { ...getImportRulesSchemaMock(), data_view_id: 5, }; - const decoded = importRulesSchema.decode(payload); + const decoded = RuleToImport.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.ts similarity index 69% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.ts index b3d533a167a7a..b40bed8ce65c5 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.ts @@ -6,20 +6,18 @@ */ import * as t from 'io-ts'; - import { OnlyFalseAllowed } from '@kbn/securitysolution-io-ts-types'; + import { - rule_id, - id, - created_at, - updated_at, - created_by, - updated_by, RelatedIntegrationArray, RequiredFieldArray, + RuleObjectId, + RuleSignatureId, SetupGuide, -} from '../common'; -import { baseCreateParams, createTypeSpecific } from './rule_schemas'; + BaseCreateProps, + TypeSpecificCreateProps, +} from '../../../rule_schema'; +import { created_at, updated_at, created_by, updated_by } from '../../../schemas/common'; /** * Differences from this and the createRulesSchema are @@ -31,13 +29,14 @@ import { baseCreateParams, createTypeSpecific } from './rule_schemas'; * - created_by is optional (but ignored in the import code) * - updated_by is optional (but ignored in the import code) */ -export const importRulesSchema = t.intersection([ - baseCreateParams, - createTypeSpecific, - t.exact(t.type({ rule_id })), +export type RuleToImport = t.TypeOf; +export const RuleToImport = t.intersection([ + BaseCreateProps, + TypeSpecificCreateProps, + t.exact(t.type({ rule_id: RuleSignatureId })), t.exact( t.partial({ - id, + id: RuleObjectId, immutable: OnlyFalseAllowed, updated_at, updated_by, @@ -49,13 +48,3 @@ export const importRulesSchema = t.intersection([ }) ), ]); - -export type ImportRulesSchema = t.TypeOf; - -export const importRulesPayloadSchema = t.exact( - t.type({ - file: t.object, - }) -); - -export type ImportRulesPayloadSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import_validation.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import_validation.test.ts new file mode 100644 index 0000000000000..31ac993eb4053 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import_validation.test.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 type { RuleToImport } from './rule_to_import'; +import { getImportRulesSchemaMock } from './rule_to_import.mock'; +import { validateRuleToImport } from './rule_to_import_validation'; + +describe('Rule to import schema, additional validation', () => { + describe('validateRuleToImport', () => { + test('You cannot omit timeline_title when timeline_id is present', () => { + const schema: RuleToImport = { + ...getImportRulesSchemaMock(), + timeline_id: '123', + }; + delete schema.timeline_title; + const errors = validateRuleToImport(schema); + expect(errors).toEqual(['when "timeline_id" exists, "timeline_title" must also exist']); + }); + + test('You cannot have empty string for timeline_title when timeline_id is present', () => { + const schema: RuleToImport = { + ...getImportRulesSchemaMock(), + timeline_id: '123', + timeline_title: '', + }; + const errors = validateRuleToImport(schema); + expect(errors).toEqual(['"timeline_title" cannot be an empty string']); + }); + + test('You cannot have timeline_title with an empty timeline_id', () => { + const schema: RuleToImport = { + ...getImportRulesSchemaMock(), + timeline_id: '', + timeline_title: 'some-title', + }; + const errors = validateRuleToImport(schema); + expect(errors).toEqual(['"timeline_id" cannot be an empty string']); + }); + + test('You cannot have timeline_title without timeline_id', () => { + const schema: RuleToImport = { + ...getImportRulesSchemaMock(), + timeline_title: 'some-title', + }; + delete schema.timeline_id; + const errors = validateRuleToImport(schema); + expect(errors).toEqual(['when "timeline_title" exists, "timeline_id" must also exist']); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_type_dependents.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import_validation.ts similarity index 78% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_type_dependents.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import_validation.ts index bdb025583b404..de21ac3a7964c 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_type_dependents.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import_validation.ts @@ -5,9 +5,16 @@ * 2.0. */ -import type { ImportRulesSchema } from './import_rules_schema'; +import type { RuleToImport } from './rule_to_import'; -export const validateTimelineId = (rule: ImportRulesSchema): string[] => { +/** + * Additional validation that is implemented outside of the schema itself. + */ +export const validateRuleToImport = (rule: RuleToImport): string[] => { + return [...validateTimelineId(rule), ...validateTimelineTitle(rule), ...validateThreshold(rule)]; +}; + +const validateTimelineId = (rule: RuleToImport): string[] => { if (rule.timeline_id != null) { if (rule.timeline_title == null) { return ['when "timeline_id" exists, "timeline_title" must also exist']; @@ -20,7 +27,7 @@ export const validateTimelineId = (rule: ImportRulesSchema): string[] => { return []; }; -export const validateTimelineTitle = (rule: ImportRulesSchema): string[] => { +const validateTimelineTitle = (rule: RuleToImport): string[] => { if (rule.timeline_title != null) { if (rule.timeline_id == null) { return ['when "timeline_title" exists, "timeline_id" must also exist']; @@ -33,7 +40,7 @@ export const validateTimelineTitle = (rule: ImportRulesSchema): string[] => { return []; }; -export const validateThreshold = (rule: ImportRulesSchema): string[] => { +const validateThreshold = (rule: RuleToImport): string[] => { const errors: string[] = []; if (rule.type === 'threshold') { if ( @@ -48,7 +55,3 @@ export const validateThreshold = (rule: ImportRulesSchema): string[] => { } return errors; }; - -export const importRuleValidateTypeDependents = (rule: ImportRulesSchema): string[] => { - return [...validateTimelineId(rule), ...validateTimelineTitle(rule), ...validateThreshold(rule)]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_monitoring/api/get_rule_execution_events/request_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_monitoring/api/get_rule_execution_events/request_schema.ts index 9ffa2467e0852..59e17a9d6f604 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_monitoring/api/get_rule_execution_events/request_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_monitoring/api/get_rule_execution_events/request_schema.ts @@ -15,7 +15,7 @@ import { TRuleExecutionEventType } from '../../model/execution_event'; import { TLogLevel } from '../../model/log_level'; /** - * Path parameters of the API route. + * URL path parameters of the API route. */ export type GetRuleExecutionEventsRequestParams = t.TypeOf< typeof GetRuleExecutionEventsRequestParams diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/index.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/index.ts new file mode 100644 index 0000000000000..cf1266b1b9a71 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/index.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. + */ + +export * from './model/common_attributes/field_overrides'; +export * from './model/common_attributes/misc_attributes'; +export * from './model/common_attributes/related_integrations'; +export * from './model/common_attributes/required_fields'; +export * from './model/common_attributes/saved_objects'; +export * from './model/common_attributes/timeline_template'; + +export * from './model/specific_attributes/eql_attributes'; +export * from './model/specific_attributes/new_terms_attributes'; +export * from './model/specific_attributes/threshold_attributes'; + +export * from './model/rule_schemas'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/mocks.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/mocks.ts new file mode 100644 index 0000000000000..6cf0d49e9560a --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/mocks.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export * from './model/rule_request_schema.mock'; +export * from './model/rule_response_schema.mock'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/build_rule_schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/build_rule_schemas.ts new file mode 100644 index 0000000000000..f7d52c682d191 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/build_rule_schemas.ts @@ -0,0 +1,90 @@ +/* + * 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 { + 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), + ]); +}; + +type OrUndefined

    = { + [K in keyof P]: P[K] | t.UndefinedC; +}; + +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 = Object.keys(optionalFields).reduce((acc, key) => { + acc[key] = t.union([optionalFields[key], t.undefined]); + return acc; + }, {}) as OrUndefined; + 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/detection_engine/rule_schema/model/common_attributes/field_overrides.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/field_overrides.ts new file mode 100644 index 0000000000000..85058099fdadf --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/field_overrides.ts @@ -0,0 +1,17 @@ +/* + * 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'; + +export type RuleNameOverride = t.TypeOf; +export const RuleNameOverride = t.string; // should be non-empty string? + +export type TimestampOverride = t.TypeOf; +export const TimestampOverride = t.string; // should be non-empty string? + +export type TimestampOverrideFallbackDisabled = t.TypeOf; +export const TimestampOverrideFallbackDisabled = t.boolean; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/misc_attributes.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/misc_attributes.ts new file mode 100644 index 0000000000000..315a15190ec28 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/misc_attributes.ts @@ -0,0 +1,105 @@ +/* + * 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 { listArray } from '@kbn/securitysolution-io-ts-list-types'; +import { NonEmptyString, version, UUID } from '@kbn/securitysolution-io-ts-types'; +import { max_signals, threat } from '@kbn/securitysolution-io-ts-alerting-types'; + +export type RuleObjectId = t.TypeOf; +export const RuleObjectId = UUID; + +/** + * NOTE: Never make this a strict uuid, we allow the rule_id to be any string at the moment + * in case we encounter 3rd party rule systems which might be using auto incrementing numbers + * or other different things. + */ +export type RuleSignatureId = t.TypeOf; +export const RuleSignatureId = t.string; // should be non-empty string? + +export type RuleName = t.TypeOf; +export const RuleName = NonEmptyString; + +export type RuleDescription = t.TypeOf; +export const RuleDescription = NonEmptyString; + +export type RuleVersion = t.TypeOf; +export const RuleVersion = version; + +export type IsRuleImmutable = t.TypeOf; +export const IsRuleImmutable = t.boolean; + +export type IsRuleEnabled = t.TypeOf; +export const IsRuleEnabled = t.boolean; + +export type RuleTagArray = t.TypeOf; +export const RuleTagArray = t.array(t.string); // should be non-empty strings? + +/** + * Note that this is a non-exact io-ts type as we allow extra meta information + * to be added to the meta object + */ +export type RuleMetadata = t.TypeOf; +export const RuleMetadata = t.object; // should be a more specific type? + +export type RuleLicense = t.TypeOf; +export const RuleLicense = t.string; // should be non-empty string? + +export type RuleAuthorArray = t.TypeOf; +export const RuleAuthorArray = t.array(t.string); // should be non-empty strings? + +export type RuleFalsePositiveArray = t.TypeOf; +export const RuleFalsePositiveArray = t.array(t.string); // should be non-empty strings? + +export type RuleReferenceArray = t.TypeOf; +export const RuleReferenceArray = t.array(t.string); // should be non-empty strings? + +export type InvestigationGuide = t.TypeOf; +export const InvestigationGuide = t.string; + +/** + * Any instructions for the user for setting up their environment in order to start receiving + * source events for a given rule. + * + * It's a multiline text. Markdown is supported. + */ +export type SetupGuide = t.TypeOf; +export const SetupGuide = t.string; + +export type BuildingBlockType = t.TypeOf; +export const BuildingBlockType = t.string; + +export type AlertsIndex = t.TypeOf; +export const AlertsIndex = t.string; + +export type AlertsIndexNamespace = t.TypeOf; +export const AlertsIndexNamespace = t.string; + +export type ExceptionListArray = t.TypeOf; +export const ExceptionListArray = listArray; + +export type MaxSignals = t.TypeOf; +export const MaxSignals = max_signals; + +export type ThreatArray = t.TypeOf; +export const ThreatArray = t.array(threat); + +export type IndexPatternArray = t.TypeOf; +export const IndexPatternArray = t.array(t.string); + +export type DataViewId = t.TypeOf; +export const DataViewId = t.string; + +export type RuleQuery = t.TypeOf; +export const RuleQuery = t.string; + +/** + * TODO: Right now the filters is an "unknown", when it could more than likely + * become the actual ESFilter as a type. + */ +export type RuleFilterArray = t.TypeOf; // Filters are not easily type-able yet +export const RuleFilterArray = t.array(t.unknown); // Filters are not easily type-able yet diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_params.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/related_integrations.ts similarity index 55% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_params.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/related_integrations.ts index d65bce6e587ef..d99043d81e19e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_params.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/related_integrations.ts @@ -8,9 +8,6 @@ import * as t from 'io-ts'; import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -// ------------------------------------------------------------------------------------------------- -// Related integrations - /** * Related integration is a potential dependency of a rule. It's assumed that if the user installs * one of the related integrations of a rule, the rule might start to work properly because it will @@ -74,72 +71,3 @@ export const RelatedIntegration = t.exact( */ export type RelatedIntegrationArray = t.TypeOf; export const RelatedIntegrationArray = t.array(RelatedIntegration); - -// ------------------------------------------------------------------------------------------------- -// Required fields - -/** - * Almost all types of Security rules check source event documents for a match to some kind of - * query or filter. If a document has certain field with certain values, then it's a match and - * the rule will generate an alert. - * - * Required field is an event field that must be present in the source indices of a given rule. - * - * @example - * const standardEcsField: RequiredField = { - * name: 'event.action', - * type: 'keyword', - * ecs: true, - * }; - * - * @example - * const nonEcsField: RequiredField = { - * name: 'winlog.event_data.AttributeLDAPDisplayName', - * type: 'keyword', - * ecs: false, - * }; - */ -export const RequiredField = t.exact( - t.type({ - name: NonEmptyString, - type: NonEmptyString, - ecs: t.boolean, - }) -); - -/** - * Array of event fields that must be present in the source indices of a given rule. - * - * @example - * const x: RequiredFieldArray = [ - * { - * name: 'event.action', - * type: 'keyword', - * ecs: true, - * }, - * { - * name: 'event.code', - * type: 'keyword', - * ecs: true, - * }, - * { - * name: 'winlog.event_data.AttributeLDAPDisplayName', - * type: 'keyword', - * ecs: false, - * }, - * ]; - */ -export type RequiredFieldArray = t.TypeOf; -export const RequiredFieldArray = t.array(RequiredField); - -// ------------------------------------------------------------------------------------------------- -// Setup guide - -/** - * Any instructions for the user for setting up their environment in order to start receiving - * source events for a given rule. - * - * It's a multiline text. Markdown is supported. - */ -export type SetupGuide = t.TypeOf; -export const SetupGuide = t.string; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/required_fields.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/required_fields.ts new file mode 100644 index 0000000000000..0938612fd4654 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/required_fields.ts @@ -0,0 +1,64 @@ +/* + * 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 { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +/** + * Almost all types of Security rules check source event documents for a match to some kind of + * query or filter. If a document has certain field with certain values, then it's a match and + * the rule will generate an alert. + * + * Required field is an event field that must be present in the source indices of a given rule. + * + * @example + * const standardEcsField: RequiredField = { + * name: 'event.action', + * type: 'keyword', + * ecs: true, + * }; + * + * @example + * const nonEcsField: RequiredField = { + * name: 'winlog.event_data.AttributeLDAPDisplayName', + * type: 'keyword', + * ecs: false, + * }; + */ +export type RequiredField = t.TypeOf; +export const RequiredField = t.exact( + t.type({ + name: NonEmptyString, + type: NonEmptyString, + ecs: t.boolean, + }) +); + +/** + * Array of event fields that must be present in the source indices of a given rule. + * + * @example + * const x: RequiredFieldArray = [ + * { + * name: 'event.action', + * type: 'keyword', + * ecs: true, + * }, + * { + * name: 'event.code', + * type: 'keyword', + * ecs: true, + * }, + * { + * name: 'winlog.event_data.AttributeLDAPDisplayName', + * type: 'keyword', + * ecs: false, + * }, + * ]; + */ +export type RequiredFieldArray = t.TypeOf; +export const RequiredFieldArray = t.array(RequiredField); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/saved_objects.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/saved_objects.ts new file mode 100644 index 0000000000000..78d2eb1d9813a --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/saved_objects.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 * as t from 'io-ts'; + +/** + * Outcome is a property of the saved object resolve api + * will tell us info about the rule after 8.0 migrations + */ +export type SavedObjectResolveOutcome = t.TypeOf; +export const SavedObjectResolveOutcome = t.union([ + t.literal('exactMatch'), + t.literal('aliasMatch'), + t.literal('conflict'), +]); + +export type SavedObjectResolveAliasTargetId = t.TypeOf; +export const SavedObjectResolveAliasTargetId = t.string; + +export type SavedObjectResolveAliasPurpose = t.TypeOf; +export const SavedObjectResolveAliasPurpose = t.union([ + t.literal('savedObjectConversion'), + t.literal('savedObjectImport'), +]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/timeline_template.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/timeline_template.ts new file mode 100644 index 0000000000000..da3f0c1c210bd --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/common_attributes/timeline_template.ts @@ -0,0 +1,14 @@ +/* + * 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'; + +export type TimelineTemplateId = t.TypeOf; +export const TimelineTemplateId = t.string; // should be non-empty string? + +export type TimelineTemplateTitle = t.TypeOf; +export const TimelineTemplateTitle = t.string; // should be non-empty string? diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_request_schema.mock.ts similarity index 86% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_request_schema.mock.ts index 5edc868a8836c..d76450a0e0425 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_request_schema.mock.ts @@ -7,18 +7,18 @@ import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../constants'; import type { - MachineLearningCreateSchema, - MachineLearningUpdateSchema, - QueryCreateSchema, - QueryUpdateSchema, - SavedQueryCreateSchema, - ThreatMatchCreateSchema, - ThresholdCreateSchema, - NewTermsCreateSchema, - NewTermsUpdateSchema, + MachineLearningRuleCreateProps, + MachineLearningRuleUpdateProps, + QueryRuleCreateProps, + QueryRuleUpdateProps, + SavedQueryRuleCreateProps, + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, + NewTermsRuleCreateProps, + NewTermsRuleUpdateProps, } from './rule_schemas'; -export const getCreateRulesSchemaMock = (ruleId = 'rule-1'): QueryCreateSchema => ({ +export const getCreateRulesSchemaMock = (ruleId = 'rule-1'): QueryRuleCreateProps => ({ description: 'Detecting root and admin users', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', @@ -29,7 +29,7 @@ export const getCreateRulesSchemaMock = (ruleId = 'rule-1'): QueryCreateSchema = rule_id: ruleId, }); -export const getCreateRulesSchemaMockWithDataView = (ruleId = 'rule-1'): QueryCreateSchema => ({ +export const getCreateRulesSchemaMockWithDataView = (ruleId = 'rule-1'): QueryRuleCreateProps => ({ data_view_id: 'logs-*', description: 'Detecting root and admin users', name: 'Query with a rule id', @@ -41,7 +41,9 @@ export const getCreateRulesSchemaMockWithDataView = (ruleId = 'rule-1'): QueryCr rule_id: ruleId, }); -export const getCreateSavedQueryRulesSchemaMock = (ruleId = 'rule-1'): SavedQueryCreateSchema => ({ +export const getCreateSavedQueryRulesSchemaMock = ( + ruleId = 'rule-1' +): SavedQueryRuleCreateProps => ({ description: 'Detecting root and admin users', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', @@ -56,7 +58,7 @@ export const getCreateSavedQueryRulesSchemaMock = (ruleId = 'rule-1'): SavedQuer export const getCreateThreatMatchRulesSchemaMock = ( ruleId = 'rule-1', enabled = false -): ThreatMatchCreateSchema => ({ +): ThreatMatchRuleCreateProps => ({ description: 'Detecting root and admin users', enabled, index: ['auditbeat-*'], @@ -105,7 +107,7 @@ export const getCreateThreatMatchRulesSchemaMock = ( export const getCreateMachineLearningRulesSchemaMock = ( ruleId = 'rule-1' -): MachineLearningCreateSchema => ({ +): MachineLearningRuleCreateProps => ({ description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -116,7 +118,7 @@ export const getCreateMachineLearningRulesSchemaMock = ( machine_learning_job_id: 'typical-ml-job-id', }); -export const getCreateThresholdRulesSchemaMock = (ruleId = 'rule-1'): ThresholdCreateSchema => ({ +export const getCreateThresholdRulesSchemaMock = (ruleId = 'rule-1'): ThresholdRuleCreateProps => ({ description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -133,7 +135,7 @@ export const getCreateThresholdRulesSchemaMock = (ruleId = 'rule-1'): ThresholdC export const getCreateNewTermsRulesSchemaMock = ( ruleId = 'rule-1', enabled = false -): NewTermsCreateSchema => ({ +): NewTermsRuleCreateProps => ({ description: 'Detecting root and admin users', enabled, index: ['auditbeat-*'], @@ -152,7 +154,7 @@ export const getCreateNewTermsRulesSchemaMock = ( export const getUpdateRulesSchemaMock = ( id = '04128c15-0d1b-4716-a4c5-46997ac7f3bd' -): QueryUpdateSchema => ({ +): QueryRuleUpdateProps => ({ description: 'Detecting root and admin users', name: 'Query with a rule id', query: 'user.name: root or user.name: admin', @@ -165,7 +167,7 @@ export const getUpdateRulesSchemaMock = ( export const getUpdateMachineLearningSchemaMock = ( id = '04128c15-0d1b-4716-a4c5-46997ac7f3bd' -): MachineLearningUpdateSchema => ({ +): MachineLearningRuleUpdateProps => ({ description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -178,7 +180,7 @@ export const getUpdateMachineLearningSchemaMock = ( export const getUpdateNewTermsSchemaMock = ( id = '04128c15-0d1b-4716-a4c5-46997ac7f3bd' -): NewTermsUpdateSchema => ({ +): NewTermsRuleUpdateProps => ({ description: 'Detecting root and admin users', index: ['auditbeat-*'], name: 'Query with a rule id', diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_request_schema.test.ts similarity index 86% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_request_schema.test.ts index 12a0c08582a0f..dab249557cc5a 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_request_schema.test.ts @@ -6,11 +6,13 @@ */ import * as t from 'io-ts'; -import type { CreateRulesSchema, SavedQueryCreateSchema } from './rule_schemas'; -import { createRulesSchema, responseSchema } from './rule_schemas'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; 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 { getListArrayMock } from '../../schemas/types/lists.mock'; +import type { SavedQueryRuleCreateProps } from './rule_schemas'; +import { RuleCreateProps } from './rule_schemas'; import { getCreateSavedQueryRulesSchemaMock, getCreateThreatMatchRulesSchemaMock, @@ -18,14 +20,14 @@ import { getCreateThresholdRulesSchemaMock, getCreateRulesSchemaMockWithDataView, getCreateMachineLearningRulesSchemaMock, -} from './rule_schemas.mock'; -import { getListArrayMock } from '../types/lists.mock'; +} from './rule_request_schema.mock'; +import { buildResponseRuleSchema } from './build_rule_schemas'; describe('rules schema', () => { test('empty objects do not validate', () => { const payload = {}; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(message.errors.length).toBeGreaterThan(0); @@ -33,12 +35,12 @@ describe('rules schema', () => { }); test('made up values do not validate', () => { - const payload: CreateRulesSchema & { madeUp: string } = { + const payload: RuleCreateProps & { madeUp: string } = { ...getCreateRulesSchemaMock(), madeUp: 'hi', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); @@ -46,11 +48,11 @@ describe('rules schema', () => { }); test('[rule_id] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(message.errors.length).toBeGreaterThan(0); @@ -58,12 +60,12 @@ describe('rules schema', () => { }); test('[rule_id, description] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(message.errors.length).toBeGreaterThan(0); @@ -71,13 +73,13 @@ describe('rules schema', () => { }); test('[rule_id, description, from] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(message.errors.length).toBeGreaterThan(0); @@ -85,14 +87,14 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', to: 'now', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(message.errors.length).toBeGreaterThan(0); @@ -100,7 +102,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, name] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -108,7 +110,7 @@ describe('rules schema', () => { name: 'some-name', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(message.errors.length).toBeGreaterThan(0); @@ -116,7 +118,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, name, severity] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -125,7 +127,7 @@ describe('rules schema', () => { severity: 'low', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(message.errors.length).toBeGreaterThan(0); @@ -133,7 +135,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -143,7 +145,7 @@ describe('rules schema', () => { type: 'query', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -153,7 +155,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -164,7 +166,7 @@ describe('rules schema', () => { type: 'query', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -174,7 +176,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -186,7 +188,7 @@ describe('rules schema', () => { index: ['index-1'], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -196,7 +198,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, name, severity, type, query, index, interval] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -210,7 +212,7 @@ describe('rules schema', () => { interval: '5m', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -218,7 +220,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does not validate', () => { - const payload: Partial = { + const payload: Partial = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -232,7 +234,7 @@ describe('rules schema', () => { language: 'kuery', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -242,7 +244,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -257,7 +259,7 @@ describe('rules schema', () => { language: 'kuery', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -265,7 +267,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, output_index] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -281,7 +283,7 @@ describe('rules schema', () => { language: 'kuery', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -289,7 +291,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -302,7 +304,7 @@ describe('rules schema', () => { risk_score: 50, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -310,7 +312,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { author: [], severity_mapping: [], risk_score_mapping: [], @@ -327,7 +329,7 @@ describe('rules schema', () => { type: 'query', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -335,12 +337,12 @@ describe('rules schema', () => { }); test('You can send in a namespace', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), namespace: 'a namespace', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -348,12 +350,12 @@ describe('rules schema', () => { }); test('You can send in an empty array to threat', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), threat: [], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -361,7 +363,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index, threat] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -392,7 +394,7 @@ describe('rules schema', () => { ], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -400,12 +402,12 @@ describe('rules schema', () => { }); test('allows references to be sent as valid', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), references: ['index-1'], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -413,12 +415,12 @@ describe('rules schema', () => { }); test('references cannot be numbers', () => { - const payload: Omit & { references: number[] } = { + const payload: Omit & { references: number[] } = { ...getCreateRulesSchemaMock(), references: [5], }; - const decoded = createRulesSchema.decode(payload); + 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"']); @@ -426,12 +428,12 @@ describe('rules schema', () => { }); test('indexes cannot be numbers', () => { - const payload: Omit & { index: number[] } = { + const payload: Omit & { index: number[] } = { ...getCreateRulesSchemaMock(), index: [5], }; - const decoded = createRulesSchema.decode(payload); + 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"']); @@ -439,12 +441,12 @@ describe('rules schema', () => { }); test('saved_query type can have filters with it', () => { - const payload: SavedQueryCreateSchema = { + const payload: SavedQueryRuleCreateProps = { ...getCreateSavedQueryRulesSchemaMock(), filters: [], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -457,7 +459,7 @@ describe('rules schema', () => { filters: 'some string', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -467,12 +469,12 @@ describe('rules schema', () => { }); test('language validates with kuery', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), language: 'kuery', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -480,12 +482,12 @@ describe('rules schema', () => { }); test('language validates with lucene', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), language: 'lucene', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -498,7 +500,7 @@ describe('rules schema', () => { language: 'something-made-up', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -508,12 +510,12 @@ describe('rules schema', () => { }); test('max_signals cannot be negative', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), max_signals: -1, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -523,12 +525,12 @@ describe('rules schema', () => { }); test('max_signals cannot be zero', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), max_signals: 0, }; - const decoded = createRulesSchema.decode(payload); + 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"']); @@ -536,12 +538,12 @@ describe('rules schema', () => { }); test('max_signals can be 1', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), max_signals: 1, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -549,12 +551,12 @@ describe('rules schema', () => { }); test('You can optionally send in an array of tags', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), tags: ['tag_1', 'tag_2'], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -567,7 +569,7 @@ describe('rules schema', () => { tags: [0, 1, 2], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -599,7 +601,7 @@ describe('rules schema', () => { ], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -625,7 +627,7 @@ describe('rules schema', () => { ], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -649,7 +651,7 @@ describe('rules schema', () => { ], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -657,12 +659,12 @@ describe('rules schema', () => { }); test('You can optionally send in an array of false positives', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), false_positives: ['false_1', 'false_2'], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -675,7 +677,7 @@ describe('rules schema', () => { false_positives: [5, 4], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -691,7 +693,7 @@ describe('rules schema', () => { immutable: 5, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['invalid keys "immutable"']); @@ -699,12 +701,12 @@ describe('rules schema', () => { }); test('You cannot set the risk_score to 101', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), risk_score: 101, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -714,12 +716,12 @@ describe('rules schema', () => { }); test('You cannot set the risk_score to -1', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), risk_score: -1, }; - const decoded = createRulesSchema.decode(payload); + 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"']); @@ -727,12 +729,12 @@ describe('rules schema', () => { }); test('You can set the risk_score to 0', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), risk_score: 0, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -740,12 +742,12 @@ describe('rules schema', () => { }); test('You can set the risk_score to 100', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), risk_score: 100, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -753,14 +755,14 @@ describe('rules schema', () => { }); test('You can set meta to any object you want', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), meta: { somethingMadeUp: { somethingElse: true }, }, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -773,7 +775,7 @@ describe('rules schema', () => { meta: 'should not work', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -784,12 +786,12 @@ describe('rules schema', () => { test('You can omit the query string when filters are present', () => { const { query, ...noQuery } = getCreateRulesSchemaMock(); - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...noQuery, filters: [], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -797,13 +799,13 @@ describe('rules schema', () => { }); test('validates with timeline_id and timeline_title', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), timeline_id: 'timeline-id', timeline_title: 'timeline-title', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -816,7 +818,7 @@ describe('rules schema', () => { severity: 'junk', }; - const decoded = createRulesSchema.decode(payload); + 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"']); @@ -829,7 +831,7 @@ describe('rules schema', () => { actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -844,7 +846,7 @@ describe('rules schema', () => { actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -859,7 +861,7 @@ describe('rules schema', () => { actions: [{ group: 'group', id: 'id', params: {} }], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -874,7 +876,7 @@ describe('rules schema', () => { actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -896,7 +898,7 @@ describe('rules schema', () => { ], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -907,12 +909,12 @@ describe('rules schema', () => { describe('note', () => { test('You can set note to a string', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), note: '# documentation markdown here', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -920,12 +922,12 @@ describe('rules schema', () => { }); test('You can set note to an empty string', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), note: '', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -940,7 +942,7 @@ describe('rules schema', () => { }, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -950,12 +952,12 @@ describe('rules schema', () => { }); test('empty name is not valid', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), name: '', }; - const decoded = createRulesSchema.decode(payload); + 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"']); @@ -963,12 +965,12 @@ describe('rules schema', () => { }); test('empty description is not valid', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { ...getCreateRulesSchemaMock(), description: '', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -978,7 +980,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -992,7 +994,7 @@ describe('rules schema', () => { note: '# some markdown', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1001,7 +1003,7 @@ describe('rules schema', () => { }); test('machine_learning type does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { type: 'machine_learning', anomaly_threshold: 50, machine_learning_job_id: 'linux_anomalous_network_activity_ecs', @@ -1023,7 +1025,7 @@ describe('rules schema', () => { rule_id: 'rule-1', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1033,7 +1035,7 @@ describe('rules schema', () => { 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 = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1044,7 +1046,7 @@ describe('rules schema', () => { test('threshold is required when type is threshold and will not validate without it', () => { const { threshold, ...payload } = getCreateThresholdRulesSchemaMock(); - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1056,7 +1058,7 @@ describe('rules schema', () => { test('threshold rules fail validation if threshold is not greater than 0', () => { const payload = getCreateThresholdRulesSchemaMock(); payload.threshold.value = 0; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1067,7 +1069,7 @@ describe('rules schema', () => { describe('exception_list', () => { test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and exceptions_list] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1083,7 +1085,7 @@ describe('rules schema', () => { exceptions_list: getListArrayMock(), }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1091,7 +1093,7 @@ describe('rules schema', () => { }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1107,7 +1109,7 @@ describe('rules schema', () => { exceptions_list: [], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1131,7 +1133,7 @@ describe('rules schema', () => { exceptions_list: [{ id: 'uuid_here', namespace_type: 'not a namespace type' }], }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1143,7 +1145,7 @@ describe('rules schema', () => { }); 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', () => { - const payload: CreateRulesSchema = { + const payload: RuleCreateProps = { rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1158,7 +1160,7 @@ describe('rules schema', () => { note: '# some markdown', }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1169,7 +1171,7 @@ describe('rules schema', () => { describe('threat_match', () => { test('You can set a threat query, index, mapping, filters when creating a rule', () => { const payload = getCreateThreatMatchRulesSchemaMock(); - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1180,7 +1182,7 @@ describe('rules schema', () => { /* eslint-disable @typescript-eslint/naming-convention */ const { threat_index, threat_query, threat_mapping, ...payload } = getCreateThreatMatchRulesSchemaMock(); - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1194,7 +1196,7 @@ describe('rules schema', () => { test('fails validation when threat_mapping is an empty array', () => { const payload = getCreateThreatMatchRulesSchemaMock(); payload.threat_mapping = []; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1207,7 +1209,7 @@ describe('rules schema', () => { describe('data_view_id', () => { test('validates when "data_view_id" and index are defined', () => { const payload = { ...getCreateRulesSchemaMockWithDataView(), index: ['auditbeat-*'] }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([]); @@ -1215,12 +1217,12 @@ describe('rules schema', () => { }); test('"data_view_id" cannot be a number', () => { - const payload: Omit & { data_view_id: number } = { + const payload: Omit & { data_view_id: number } = { ...getCreateRulesSchemaMockWithDataView(), data_view_id: 5, }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ @@ -1232,7 +1234,7 @@ describe('rules schema', () => { test('it should validate a type of "query" with "data_view_id" defined', () => { const payload = getCreateRulesSchemaMockWithDataView(); - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = getCreateRulesSchemaMockWithDataView(); @@ -1244,7 +1246,7 @@ describe('rules schema', () => { test('it should validate a type of "saved_query" with "data_view_id" defined', () => { const payload = { ...getCreateSavedQueryRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = { ...getCreateSavedQueryRulesSchemaMock(), data_view_id: 'logs-*' }; @@ -1256,7 +1258,7 @@ describe('rules schema', () => { test('it should validate a type of "threat_match" with "data_view_id" defined', () => { const payload = { ...getCreateThreatMatchRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = { ...getCreateThreatMatchRulesSchemaMock(), data_view_id: 'logs-*' }; @@ -1268,7 +1270,7 @@ describe('rules schema', () => { test('it should validate a type of "threshold" with "data_view_id" defined', () => { const payload = { ...getCreateThresholdRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = { ...getCreateThresholdRulesSchemaMock(), data_view_id: 'logs-*' }; @@ -1280,7 +1282,7 @@ describe('rules schema', () => { test('it should NOT validate a type of "machine_learning" with "data_view_id" defined', () => { const payload = { ...getCreateMachineLearningRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = createRulesSchema.decode(payload); + const decoded = RuleCreateProps.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -1301,7 +1303,11 @@ describe('rules schema', () => { testDefaultableString: t.string, }, }; - const schema = responseSchema(testSchema.required, testSchema.optional, testSchema.defaultable); + const schema = buildResponseRuleSchema( + testSchema.required, + testSchema.optional, + testSchema.defaultable + ); describe('required fields', () => { test('should allow required fields with the correct type', () => { diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.mock.ts similarity index 87% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.mock.ts index 189cbd1045d67..0a99da6b4f6f3 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.mock.ts @@ -7,18 +7,18 @@ import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../constants'; import type { - EqlResponseSchema, - MachineLearningResponseSchema, - QueryResponseSchema, - SavedQueryResponseSchema, - SharedResponseSchema, - ThreatMatchResponseSchema, -} from '../request'; -import { getListArrayMock } from '../types/lists.mock'; + EqlRule, + MachineLearningRule, + QueryRule, + SavedQueryRule, + SharedResponseProps, + ThreatMatchRule, +} from './rule_schemas'; +import { getListArrayMock } from '../../schemas/types/lists.mock'; export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z'; -const getResponseBaseParams = (anchorDate: string = ANCHOR_DATE): SharedResponseSchema => ({ +const getResponseBaseParams = (anchorDate: string = ANCHOR_DATE): SharedResponseProps => ({ author: [], id: '7a7065d7-6e8b-4aae-8d20-c93613dec9f9', created_at: new Date(anchorDate).toISOString(), @@ -65,7 +65,7 @@ const getResponseBaseParams = (anchorDate: string = ANCHOR_DATE): SharedResponse namespace: undefined, }); -export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): QueryResponseSchema => ({ +export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): QueryRule => ({ ...getResponseBaseParams(anchorDate), query: 'user.name: root or user.name: admin', type: 'query', @@ -76,9 +76,8 @@ export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): QueryRespo saved_id: undefined, response_actions: undefined, }); -export const getSavedQuerySchemaMock = ( - anchorDate: string = ANCHOR_DATE -): SavedQueryResponseSchema => ({ + +export const getSavedQuerySchemaMock = (anchorDate: string = ANCHOR_DATE): SavedQueryRule => ({ ...getResponseBaseParams(anchorDate), query: 'user.name: root or user.name: admin', type: 'saved_query', @@ -90,9 +89,7 @@ export const getSavedQuerySchemaMock = ( response_actions: undefined, }); -export const getRulesMlSchemaMock = ( - anchorDate: string = ANCHOR_DATE -): MachineLearningResponseSchema => { +export const getRulesMlSchemaMock = (anchorDate: string = ANCHOR_DATE): MachineLearningRule => { return { ...getResponseBaseParams(anchorDate), type: 'machine_learning', @@ -101,9 +98,7 @@ export const getRulesMlSchemaMock = ( }; }; -export const getThreatMatchingSchemaMock = ( - anchorDate: string = ANCHOR_DATE -): ThreatMatchResponseSchema => { +export const getThreatMatchingSchemaMock = (anchorDate: string = ANCHOR_DATE): ThreatMatchRule => { return { ...getResponseBaseParams(anchorDate), type: 'threat_match', @@ -145,9 +140,7 @@ export const getThreatMatchingSchemaMock = ( * Useful for e2e backend tests where it doesn't have date time and other * server side properties attached to it. */ -export const getThreatMatchingSchemaPartialMock = ( - enabled = false -): Partial => { +export const getThreatMatchingSchemaPartialMock = (enabled = false): Partial => { return { author: [], created_by: 'elastic', @@ -216,7 +209,7 @@ export const getThreatMatchingSchemaPartialMock = ( }; }; -export const getRulesEqlSchemaMock = (anchorDate: string = ANCHOR_DATE): EqlResponseSchema => { +export const getRulesEqlSchemaMock = (anchorDate: string = ANCHOR_DATE): EqlRule => { return { ...getResponseBaseParams(anchorDate), language: 'eql', diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.test.ts similarity index 80% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.test.ts index 0a337eb28bc1c..0032ee60267c4 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.test.ts @@ -7,23 +7,22 @@ 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 { getRulesSchemaMock, getRulesMlSchemaMock, getSavedQuerySchemaMock, getThreatMatchingSchemaMock, getRulesEqlSchemaMock, -} from './rules_schema.mocks'; -import { fullResponseSchema } from '../request'; -import type { FullResponseSchema } from '../request'; +} from './rule_response_schema.mock'; -describe('rules_schema', () => { +describe('Rule response schema', () => { test('it should validate a type of "query" without anything extra', () => { const payload = getRulesSchemaMock(); - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = getRulesSchemaMock(); @@ -33,10 +32,10 @@ describe('rules_schema', () => { }); test('it should NOT validate a type of "query" when it has extra data', () => { - const payload: FullResponseSchema & { invalid_extra_data?: string } = getRulesSchemaMock(); + const payload: RuleResponse & { invalid_extra_data?: string } = getRulesSchemaMock(); payload.invalid_extra_data = 'invalid_extra_data'; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -45,10 +44,10 @@ describe('rules_schema', () => { }); test('it should NOT validate invalid_data for the type', () => { - const payload: Omit & { type: string } = getRulesSchemaMock(); + const payload: Omit & { type: string } = getRulesSchemaMock(); payload.type = 'invalid_data'; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -57,11 +56,11 @@ describe('rules_schema', () => { }); test('it should validate a type of "query" with a saved_id together', () => { - const payload: FullResponseSchema & { saved_id?: string } = getRulesSchemaMock(); + const payload: RuleResponse & { saved_id?: string } = getRulesSchemaMock(); payload.type = 'query'; payload.saved_id = 'save id 123'; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -72,7 +71,7 @@ describe('rules_schema', () => { test('it should validate a type of "saved_query" with a "saved_id" dependent', () => { const payload = getSavedQuerySchemaMock(); - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = getSavedQuerySchemaMock(); @@ -82,11 +81,11 @@ describe('rules_schema', () => { }); test('it should NOT validate a type of "saved_query" without a "saved_id" dependent', () => { - const payload: FullResponseSchema & { saved_id?: string } = getSavedQuerySchemaMock(); + const payload: RuleResponse & { saved_id?: string } = getSavedQuerySchemaMock(); // @ts-expect-error delete payload.saved_id; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -97,11 +96,11 @@ describe('rules_schema', () => { }); test('it should NOT validate a type of "saved_query" when it has extra data', () => { - const payload: FullResponseSchema & { saved_id?: string; invalid_extra_data?: string } = + const payload: RuleResponse & { saved_id?: string; invalid_extra_data?: string } = getSavedQuerySchemaMock(); payload.invalid_extra_data = 'invalid_extra_data'; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -114,7 +113,7 @@ describe('rules_schema', () => { payload.timeline_id = 'some timeline id'; payload.timeline_title = 'some timeline title'; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = getRulesSchemaMock(); @@ -126,12 +125,12 @@ describe('rules_schema', () => { }); test('it should NOT validate a type of "timeline_id" if there is "timeline_title" dependent when it has extra invalid data', () => { - const payload: FullResponseSchema & { invalid_extra_data?: string } = getRulesSchemaMock(); + 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 = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -143,7 +142,7 @@ describe('rules_schema', () => { test('it should validate an empty array for "exceptions_list"', () => { const payload = getRulesSchemaMock(); payload.exceptions_list = []; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = getRulesSchemaMock(); @@ -153,11 +152,11 @@ describe('rules_schema', () => { }); test('it should NOT validate when "exceptions_list" is not expected type', () => { - const payload: Omit & { + const payload: Omit & { exceptions_list?: string; } = { ...getRulesSchemaMock(), exceptions_list: 'invalid_data' }; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -172,7 +171,7 @@ describe('rules_schema', () => { test('it should validate a type of "query" with "data_view_id" defined', () => { const payload = { ...getRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = { ...getRulesSchemaMock(), data_view_id: 'logs-*' }; @@ -182,14 +181,14 @@ describe('rules_schema', () => { }); test('it should validate a type of "saved_query" with "data_view_id" defined', () => { - const payload: FullResponseSchema & { saved_id?: string; data_view_id?: string } = + const payload: RuleResponse & { saved_id?: string; data_view_id?: string } = getSavedQuerySchemaMock(); payload.data_view_id = 'logs-*'; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); - const expected: FullResponseSchema & { saved_id?: string; data_view_id?: string } = + const expected: RuleResponse & { saved_id?: string; data_view_id?: string } = getSavedQuerySchemaMock(); expected.data_view_id = 'logs-*'; @@ -201,7 +200,7 @@ describe('rules_schema', () => { test('it should validate a type of "eql" with "data_view_id" defined', () => { const payload = { ...getRulesEqlSchemaMock(), data_view_id: 'logs-*' }; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = { ...getRulesEqlSchemaMock(), data_view_id: 'logs-*' }; @@ -213,7 +212,7 @@ describe('rules_schema', () => { test('it should validate a type of "threat_match" with "data_view_id" defined', () => { const payload = { ...getThreatMatchingSchemaMock(), data_view_id: 'logs-*' }; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); const expected = { ...getThreatMatchingSchemaMock(), data_view_id: 'logs-*' }; @@ -225,7 +224,7 @@ describe('rules_schema', () => { test('it should NOT validate a type of "machine_learning" with "data_view_id" defined', () => { const payload = { ...getRulesMlSchemaMock(), data_view_id: 'logs-*' }; - const decoded = fullResponseSchema.decode(payload); + const decoded = RuleResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_schemas.ts new file mode 100644 index 0000000000000..9985ef4102736 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_schemas.ts @@ -0,0 +1,554 @@ +/* + * 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 { + concurrent_searches, + items_per_search, + machine_learning_job_id, + RiskScore, + RiskScoreMapping, + RuleActionArray, + RuleActionThrottle, + RuleInterval, + RuleIntervalFrom, + RuleIntervalTo, + Severity, + SeverityMapping, + threat_filters, + threat_index, + threat_indicator_path, + threat_mapping, + threat_query, +} from '@kbn/securitysolution-io-ts-alerting-types'; + +import { RuleExecutionSummary } from '../../rule_monitoring'; +import { ResponseActionArray } from '../../rule_response_actions/schemas'; +import { + saved_id, + anomaly_threshold, + updated_at, + updated_by, + created_at, + created_by, +} from '../../schemas/common'; + +import { + AlertsIndex, + AlertsIndexNamespace, + BuildingBlockType, + DataViewId, + ExceptionListArray, + IndexPatternArray, + InvestigationGuide, + IsRuleEnabled, + IsRuleImmutable, + MaxSignals, + RuleAuthorArray, + RuleDescription, + RuleFalsePositiveArray, + RuleFilterArray, + RuleLicense, + RuleMetadata, + RuleName, + RuleObjectId, + RuleQuery, + RuleReferenceArray, + RuleSignatureId, + RuleTagArray, + RuleVersion, + SetupGuide, + ThreatArray, +} from './common_attributes/misc_attributes'; +import { + RuleNameOverride, + TimestampOverride, + TimestampOverrideFallbackDisabled, +} from './common_attributes/field_overrides'; +import { + SavedObjectResolveAliasPurpose, + SavedObjectResolveAliasTargetId, + SavedObjectResolveOutcome, +} from './common_attributes/saved_objects'; +import { RelatedIntegrationArray } from './common_attributes/related_integrations'; +import { RequiredFieldArray } from './common_attributes/required_fields'; +import { TimelineTemplateId, TimelineTemplateTitle } from './common_attributes/timeline_template'; +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 { buildRuleSchemas } from './build_rule_schemas'; + +// ------------------------------------------------------------------------------------------------- +// Base schema + +const baseSchema = buildRuleSchemas({ + required: { + name: RuleName, + description: RuleDescription, + risk_score: RiskScore, + severity: Severity, + }, + optional: { + // Field overrides + rule_name_override: RuleNameOverride, + timestamp_override: TimestampOverride, + timestamp_override_fallback_disabled: TimestampOverrideFallbackDisabled, + // Timeline template + timeline_id: TimelineTemplateId, + timeline_title: TimelineTemplateTitle, + // Atributes related to SavedObjectsClient.resolve API + outcome: SavedObjectResolveOutcome, + alias_target_id: SavedObjectResolveAliasTargetId, + alias_purpose: SavedObjectResolveAliasPurpose, + // Misc attributes + license: RuleLicense, + note: InvestigationGuide, + building_block_type: BuildingBlockType, + output_index: AlertsIndex, + namespace: AlertsIndexNamespace, + meta: RuleMetadata, + }, + defaultable: { + // Main attributes + version: RuleVersion, + tags: RuleTagArray, + enabled: IsRuleEnabled, + // Field overrides + risk_score_mapping: RiskScoreMapping, + severity_mapping: SeverityMapping, + // Rule schedule + interval: RuleInterval, + from: RuleIntervalFrom, + to: RuleIntervalTo, + // Rule actions + actions: RuleActionArray, + throttle: RuleActionThrottle, + // Rule exceptions + exceptions_list: ExceptionListArray, + // Misc attributes + author: RuleAuthorArray, + false_positives: RuleFalsePositiveArray, + references: RuleReferenceArray, + // maxSignals not used in ML rules but probably should be used + max_signals: MaxSignals, + threat: ThreatArray, + }, +}); + +const responseRequiredFields = { + id: RuleObjectId, + rule_id: RuleSignatureId, + immutable: IsRuleImmutable, + updated_at, + updated_by, + created_at, + created_by, + + // 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: RelatedIntegrationArray, + required_fields: RequiredFieldArray, + setup: SetupGuide, +}; + +const responseOptionalFields = { + execution_summary: RuleExecutionSummary, +}; + +export type BaseCreateProps = t.TypeOf; +export const BaseCreateProps = baseSchema.create; + +// ------------------------------------------------------------------------------------------------- +// Shared schemas + +// "Shared" types are the same across all rule types, and built from "baseSchema" above +// with some variations for each route. These intersect with type specific schemas below +// to create the full schema for each route. + +type SharedCreateProps = t.TypeOf; +const SharedCreateProps = t.intersection([ + baseSchema.create, + t.exact(t.partial({ rule_id: RuleSignatureId })), +]); + +type SharedUpdateProps = t.TypeOf; +const SharedUpdateProps = t.intersection([ + baseSchema.create, + t.exact(t.partial({ rule_id: RuleSignatureId })), + t.exact(t.partial({ id: RuleObjectId })), +]); + +type SharedPatchProps = t.TypeOf; +const SharedPatchProps = t.intersection([ + baseSchema.patch, + t.exact(t.partial({ rule_id: RuleSignatureId, id: RuleObjectId })), +]); + +export type SharedResponseProps = t.TypeOf; +export const SharedResponseProps = t.intersection([ + baseSchema.response, + t.exact(t.type(responseRequiredFields)), + t.exact(t.partial(responseOptionalFields)), +]); + +// ------------------------------------------------------------------------------------------------- +// EQL rule schema + +const eqlSchema = buildRuleSchemas({ + required: { + type: t.literal('eql'), + language: t.literal('eql'), + query: RuleQuery, + }, + optional: { + index: IndexPatternArray, + data_view_id: DataViewId, + filters: RuleFilterArray, + timestamp_field: TimestampField, + event_category_override: EventCategoryOverride, + tiebreaker_field: TiebreakerField, + }, + defaultable: {}, +}); + +export type EqlRule = t.TypeOf; +export const EqlRule = t.intersection([SharedResponseProps, eqlSchema.response]); + +export type EqlRuleCreateProps = t.TypeOf; +export const EqlRuleCreateProps = t.intersection([SharedCreateProps, eqlSchema.create]); + +export type EqlRuleUpdateProps = t.TypeOf; +export const EqlRuleUpdateProps = t.intersection([SharedUpdateProps, eqlSchema.create]); + +export type EqlRulePatchProps = t.TypeOf; +export const EqlRulePatchProps = t.intersection([SharedPatchProps, eqlSchema.patch]); + +export type EqlPatchParams = t.TypeOf; +export const EqlPatchParams = eqlSchema.patch; + +// ------------------------------------------------------------------------------------------------- +// Indicator Match rule schema + +const threatMatchSchema = buildRuleSchemas({ + required: { + type: t.literal('threat_match'), + query: RuleQuery, + threat_query, + threat_mapping, + threat_index, + }, + optional: { + index: IndexPatternArray, + data_view_id: DataViewId, + filters: RuleFilterArray, + saved_id, + threat_filters, + threat_indicator_path, + threat_language: t.keyof({ kuery: null, lucene: null }), + concurrent_searches, + items_per_search, + }, + defaultable: { + language: t.keyof({ kuery: null, lucene: null }), + }, +}); + +export type ThreatMatchRule = t.TypeOf; +export const ThreatMatchRule = t.intersection([SharedResponseProps, threatMatchSchema.response]); + +export type ThreatMatchRuleCreateProps = t.TypeOf; +export const ThreatMatchRuleCreateProps = t.intersection([ + SharedCreateProps, + threatMatchSchema.create, +]); + +export type ThreatMatchRuleUpdateProps = t.TypeOf; +export const ThreatMatchRuleUpdateProps = t.intersection([ + SharedUpdateProps, + threatMatchSchema.create, +]); + +export type ThreatMatchRulePatchProps = t.TypeOf; +export const ThreatMatchRulePatchProps = t.intersection([ + SharedPatchProps, + threatMatchSchema.patch, +]); + +export type ThreatMatchPatchParams = t.TypeOf; +export const ThreatMatchPatchParams = threatMatchSchema.patch; + +// ------------------------------------------------------------------------------------------------- +// Custom Query rule schema + +const querySchema = buildRuleSchemas({ + required: { + type: t.literal('query'), + }, + optional: { + index: IndexPatternArray, + data_view_id: DataViewId, + filters: RuleFilterArray, + saved_id, + response_actions: ResponseActionArray, + }, + defaultable: { + query: RuleQuery, + language: t.keyof({ kuery: null, lucene: null }), + }, +}); + +export type QueryRule = t.TypeOf; +export const QueryRule = t.intersection([SharedResponseProps, querySchema.response]); + +export type QueryRuleCreateProps = t.TypeOf; +export const QueryRuleCreateProps = t.intersection([SharedCreateProps, querySchema.create]); + +export type QueryRuleUpdateProps = t.TypeOf; +export const QueryRuleUpdateProps = t.intersection([SharedUpdateProps, querySchema.create]); + +export type QueryRulePatchProps = t.TypeOf; +export const QueryRulePatchProps = t.intersection([SharedPatchProps, querySchema.patch]); + +export type QueryPatchParams = t.TypeOf; +export const QueryPatchParams = querySchema.patch; + +// ------------------------------------------------------------------------------------------------- +// Saved Query rule schema + +const savedQuerySchema = buildRuleSchemas({ + required: { + type: t.literal('saved_query'), + saved_id, + }, + optional: { + // Having language, query, and filters possibly defined adds more code confusion and probably user confusion + // if the saved object gets deleted for some reason + index: IndexPatternArray, + data_view_id: DataViewId, + query: RuleQuery, + filters: RuleFilterArray, + response_actions: ResponseActionArray, + }, + defaultable: { + language: t.keyof({ kuery: null, lucene: null }), + }, +}); + +export type SavedQueryRule = t.TypeOf; +export const SavedQueryRule = t.intersection([SharedResponseProps, savedQuerySchema.response]); + +export type SavedQueryRuleCreateProps = t.TypeOf; +export const SavedQueryRuleCreateProps = t.intersection([ + SharedCreateProps, + savedQuerySchema.create, +]); + +export type SavedQueryRuleUpdateProps = t.TypeOf; +export const SavedQueryRuleUpdateProps = t.intersection([ + SharedUpdateProps, + savedQuerySchema.create, +]); + +export type SavedQueryRulePatchProps = t.TypeOf; +export const SavedQueryRulePatchProps = t.intersection([SharedPatchProps, savedQuerySchema.patch]); + +export type SavedQueryPatchParams = t.TypeOf; +export const SavedQueryPatchParams = savedQuerySchema.patch; + +// ------------------------------------------------------------------------------------------------- +// Threshold rule schema + +const thresholdSchema = buildRuleSchemas({ + required: { + type: t.literal('threshold'), + query: RuleQuery, + threshold: Threshold, + }, + optional: { + index: IndexPatternArray, + data_view_id: DataViewId, + filters: RuleFilterArray, + saved_id, + }, + defaultable: { + language: t.keyof({ kuery: null, lucene: null }), + }, +}); + +export type ThresholdRule = t.TypeOf; +export const ThresholdRule = t.intersection([SharedResponseProps, thresholdSchema.response]); + +export type ThresholdRuleCreateProps = t.TypeOf; +export const ThresholdRuleCreateProps = t.intersection([SharedCreateProps, thresholdSchema.create]); + +export type ThresholdRuleUpdateProps = t.TypeOf; +export const ThresholdRuleUpdateProps = t.intersection([SharedUpdateProps, thresholdSchema.create]); + +export type ThresholdRulePatchProps = t.TypeOf; +export const ThresholdRulePatchProps = t.intersection([SharedPatchProps, thresholdSchema.patch]); + +export type ThresholdPatchParams = t.TypeOf; +export const ThresholdPatchParams = thresholdSchema.patch; + +// ------------------------------------------------------------------------------------------------- +// Machine Learning rule schema + +const machineLearningSchema = buildRuleSchemas({ + required: { + type: t.literal('machine_learning'), + anomaly_threshold, + machine_learning_job_id, + }, + optional: {}, + defaultable: {}, +}); + +export type MachineLearningRule = t.TypeOf; +export const MachineLearningRule = t.intersection([ + SharedResponseProps, + machineLearningSchema.response, +]); + +export type MachineLearningRuleCreateProps = t.TypeOf; +export const MachineLearningRuleCreateProps = t.intersection([ + SharedCreateProps, + machineLearningSchema.create, +]); + +export type MachineLearningRuleUpdateProps = t.TypeOf; +export const MachineLearningRuleUpdateProps = t.intersection([ + SharedUpdateProps, + machineLearningSchema.create, +]); + +export type MachineLearningRulePatchProps = t.TypeOf; +export const MachineLearningRulePatchProps = t.intersection([ + SharedPatchProps, + machineLearningSchema.patch, +]); + +export type MachineLearningPatchParams = t.TypeOf; +export const MachineLearningPatchParams = machineLearningSchema.patch; + +// ------------------------------------------------------------------------------------------------- +// New Terms rule schema + +const newTermsSchema = buildRuleSchemas({ + required: { + type: t.literal('new_terms'), + query: RuleQuery, + new_terms_fields: NewTermsFields, + history_window_start: HistoryWindowStart, + }, + optional: { + index: IndexPatternArray, + data_view_id: DataViewId, + filters: RuleFilterArray, + }, + defaultable: { + language: t.keyof({ kuery: null, lucene: null }), + }, +}); + +export type NewTermsRule = t.TypeOf; +export const NewTermsRule = t.intersection([SharedResponseProps, newTermsSchema.response]); + +export type NewTermsRuleCreateProps = t.TypeOf; +export const NewTermsRuleCreateProps = t.intersection([SharedCreateProps, newTermsSchema.create]); + +export type NewTermsRuleUpdateProps = t.TypeOf; +export const NewTermsRuleUpdateProps = t.intersection([SharedUpdateProps, newTermsSchema.create]); + +export type NewTermsRulePatchProps = t.TypeOf; +export const NewTermsRulePatchProps = t.intersection([SharedPatchProps, newTermsSchema.patch]); + +export type NewTermsPatchParams = t.TypeOf; +export const NewTermsPatchParams = newTermsSchema.patch; + +// ------------------------------------------------------------------------------------------------- +// Combined type specific schemas + +export type TypeSpecificCreateProps = t.TypeOf; +export const TypeSpecificCreateProps = t.union([ + eqlSchema.create, + threatMatchSchema.create, + querySchema.create, + savedQuerySchema.create, + thresholdSchema.create, + machineLearningSchema.create, + newTermsSchema.create, +]); + +export type TypeSpecificPatchProps = t.TypeOf; +export const TypeSpecificPatchProps = t.union([ + eqlSchema.patch, + threatMatchSchema.patch, + querySchema.patch, + savedQuerySchema.patch, + thresholdSchema.patch, + machineLearningSchema.patch, + newTermsSchema.patch, +]); + +export type TypeSpecificResponse = t.TypeOf; +export const TypeSpecificResponse = t.union([ + eqlSchema.response, + threatMatchSchema.response, + querySchema.response, + savedQuerySchema.response, + thresholdSchema.response, + machineLearningSchema.response, + newTermsSchema.response, +]); + +// ------------------------------------------------------------------------------------------------- +// Final combined schemas + +export type RuleCreateProps = t.TypeOf; +export const RuleCreateProps = t.intersection([SharedCreateProps, TypeSpecificCreateProps]); + +export type RuleUpdateProps = t.TypeOf; +export const RuleUpdateProps = t.intersection([TypeSpecificCreateProps, SharedUpdateProps]); + +export type RulePatchProps = t.TypeOf; +export const RulePatchProps = t.intersection([TypeSpecificPatchProps, SharedPatchProps]); + +export type RuleResponse = t.TypeOf; +export const RuleResponse = t.intersection([SharedResponseProps, TypeSpecificResponse]); + +// ------------------------------------------------------------------------------------------------- +// Rule preview schemas + +// TODO: Move to the rule_preview subdomain + +export type PreviewRulesSchema = t.TypeOf; +export const previewRulesSchema = t.intersection([ + SharedCreateProps, + TypeSpecificCreateProps, + t.type({ invocationCount: t.number, timeframeEnd: t.string }), +]); + +export interface RulePreviewLogs { + errors: string[]; + warnings: string[]; + startedAt?: string; + duration: number; +} + +export interface PreviewResponse { + previewId: string | undefined; + logs: RulePreviewLogs[] | undefined; + isAborted: boolean | undefined; +} diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/eql_attributes.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/eql_attributes.ts new file mode 100644 index 0000000000000..0bc029fa0d4a5 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/eql_attributes.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 * as t from 'io-ts'; + +// Attributes specific to EQL rules + +export type EventCategoryOverride = t.TypeOf; +export const EventCategoryOverride = t.string; // should be non-empty string? + +export type TimestampField = t.TypeOf; +export const TimestampField = t.string; // should be non-empty string? + +export type TiebreakerField = t.TypeOf; +export const TiebreakerField = t.string; // should be non-empty string? diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/new_terms_attributes.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/new_terms_attributes.ts new file mode 100644 index 0000000000000..15bf73ba150e5 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/new_terms_attributes.ts @@ -0,0 +1,20 @@ +/* + * 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 { LimitedSizeArray, NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +// Attributes specific to New Terms rules + +/** + * New terms rule type currently only supports a single term, but should support more in the future + */ +export type NewTermsFields = t.TypeOf; +export const NewTermsFields = LimitedSizeArray({ codec: t.string, minSize: 1, maxSize: 1 }); + +export type HistoryWindowStart = t.TypeOf; +export const HistoryWindowStart = NonEmptyString; diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/threshold_attributes.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/threshold_attributes.ts new file mode 100644 index 0000000000000..eb5639c97ab3e --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/specific_attributes/threshold_attributes.ts @@ -0,0 +1,62 @@ +/* + * 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 { PositiveInteger, PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; + +// Attributes specific to Threshold rules + +const thresholdField = t.exact( + t.type({ + field: t.union([t.string, t.array(t.string)]), // Covers pre- and post-7.12 + value: PositiveIntegerGreaterThanZero, + }) +); + +const thresholdFieldNormalized = t.exact( + t.type({ + field: t.array(t.string), + value: PositiveIntegerGreaterThanZero, + }) +); + +const thresholdCardinalityField = t.exact( + t.type({ + field: t.string, + value: PositiveInteger, + }) +); + +export type Threshold = t.TypeOf; +export const Threshold = t.intersection([ + thresholdField, + t.exact( + t.partial({ + cardinality: t.array(thresholdCardinalityField), + }) + ), +]); + +export type ThresholdNormalized = t.TypeOf; +export const ThresholdNormalized = t.intersection([ + thresholdFieldNormalized, + t.exact( + t.partial({ + cardinality: t.array(thresholdCardinalityField), + }) + ), +]); + +export type ThresholdWithCardinality = t.TypeOf; +export const ThresholdWithCardinality = t.intersection([ + thresholdFieldNormalized, + t.exact( + t.type({ + cardinality: t.array(thresholdCardinalityField), + }) + ), +]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/index.ts index ad8745a8caf21..e129a72362ed7 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/index.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/index.ts @@ -5,8 +5,6 @@ * 2.0. */ -export * from './installed_integrations'; export * from './pagination'; -export * from './rule_params'; export * from './schemas'; export * from './sorting'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index f7c5fe6307736..52ba9e06622d4 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -7,55 +7,8 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { - IsoDateString, - NonEmptyString, - PositiveInteger, - PositiveIntegerGreaterThanZero, - UUID, - LimitedSizeArray, -} from '@kbn/securitysolution-io-ts-types'; import * as t from 'io-ts'; - -export const author = t.array(t.string); -export type Author = t.TypeOf; - -export const building_block_type = t.string; -export type BuildingBlockType = t.TypeOf; - -export const buildingBlockTypeOrUndefined = t.union([building_block_type, t.undefined]); - -export const description = NonEmptyString; -export type Description = t.TypeOf; - -// outcome is a property of the saved object resolve api -// will tell us info about the rule after 8.0 migrations -export const outcome = t.union([ - t.literal('exactMatch'), - t.literal('aliasMatch'), - t.literal('conflict'), -]); -export type Outcome = t.TypeOf; - -export const alias_target_id = t.string; -export const alias_purpose = t.union([ - t.literal('savedObjectConversion'), - t.literal('savedObjectImport'), -]); -export const enabled = t.boolean; -export type Enabled = t.TypeOf; -export const event_category_override = t.string; -export const eventCategoryOverrideOrUndefined = t.union([event_category_override, t.undefined]); - -export const tiebreaker_field = t.string; - -export const tiebreakerFieldOrUndefined = t.union([tiebreaker_field, t.undefined]); - -export const timestamp_field = t.string; - -export const timestampFieldOrUndefined = t.union([timestamp_field, t.undefined]); - -export const false_positives = t.array(t.string); +import { IsoDateString, PositiveInteger } from '@kbn/securitysolution-io-ts-types'; export const file_name = t.string; export type FileName = t.TypeOf; @@ -63,112 +16,13 @@ export type FileName = t.TypeOf; export const exclude_export_details = t.boolean; export type ExcludeExportDetails = t.TypeOf; -export const namespace = t.string; -export type Namespace = t.TypeOf; - -/** - * TODO: Right now the filters is an "unknown", when it could more than likely - * become the actual ESFilter as a type. - */ -export const filters = t.array(t.unknown); // Filters are not easily type-able yet -export type Filters = t.TypeOf; // Filters are not easily type-able yet - -export const filtersOrUndefined = t.union([filters, t.undefined]); -export type FiltersOrUndefined = t.TypeOf; - -export const immutable = t.boolean; -export type Immutable = t.TypeOf; - -// Note: Never make this a strict uuid, we allow the rule_id to be any string at the moment -// in case we encounter 3rd party rule systems which might be using auto incrementing numbers -// or other different things. -export const rule_id = t.string; -export type RuleId = t.TypeOf; - -export const ruleIdOrUndefined = t.union([rule_id, t.undefined]); -export type RuleIdOrUndefined = t.TypeOf; - -export const id = UUID; -export type Id = t.TypeOf; - -export const idOrUndefined = t.union([id, t.undefined]); -export type IdOrUndefined = t.TypeOf; - -export const index = t.array(t.string); -export type Index = t.TypeOf; - -export const data_view_id = t.string; - -export const dataViewIdOrUndefined = t.union([data_view_id, t.undefined]); - -export const indexOrUndefined = t.union([index, t.undefined]); -export type IndexOrUndefined = t.TypeOf; - -export const interval = t.string; -export type Interval = t.TypeOf; - -export const query = t.string; -export type Query = t.TypeOf; - -export const queryOrUndefined = t.union([query, t.undefined]); -export type QueryOrUndefined = t.TypeOf; - -export const license = t.string; -export type License = t.TypeOf; - -export const licenseOrUndefined = t.union([license, t.undefined]); - -export const objects = t.array(t.type({ rule_id })); - -export const output_index = t.string; - export const saved_id = t.string; export const savedIdOrUndefined = t.union([saved_id, t.undefined]); export type SavedIdOrUndefined = t.TypeOf; -export const timeline_id = t.string; -export type TimelineId = t.TypeOf; - -export const timelineIdOrUndefined = t.union([timeline_id, t.undefined]); - -export const timeline_title = t.string; - -export const timelineTitleOrUndefined = t.union([timeline_title, t.undefined]); - -export const timestamp_override = t.string; -export type TimestampOverride = t.TypeOf; - -export const timestampOverrideOrUndefined = t.union([timestamp_override, t.undefined]); -export type TimestampOverrideOrUndefined = t.TypeOf; - export const anomaly_threshold = PositiveInteger; -export const timestamp_override_fallback_disabled = t.boolean; - -export const timestampOverrideFallbackDisabledOrUndefined = t.union([ - timestamp_override_fallback_disabled, - t.undefined, -]); - -/** - * Note that this is a non-exact io-ts type as we allow extra meta information - * to be added to the meta object - */ -export const meta = t.object; -export type Meta = t.TypeOf; -export const metaOrUndefined = t.union([meta, t.undefined]); -export type MetaOrUndefined = t.TypeOf; - -export const name = NonEmptyString; -export type Name = t.TypeOf; - -export const rule_name_override = t.string; -export type RuleNameOverride = t.TypeOf; - -export const ruleNameOverrideOrUndefined = t.union([rule_name_override, t.undefined]); -export type RuleNameOverrideOrUndefined = t.TypeOf; - export const status = t.keyof({ open: null, closed: null, @@ -179,122 +33,34 @@ export type Status = t.TypeOf; export const conflicts = t.keyof({ abort: null, proceed: null }); -// TODO: Create a regular expression type or custom date math part type here -export const to = t.string; -export type To = t.TypeOf; - export const queryFilter = t.string; export type QueryFilter = t.TypeOf; export const queryFilterOrUndefined = t.union([queryFilter, t.undefined]); export type QueryFilterOrUndefined = t.TypeOf; -export const references = t.array(t.string); -export type References = t.TypeOf; - export const signal_ids = t.array(t.string); export type SignalIds = t.TypeOf; // TODO: Can this be more strict or is this is the set of all Elastic Queries? export const signal_status_query = t.object; -export const tags = t.array(t.string); -export type Tags = t.TypeOf; - export const fields = t.array(t.string); export type Fields = t.TypeOf; export const fieldsOrUndefined = t.union([fields, t.undefined]); export type FieldsOrUndefined = t.TypeOf; -export const thresholdField = t.exact( - t.type({ - field: t.union([t.string, t.array(t.string)]), // Covers pre- and post-7.12 - value: PositiveIntegerGreaterThanZero, - }) -); - -export const thresholdFieldNormalized = t.exact( - t.type({ - field: t.array(t.string), - value: PositiveIntegerGreaterThanZero, - }) -); - -export const thresholdCardinalityField = t.exact( - t.type({ - field: t.string, - value: PositiveInteger, - }) -); - -export const threshold = t.intersection([ - thresholdField, - t.exact( - t.partial({ - cardinality: t.array(thresholdCardinalityField), - }) - ), -]); -export type Threshold = t.TypeOf; - -export const thresholdNormalized = t.intersection([ - thresholdFieldNormalized, - t.exact( - t.partial({ - cardinality: t.array(thresholdCardinalityField), - }) - ), -]); -export type ThresholdNormalized = t.TypeOf; - -export const thresholdWithCardinality = t.intersection([ - thresholdFieldNormalized, - t.exact( - t.type({ - cardinality: t.array(thresholdCardinalityField), - }) - ), -]); -export type ThresholdWithCardinality = t.TypeOf; - -// New terms rule type currently only supports a single term, but should support more in the future -export const newTermsFields = LimitedSizeArray({ codec: t.string, minSize: 1, maxSize: 1 }); -export type NewTermsFields = t.TypeOf; - -export const historyWindowStart = NonEmptyString; -export type HistoryWindowStart = t.TypeOf; - export const created_at = IsoDateString; - export const updated_at = IsoDateString; - -export const updated_by = t.string; - export const created_by = t.string; +export const updated_by = t.string; -export const rules_installed = PositiveInteger; -export const rules_updated = PositiveInteger; export const status_code = PositiveInteger; export const message = t.string; export const perPage = PositiveInteger; export const total = PositiveInteger; export const success = t.boolean; export const success_count = PositiveInteger; -export const rules_custom_installed = PositiveInteger; -export const rules_not_installed = PositiveInteger; -export const rules_not_updated = PositiveInteger; - -export const timelines_installed = PositiveInteger; -export const timelines_updated = PositiveInteger; -export const timelines_not_installed = PositiveInteger; -export const timelines_not_updated = PositiveInteger; - -export const note = t.string; -export type Note = t.TypeOf; - -export const namespaceOrUndefined = t.union([namespace, t.undefined]); - -export const noteOrUndefined = t.union([note, t.undefined]); export const indexRecord = t.record( t.string, diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rule_exception_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rule_exception_schema.ts deleted file mode 100644 index e2d23d21abd53..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rule_exception_schema.ts +++ /dev/null @@ -1,28 +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 type { CreateRuleExceptionListItemSchemaDecoded } from '@kbn/securitysolution-io-ts-list-types'; -import { createRuleExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import type { RequiredKeepUndefined } from '@kbn/osquery-plugin/common/types'; - -export const createRuleExceptionsSchema = t.exact( - t.type({ - items: t.array(createRuleExceptionListItemSchema), - }) -); - -export type CreateRuleExceptionSchema = t.TypeOf; - -// This type is used after a decode since some things are defaults after a decode. -export type CreateRuleExceptionSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'items' -> & { - items: CreateRuleExceptionListItemSchemaDecoded[]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_type_dependents.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_type_dependents.ts deleted file mode 100644 index c429656d575f8..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_type_dependents.ts +++ /dev/null @@ -1,76 +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 { CreateRulesSchema } from './rule_schemas'; - -export const validateTimelineId = (rule: CreateRulesSchema): string[] => { - if (rule.timeline_id != null) { - if (rule.timeline_title == null) { - return ['when "timeline_id" exists, "timeline_title" must also exist']; - } else if (rule.timeline_id === '') { - return ['"timeline_id" cannot be an empty string']; - } else { - return []; - } - } - return []; -}; - -export const validateTimelineTitle = (rule: CreateRulesSchema): string[] => { - if (rule.timeline_title != null) { - if (rule.timeline_id == null) { - return ['when "timeline_title" exists, "timeline_id" must also exist']; - } else if (rule.timeline_title === '') { - return ['"timeline_title" cannot be an empty string']; - } else { - return []; - } - } - return []; -}; - -export const validateThreatMapping = (rule: CreateRulesSchema): string[] => { - const errors: string[] = []; - if (rule.type === 'threat_match') { - if (rule.concurrent_searches != null && rule.items_per_search == null) { - errors.push('when "concurrent_searches" exists, "items_per_search" must also exist'); - } - if (rule.concurrent_searches == null && rule.items_per_search != null) { - errors.push('when "items_per_search" exists, "concurrent_searches" must also exist'); - } - } - return errors; -}; - -export const validateThreshold = (rule: CreateRulesSchema): string[] => { - const errors: string[] = []; - if (rule.type === 'threshold') { - if (!rule.threshold) { - errors.push('when "type" is "threshold", "threshold" is required'); - } else { - if ( - rule.threshold.cardinality?.length && - rule.threshold.field.includes(rule.threshold.cardinality[0].field) - ) { - errors.push('Cardinality of a field that is being aggregated on is always 1'); - } - if (Array.isArray(rule.threshold.field) && rule.threshold.field.length > 3) { - errors.push('Number of fields must be 3 or less'); - } - } - } - return errors; -}; - -export const createRuleValidateTypeDependents = (rule: CreateRulesSchema): string[] => { - return [ - ...validateTimelineId(rule), - ...validateTimelineTitle(rule), - ...validateThreatMapping(rule), - ...validateThreshold(rule), - ]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_signals_migration_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_signals_migration_schema.ts index 55267c27ee37f..1eba4855bf0d3 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_signals_migration_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_signals_migration_schema.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; import { PositiveInteger, PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; -import { index } from '../common/schemas'; +import { IndexPatternArray } from '../../rule_schema'; export const signalsReindexOptions = t.partial({ requests_per_second: t.number, @@ -21,7 +21,7 @@ export type SignalsReindexOptions = t.TypeOf; export const createSignalsMigrationSchema = t.intersection([ t.exact( t.type({ - index, + index: IndexPatternArray, }) ), t.exact(signalsReindexOptions), diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/export_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/export_rules_schema.ts deleted file mode 100644 index 9541d37c78049..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/export_rules_schema.ts +++ /dev/null @@ -1,32 +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 { DefaultExportFileName } from '@kbn/securitysolution-io-ts-alerting-types'; -import { DefaultStringBooleanFalse } from '@kbn/securitysolution-io-ts-types'; -import type { FileName, ExcludeExportDetails } from '../common/schemas'; -import { rule_id } from '../common/schemas'; - -const objects = t.array(t.exact(t.type({ rule_id }))); -export const exportRulesSchema = t.union([t.exact(t.type({ objects })), t.null]); -export type ExportRulesSchema = t.TypeOf; -export type ExportRulesSchemaDecoded = ExportRulesSchema; - -export const exportRulesQuerySchema = t.exact( - t.partial({ file_name: DefaultExportFileName, exclude_export_details: DefaultStringBooleanFalse }) -); - -export type ExportRulesQuerySchema = t.TypeOf; - -export type ExportRulesQuerySchemaDecoded = Omit< - ExportRulesQuerySchema, - 'file_name' | 'exclude_export_details' -> & { - file_name: FileName; - exclude_export_details: ExcludeExportDetails; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rule_type_dependents.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rule_type_dependents.test.ts deleted file mode 100644 index 50afe7f970acb..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rule_type_dependents.test.ts +++ /dev/null @@ -1,46 +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 { FindRulesSchema } from './find_rules_schema'; -import { findRuleValidateTypeDependents } from './find_rules_type_dependents'; - -describe('find_rules_type_dependents', () => { - test('You can have an empty sort_field and empty sort_order', () => { - const schema: FindRulesSchema = {}; - const errors = findRuleValidateTypeDependents(schema); - expect(errors).toEqual([]); - }); - - test('You can have both a sort_field and and a sort_order', () => { - const schema: FindRulesSchema = { - sort_field: 'some field', - sort_order: 'asc', - }; - const errors = findRuleValidateTypeDependents(schema); - expect(errors).toEqual([]); - }); - - test('You cannot have sort_field without sort_order', () => { - const schema: FindRulesSchema = { - sort_field: 'some field', - }; - const errors = findRuleValidateTypeDependents(schema); - expect(errors).toEqual([ - 'when "sort_order" and "sort_field" must exist together or not at all', - ]); - }); - - test('You cannot have sort_order without sort_field', () => { - const schema: FindRulesSchema = { - sort_order: 'asc', - }; - const errors = findRuleValidateTypeDependents(schema); - expect(errors).toEqual([ - 'when "sort_order" and "sort_field" must exist together or not at all', - ]); - }); -}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_type_dependents.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_type_dependents.ts deleted file mode 100644 index f9bd6dc56f104..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rules_type_dependents.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 { FindRulesSchema } from './find_rules_schema'; - -export const validateSortOrder = (find: FindRulesSchema): string[] => { - if (find.sort_order != null || find.sort_field != null) { - if (find.sort_order == null || find.sort_field == null) { - return ['when "sort_order" and "sort_field" must exist together or not at all']; - } else { - return []; - } - } else { - return []; - } -}; - -export const findRuleValidateTypeDependents = (schema: FindRulesSchema): string[] => { - return [...validateSortOrder(schema)]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_signals_migration_status_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_signals_migration_status_schema.ts index c0969768d8be6..f2a9fc210df2b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_signals_migration_status_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_signals_migration_status_schema.ts @@ -7,11 +7,11 @@ import * as t from 'io-ts'; -import { from } from '@kbn/securitysolution-io-ts-alerting-types'; +import { RuleIntervalFrom } from '@kbn/securitysolution-io-ts-alerting-types'; export const getSignalsMigrationStatusSchema = t.exact( t.type({ - from, + from: RuleIntervalFrom, }) ); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_type_dependents.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_type_dependents.test.ts deleted file mode 100644 index cd7ec37a85edb..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_type_dependents.test.ts +++ /dev/null @@ -1,52 +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 { getImportRulesSchemaMock } from './import_rules_schema.mock'; -import type { ImportRulesSchema } from './import_rules_schema'; -import { importRuleValidateTypeDependents } from './import_rules_type_dependents'; - -describe('import_rules_type_dependents', () => { - test('You cannot omit timeline_title when timeline_id is present', () => { - const schema: ImportRulesSchema = { - ...getImportRulesSchemaMock(), - timeline_id: '123', - }; - delete schema.timeline_title; - const errors = importRuleValidateTypeDependents(schema); - expect(errors).toEqual(['when "timeline_id" exists, "timeline_title" must also exist']); - }); - - test('You cannot have empty string for timeline_title when timeline_id is present', () => { - const schema: ImportRulesSchema = { - ...getImportRulesSchemaMock(), - timeline_id: '123', - timeline_title: '', - }; - const errors = importRuleValidateTypeDependents(schema); - expect(errors).toEqual(['"timeline_title" cannot be an empty string']); - }); - - test('You cannot have timeline_title with an empty timeline_id', () => { - const schema: ImportRulesSchema = { - ...getImportRulesSchemaMock(), - timeline_id: '', - timeline_title: 'some-title', - }; - const errors = importRuleValidateTypeDependents(schema); - expect(errors).toEqual(['"timeline_id" cannot be an empty string']); - }); - - test('You cannot have timeline_title without timeline_id', () => { - const schema: ImportRulesSchema = { - ...getImportRulesSchemaMock(), - timeline_title: 'some-title', - }; - delete schema.timeline_id; - const errors = importRuleValidateTypeDependents(schema); - expect(errors).toEqual(['when "timeline_title" exists, "timeline_id" must also exist']); - }); -}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/index.ts index 6e77066299249..56ea598c58b0d 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/index.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/index.ts @@ -5,18 +5,5 @@ * 2.0. */ -export * from './add_prepackaged_rules_schema'; -export * from './create_rules_bulk_schema'; -export * from './create_rule_exception_schema'; -export * from './export_rules_schema'; -export * from './find_rules_schema'; -export * from './import_rules_schema'; -export * from './patch_rules_bulk_schema'; -export * from './patch_rules_schema'; -export * from './perform_bulk_action_schema'; -export * from './query_rule_by_id_schema'; -export * from './query_rules_schema'; export * from './query_signals_index_schema'; -export * from './rule_schemas'; export * from './set_signal_status_schema'; -export * from './update_rules_bulk_schema'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts deleted file mode 100644 index 5f4f5a4b16891..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.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 * as t from 'io-ts'; - -import { patchTypeSpecific, sharedPatchSchema, thresholdPatchParams } from './rule_schemas'; - -/** - * All of the patch elements should default to undefined if not set - */ -export const patchRulesSchema = t.intersection([patchTypeSpecific, sharedPatchSchema]); -export type PatchRulesSchema = t.TypeOf; - -const thresholdPatchSchema = t.intersection([thresholdPatchParams, sharedPatchSchema]); -export type ThresholdPatchSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_type_dependents.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_type_dependents.test.ts deleted file mode 100644 index abb64ec5522f2..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_type_dependents.test.ts +++ /dev/null @@ -1,117 +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 { - getPatchRulesSchemaMock, - getPatchThresholdRulesSchemaMock, -} from './patch_rules_schema.mock'; -import type { PatchRulesSchema, ThresholdPatchSchema } from './patch_rules_schema'; -import { patchRuleValidateTypeDependents } from './patch_rules_type_dependents'; - -describe('patch_rules_type_dependents', () => { - test('You cannot omit timeline_title when timeline_id is present', () => { - const schema: PatchRulesSchema = { - ...getPatchRulesSchemaMock(), - timeline_id: '123', - }; - delete schema.timeline_title; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['when "timeline_id" exists, "timeline_title" must also exist']); - }); - - test('You cannot have empty string for timeline_title when timeline_id is present', () => { - const schema: PatchRulesSchema = { - ...getPatchRulesSchemaMock(), - timeline_id: '123', - timeline_title: '', - }; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['"timeline_title" cannot be an empty string']); - }); - - test('You cannot have timeline_title with an empty timeline_id', () => { - const schema: PatchRulesSchema = { - ...getPatchRulesSchemaMock(), - timeline_id: '', - timeline_title: 'some-title', - }; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['"timeline_id" cannot be an empty string']); - }); - - test('You cannot have timeline_title without timeline_id', () => { - const schema: PatchRulesSchema = { - ...getPatchRulesSchemaMock(), - timeline_title: 'some-title', - }; - delete schema.timeline_id; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['when "timeline_title" exists, "timeline_id" must also exist']); - }); - - test('You cannot have both an id and a rule_id', () => { - const schema: PatchRulesSchema = { - ...getPatchRulesSchemaMock(), - id: 'some-id', - rule_id: 'some-rule-id', - }; - const errors = patchRuleValidateTypeDependents(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: PatchRulesSchema = { - ...getPatchRulesSchemaMock(), - }; - delete schema.id; - delete schema.rule_id; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['either "id" or "rule_id" must be set']); - }); - - test('threshold.value is required and has to be bigger than 0 when type is threshold and validates with it', () => { - const schema: ThresholdPatchSchema = { - ...getPatchThresholdRulesSchemaMock(), - threshold: { - field: '', - value: -1, - }, - }; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['"threshold.value" has to be bigger than 0']); - }); - - test('threshold.field should contain 3 items or less', () => { - const schema: ThresholdPatchSchema = { - ...getPatchThresholdRulesSchemaMock(), - threshold: { - field: ['field-1', 'field-2', 'field-3', 'field-4'], - value: 1, - }, - }; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['Number of fields must be 3 or less']); - }); - - test('threshold.cardinality[0].field should not be in threshold.field', () => { - const schema: ThresholdPatchSchema = { - ...getPatchThresholdRulesSchemaMock(), - threshold: { - field: ['field-1', 'field-2', 'field-3'], - value: 1, - cardinality: [ - { - field: 'field-1', - value: 2, - }, - ], - }, - }; - const errors = patchRuleValidateTypeDependents(schema); - expect(errors).toEqual(['Cardinality of a field that is being aggregated on is always 1']); - }); -}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rule_by_id_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rule_by_id_schema.test.ts deleted file mode 100644 index 7266bebc8027d..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rule_by_id_schema.test.ts +++ /dev/null @@ -1,38 +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 { QueryRuleByIdSchema } from './query_rule_by_id_schema'; -import { queryRuleByIdSchema } from './query_rule_by_id_schema'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -describe('query_rule_by_id_schema', () => { - test('empty objects do not validate', () => { - const payload: Partial = {}; - - const decoded = queryRuleByIdSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('validates string for id', () => { - const payload: Partial = { - id: '4656dc92-5832-11ea-8e2d-0242ac130003', - }; - - const decoded = queryRuleByIdSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual({ - id: '4656dc92-5832-11ea-8e2d-0242ac130003', - }); - }); -}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_bulk_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_bulk_schema.ts deleted file mode 100644 index afa485687043f..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_rules_bulk_schema.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 * as t from 'io-ts'; - -import type { QueryRulesSchemaDecoded } from './query_rules_schema'; -import { queryRulesSchema } from './query_rules_schema'; - -export const queryRulesBulkSchema = t.array(queryRulesSchema); -export type QueryRulesBulkSchema = t.TypeOf; - -export type QueryRulesBulkSchemaDecoded = QueryRulesSchemaDecoded[]; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts deleted file mode 100644 index 61e28f1edb902..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts +++ /dev/null @@ -1,541 +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 { - actions, - from, - risk_score, - machine_learning_job_id, - risk_score_mapping, - threat_filters, - threat_query, - threat_mapping, - threat_index, - threat_indicator_path, - concurrent_searches, - items_per_search, - threats, - severity_mapping, - severity, - max_signals, - throttle, -} from '@kbn/securitysolution-io-ts-alerting-types'; -import { listArray } from '@kbn/securitysolution-io-ts-list-types'; -import { version } from '@kbn/securitysolution-io-ts-types'; - -import { RuleExecutionSummary } from '../../rule_monitoring'; -import { - id, - index, - data_view_id, - filters, - timestamp_field, - event_category_override, - tiebreaker_field, - building_block_type, - note, - license, - timeline_id, - timeline_title, - meta, - rule_name_override, - timestamp_override, - timestamp_override_fallback_disabled, - author, - description, - false_positives, - rule_id, - immutable, - output_index, - query, - to, - references, - saved_id, - threshold, - anomaly_threshold, - name, - tags, - interval, - enabled, - outcome, - alias_target_id, - alias_purpose, - updated_at, - updated_by, - created_at, - created_by, - namespace, - RelatedIntegrationArray, - RequiredFieldArray, - SetupGuide, - newTermsFields, - historyWindowStart, -} from '../common'; -import { ResponseActionArray } from '../../rule_response_actions/schemas'; - -export const createSchema = < - 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 patchSchema = < - 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), - ]); -}; - -type OrUndefined

    = { - [K in keyof P]: P[K] | t.UndefinedC; -}; - -export const responseSchema = < - 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 = Object.keys(optionalFields).reduce((acc, key) => { - acc[key] = t.union([optionalFields[key], t.undefined]); - return acc; - }, {}) as OrUndefined; - return t.intersection([ - t.exact(t.type(requiredFields)), - t.exact(t.type(optionalWithUndefined)), - t.exact(t.type(defaultableFields)), - ]); -}; - -export const buildAPISchemas = ( - params: APIParams -) => { - return { - create: createSchema(params.required, params.optional, params.defaultable), - patch: patchSchema(params.required, params.optional, params.defaultable), - response: responseSchema(params.required, params.optional, params.defaultable), - }; -}; - -interface APIParams< - Required extends t.Props, - Optional extends t.Props, - Defaultable extends t.Props -> { - required: Required; - optional: Optional; - defaultable: Defaultable; -} - -const baseParams = { - required: { - name, - description, - risk_score, - severity, - }, - optional: { - building_block_type, - note, - license, - outcome, - alias_target_id, - alias_purpose, - output_index, - timeline_id, - timeline_title, - meta, - rule_name_override, - timestamp_override, - timestamp_override_fallback_disabled, - namespace, - }, - defaultable: { - tags, - interval, - enabled, - throttle, - actions, - author, - false_positives, - from, - // maxSignals not used in ML rules but probably should be used - max_signals, - risk_score_mapping, - severity_mapping, - threat: threats, - to, - references, - version, - exceptions_list: listArray, - }, -}; -const { - create: baseCreateParams, - patch: basePatchParams, - response: baseResponseParams, -} = buildAPISchemas(baseParams); -export { baseCreateParams }; - -// "shared" types are the same across all rule types, and built from "baseParams" above -// with some variations for each route. These intersect with type specific schemas below -// to create the full schema for each route. -export const sharedCreateSchema = t.intersection([ - baseCreateParams, - t.exact(t.partial({ rule_id })), -]); -export type SharedCreateSchema = t.TypeOf; - -export const sharedUpdateSchema = t.intersection([ - baseCreateParams, - t.exact(t.partial({ rule_id })), - t.exact(t.partial({ id })), -]); -export type SharedUpdateSchema = t.TypeOf; - -export const sharedPatchSchema = t.intersection([ - basePatchParams, - t.exact(t.partial({ rule_id, id })), -]); - -// START type specific parameter definitions -// ----------------------------------------- -const eqlRuleParams = { - required: { - type: t.literal('eql'), - language: t.literal('eql'), - query, - }, - optional: { - index, - data_view_id, - filters, - timestamp_field, - event_category_override, - tiebreaker_field, - }, - defaultable: {}, -}; -const { - create: eqlCreateParams, - patch: eqlPatchParams, - response: eqlResponseParams, -} = buildAPISchemas(eqlRuleParams); -export { eqlCreateParams, eqlResponseParams }; - -const threatMatchRuleParams = { - required: { - type: t.literal('threat_match'), - query, - threat_query, - threat_mapping, - threat_index, - }, - optional: { - index, - data_view_id, - filters, - saved_id, - threat_filters, - threat_indicator_path, - threat_language: t.keyof({ kuery: null, lucene: null }), - concurrent_searches, - items_per_search, - }, - defaultable: { - language: t.keyof({ kuery: null, lucene: null }), - }, -}; -const { - create: threatMatchCreateParams, - patch: threatMatchPatchParams, - response: threatMatchResponseParams, -} = buildAPISchemas(threatMatchRuleParams); -export { threatMatchCreateParams, threatMatchResponseParams }; - -const queryRuleParams = { - required: { - type: t.literal('query'), - }, - optional: { - index, - data_view_id, - filters, - saved_id, - response_actions: ResponseActionArray, - }, - defaultable: { - query, - language: t.keyof({ kuery: null, lucene: null }), - }, -}; -const { - create: queryCreateParams, - patch: queryPatchParams, - response: queryResponseParams, -} = buildAPISchemas(queryRuleParams); - -export { queryCreateParams, queryResponseParams }; - -const savedQueryRuleParams = { - required: { - type: t.literal('saved_query'), - saved_id, - }, - optional: { - // Having language, query, and filters possibly defined adds more code confusion and probably user confusion - // if the saved object gets deleted for some reason - index, - data_view_id, - query, - filters, - response_actions: ResponseActionArray, - }, - defaultable: { - language: t.keyof({ kuery: null, lucene: null }), - }, -}; -const { - create: savedQueryCreateParams, - patch: savedQueryPatchParams, - response: savedQueryResponseParams, -} = buildAPISchemas(savedQueryRuleParams); - -export { savedQueryCreateParams, savedQueryResponseParams }; - -const thresholdRuleParams = { - required: { - type: t.literal('threshold'), - query, - threshold, - }, - optional: { - index, - data_view_id, - filters, - saved_id, - }, - defaultable: { - language: t.keyof({ kuery: null, lucene: null }), - }, -}; -const { - create: thresholdCreateParams, - patch: thresholdPatchParams, - response: thresholdResponseParams, -} = buildAPISchemas(thresholdRuleParams); - -export { thresholdCreateParams, thresholdResponseParams }; - -const machineLearningRuleParams = { - required: { - type: t.literal('machine_learning'), - anomaly_threshold, - machine_learning_job_id, - }, - optional: {}, - defaultable: {}, -}; -const { - create: machineLearningCreateParams, - patch: machineLearningPatchParams, - response: machineLearningResponseParams, -} = buildAPISchemas(machineLearningRuleParams); - -export { machineLearningCreateParams, machineLearningResponseParams }; - -const newTermsRuleParams = { - required: { - type: t.literal('new_terms'), - query, - new_terms_fields: newTermsFields, - history_window_start: historyWindowStart, - }, - optional: { - index, - data_view_id, - filters, - }, - defaultable: { - language: t.keyof({ kuery: null, lucene: null }), - }, -}; -const { - create: newTermsCreateParams, - patch: newTermsPatchParams, - response: newTermsResponseParams, -} = buildAPISchemas(newTermsRuleParams); - -export { newTermsCreateParams, newTermsResponseParams }; -// --------------------------------------- -// END type specific parameter definitions - -export const createTypeSpecific = t.union([ - eqlCreateParams, - threatMatchCreateParams, - queryCreateParams, - savedQueryCreateParams, - thresholdCreateParams, - machineLearningCreateParams, - newTermsCreateParams, -]); -export type CreateTypeSpecific = t.TypeOf; - -// Convenience types for building specific types of rules -type CreateSchema = SharedCreateSchema & T; -export type EqlCreateSchema = CreateSchema>; -export type ThreatMatchCreateSchema = CreateSchema>; -export type QueryCreateSchema = CreateSchema>; -export type SavedQueryCreateSchema = CreateSchema>; -export type ThresholdCreateSchema = CreateSchema>; -export type MachineLearningCreateSchema = CreateSchema< - t.TypeOf ->; -export type NewTermsCreateSchema = CreateSchema>; - -export const createRulesSchema = t.intersection([sharedCreateSchema, createTypeSpecific]); -export type CreateRulesSchema = t.TypeOf; -export const previewRulesSchema = t.intersection([ - sharedCreateSchema, - createTypeSpecific, - t.type({ invocationCount: t.number, timeframeEnd: t.string }), -]); -export type PreviewRulesSchema = t.TypeOf; - -type UpdateSchema = SharedUpdateSchema & T; -export type QueryUpdateSchema = UpdateSchema>; -export type MachineLearningUpdateSchema = UpdateSchema< - t.TypeOf ->; -export type NewTermsUpdateSchema = UpdateSchema>; - -export const patchTypeSpecific = t.union([ - eqlPatchParams, - threatMatchPatchParams, - queryPatchParams, - savedQueryPatchParams, - thresholdPatchParams, - machineLearningPatchParams, - newTermsPatchParams, -]); -export { - eqlPatchParams, - threatMatchPatchParams, - queryPatchParams, - savedQueryPatchParams, - thresholdPatchParams, - machineLearningPatchParams, - newTermsPatchParams, -}; - -export type EqlPatchParams = t.TypeOf; -export type ThreatMatchPatchParams = t.TypeOf; -export type QueryPatchParams = t.TypeOf; -export type SavedQueryPatchParams = t.TypeOf; -export type ThresholdPatchParams = t.TypeOf; -export type MachineLearningPatchParams = t.TypeOf; -export type NewTermsPatchParams = t.TypeOf; - -const responseTypeSpecific = t.union([ - eqlResponseParams, - threatMatchResponseParams, - queryResponseParams, - savedQueryResponseParams, - thresholdResponseParams, - machineLearningResponseParams, - newTermsResponseParams, -]); -export type ResponseTypeSpecific = t.TypeOf; - -export const updateRulesSchema = t.intersection([createTypeSpecific, sharedUpdateSchema]); -export type UpdateRulesSchema = t.TypeOf; - -const responseRequiredFields = { - id, - rule_id, - immutable, - updated_at, - updated_by, - created_at, - created_by, - - // 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: RelatedIntegrationArray, - required_fields: RequiredFieldArray, - setup: SetupGuide, -}; - -const responseOptionalFields = { - execution_summary: RuleExecutionSummary, -}; - -const sharedResponseSchema = t.intersection([ - baseResponseParams, - t.exact(t.type(responseRequiredFields)), - t.exact(t.partial(responseOptionalFields)), -]); -export type SharedResponseSchema = t.TypeOf; -export const fullResponseSchema = t.intersection([sharedResponseSchema, responseTypeSpecific]); -export type FullResponseSchema = t.TypeOf; - -// Convenience types for type specific responses -type ResponseSchema = SharedResponseSchema & T; -export type EqlResponseSchema = ResponseSchema>; -export type ThreatMatchResponseSchema = ResponseSchema>; -export type QueryResponseSchema = ResponseSchema>; -export type SavedQueryResponseSchema = ResponseSchema>; -export type ThresholdResponseSchema = ResponseSchema>; -export type MachineLearningResponseSchema = ResponseSchema< - t.TypeOf ->; -export type NewTermsResponseSchema = ResponseSchema>; - -export interface RulePreviewLogs { - errors: string[]; - warnings: string[]; - startedAt?: string; - duration: number; -} - -export interface PreviewResponse { - previewId: string | undefined; - logs: RulePreviewLogs[] | undefined; - isAborted: boolean | undefined; -} diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_type_dependents.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_type_dependents.ts deleted file mode 100644 index 518937193cc4f..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_type_dependents.ts +++ /dev/null @@ -1,73 +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 { UpdateRulesSchema } from './rule_schemas'; - -export const validateTimelineId = (rule: UpdateRulesSchema): string[] => { - if (rule.timeline_id != null) { - if (rule.timeline_title == null) { - return ['when "timeline_id" exists, "timeline_title" must also exist']; - } else if (rule.timeline_id === '') { - return ['"timeline_id" cannot be an empty string']; - } else { - return []; - } - } - return []; -}; - -export const validateTimelineTitle = (rule: UpdateRulesSchema): string[] => { - if (rule.timeline_title != null) { - if (rule.timeline_id == null) { - return ['when "timeline_title" exists, "timeline_id" must also exist']; - } else if (rule.timeline_title === '') { - return ['"timeline_title" cannot be an empty string']; - } else { - return []; - } - } - return []; -}; - -export const validateId = (rule: UpdateRulesSchema): 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) { - return ['either "id" or "rule_id" must be set']; - } else { - return []; - } -}; - -export const validateThreshold = (rule: UpdateRulesSchema): string[] => { - const errors: string[] = []; - if (rule.type === 'threshold') { - if (!rule.threshold) { - errors.push('when "type" is "threshold", "threshold" is required'); - } else { - if ( - rule.threshold.cardinality?.length && - rule.threshold.field.includes(rule.threshold.cardinality[0].field) - ) { - errors.push('Cardinality of a field that is being aggregated on is always 1'); - } - if (Array.isArray(rule.threshold.field) && rule.threshold.field.length > 3) { - errors.push('Number of fields must be 3 or less'); - } - } - } - return errors; -}; - -export const updateRuleValidateTypeDependents = (rule: UpdateRulesSchema): string[] => { - return [ - ...validateId(rule), - ...validateTimelineId(rule), - ...validateTimelineTitle(rule), - ...validateThreshold(rule), - ]; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/error_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/error_schema.ts index d6e1faa7a5180..2c1cf288afe03 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/error_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/error_schema.ts @@ -8,13 +8,19 @@ import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; import * as t from 'io-ts'; -import { rule_id, status_code, message } from '../common/schemas'; +import { RuleSignatureId } from '../../rule_schema'; +import { status_code, message } from '../common/schemas'; // We use id: t.string intentionally and _never_ the id from global schemas as // sometimes echo back out the id that the user gave us and it is not guaranteed // to be a UUID but rather just a string const partial = t.exact( - t.partial({ id: t.string, rule_id, list_id: NonEmptyString, item_id: NonEmptyString }) + t.partial({ + id: t.string, + rule_id: RuleSignatureId, + list_id: NonEmptyString, + item_id: NonEmptyString, + }) ); const required = t.exact( t.type({ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts index 5c934b0d2e040..b20a956525e2e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts @@ -6,9 +6,3 @@ */ export * from './error_schema'; -export * from './get_installed_integrations_response_schema'; -export * from './find_exception_list_references_schema'; -export * from './import_rules_schema'; -export * from './prepackaged_rules_schema'; -export * from './prepackaged_rules_status_schema'; -export * from './rules_bulk_schema'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_schema.ts deleted file mode 100644 index 50c36075a0cf2..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_schema.ts +++ /dev/null @@ -1,33 +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 { - rules_installed, - rules_updated, - timelines_installed, - timelines_updated, -} from '../common/schemas'; - -const prePackagedRulesSchema = t.type({ - rules_installed, - rules_updated, -}); - -const prePackagedTimelinesSchema = t.type({ - timelines_installed, - timelines_updated, -}); - -export const prePackagedRulesAndTimelinesSchema = t.exact( - t.intersection([prePackagedRulesSchema, prePackagedTimelinesSchema]) -); - -export type PrePackagedRulesAndTimelinesSchema = t.TypeOf< - typeof prePackagedRulesAndTimelinesSchema ->; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_status_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_status_schema.ts deleted file mode 100644 index 9f5cc5542bc7c..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/prepackaged_rules_status_schema.ts +++ /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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; - -import { - rules_installed, - rules_custom_installed, - rules_not_installed, - rules_not_updated, - timelines_installed, - timelines_not_installed, - timelines_not_updated, -} from '../common/schemas'; - -export const prePackagedTimelinesStatusSchema = t.type({ - timelines_installed, - timelines_not_installed, - timelines_not_updated, -}); - -const prePackagedRulesStatusSchema = t.type({ - rules_custom_installed, - rules_installed, - rules_not_installed, - rules_not_updated, -}); - -export const prePackagedRulesAndTimelinesStatusSchema = t.exact( - t.intersection([prePackagedRulesStatusSchema, prePackagedTimelinesStatusSchema]) -); - -export type PrePackagedRulesAndTimelinesStatusSchema = t.TypeOf< - typeof prePackagedRulesAndTimelinesStatusSchema ->; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_bulk_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_bulk_schema.ts deleted file mode 100644 index 65c55f356c44b..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_bulk_schema.ts +++ /dev/null @@ -1,14 +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 { fullResponseSchema } from '../request'; -import { errorSchema } from './error_schema'; - -export const rulesBulkSchema = t.array(t.union([fullResponseSchema, errorSchema])); -export type RulesBulkSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index afa5a3950921b..36f7ee8977f5f 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -16,7 +16,7 @@ import type { import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { hasLargeValueList } from '@kbn/securitysolution-list-utils'; -import type { Threshold, ThresholdNormalized } from './schemas/common'; +import type { Threshold, ThresholdNormalized } from './rule_schema'; export const hasLargeValueItem = ( exceptionItems: Array diff --git a/x-pack/plugins/security_solution/common/ecs/rule/index.ts b/x-pack/plugins/security_solution/common/ecs/rule/index.ts index 073bb7db3a3e8..c52a9253122dc 100644 --- a/x-pack/plugins/security_solution/common/ecs/rule/index.ts +++ b/x-pack/plugins/security_solution/common/ecs/rule/index.ts @@ -17,6 +17,7 @@ export interface RuleEcs { risk_score?: string[]; output_index?: string[]; description?: string[]; + exceptions_list?: string[]; from?: string[]; immutable?: boolean[]; index?: string[]; diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index 2d8f468233f0d..3aa4fe007a959 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -73,9 +73,14 @@ export const GET_FILE_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/get_file`; export const ENDPOINT_ACTION_LOG_ROUTE = `${BASE_ENDPOINT_ROUTE}/action_log/{agent_id}`; export const ACTION_STATUS_ROUTE = `${BASE_ENDPOINT_ROUTE}/action_status`; export const ACTION_DETAILS_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/{action_id}`; +export const ACTION_AGENT_FILE_DOWNLOAD_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/{action_id}/{agent_id}/file/download`; export const ENDPOINTS_ACTION_LIST_ROUTE = `${BASE_ENDPOINT_ROUTE}/action`; export const failedFleetActionErrorCode = '424'; export const ENDPOINT_DEFAULT_PAGE = 0; export const ENDPOINT_DEFAULT_PAGE_SIZE = 10; + +export const ENDPOINT_ERROR_CODES: Record = { + ES_CONNECTION_ERROR: -272, +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts index 127e69b862305..f8bc8f0a20a7b 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts @@ -14,9 +14,13 @@ import type { FleetServerAgent, FleetServerAgentComponentStatus, } from '@kbn/fleet-plugin/common'; -import { AGENTS_INDEX, FleetServerAgentComponentStatuses } from '@kbn/fleet-plugin/common'; +import { FleetServerAgentComponentStatuses, AGENTS_INDEX } from '@kbn/fleet-plugin/common'; +import moment from 'moment'; import { BaseDataGenerator } from './base_data_generator'; +import { ENDPOINT_ERROR_CODES } from '../constants'; +// List of computed (as in, done in code is kibana via +// https://github.com/elastic/kibana/blob/main/x-pack/plugins/fleet/common/services/agent_status.ts#L13-L44 const agentStatusList: readonly AgentStatus[] = [ 'offline', 'error', @@ -29,6 +33,13 @@ const agentStatusList: readonly AgentStatus[] = [ 'degraded', ]; +const lastCheckinStatusList: ReadonlyArray = [ + 'error', + 'online', + 'degraded', + 'updating', +]; + export class FleetAgentGenerator extends BaseDataGenerator { /** * @param [overrides] any partial value to the full Agent record @@ -81,7 +92,7 @@ export class FleetAgentGenerator extends BaseDataGenerator { componentStatus === 'failed' ? { error: { - code: 123, + code: ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR, message: 'Unable to connect to Elasticsearch', }, } @@ -138,8 +149,6 @@ export class FleetAgentGenerator extends BaseDataGenerator { policy_id: this.randomUUID(), type: 'PERMANENT', default_api_key: 'so3dWnkBj1tiuAw9yAm3:t7jNlnPnR6azEI_YpXuBXQ', - // policy_output_permissions_hash: - // '81b3d070dddec145fafcbdfb6f22888495a12edc31881f6b0511fa10de66daa7', default_api_key_id: 'so3dWnkBj1tiuAw9yAm3', updated_at: now, last_checkin: now, @@ -171,13 +180,76 @@ export class FleetAgentGenerator extends BaseDataGenerator { ], }, ], + last_checkin_status: this.randomChoice(lastCheckinStatusList), + upgraded_at: null, + upgrade_started_at: null, + unenrolled_at: undefined, + unenrollment_started_at: undefined, }, }, overrides ); } - private randomAgentStatus() { + generateEsHitWithStatus( + status: AgentStatus, + overrides: DeepPartial> = {} + ) { + const esHit = this.generateEsHit(overrides); + + // Basically: reverse engineer the Fleet `getAgentStatus()` utility: + // https://github.com/elastic/kibana/blob/main/x-pack/plugins/fleet/common/services/agent_status.ts#L13-L44 + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const fleetServerAgent = esHit._source!; + + // Reset the `last_checkin_status since we're controlling the agent status here + fleetServerAgent.last_checkin_status = 'online'; + + switch (status) { + case 'degraded': + fleetServerAgent.last_checkin_status = 'degraded'; + break; + + case 'enrolling': + fleetServerAgent.last_checkin = undefined; + + break; + case 'error': + fleetServerAgent.last_checkin_status = 'error'; + break; + + case 'inactive': + fleetServerAgent.active = false; + break; + + case 'offline': + // current fleet timeout interface for offline is 5 minutes + // https://github.com/elastic/kibana/blob/main/x-pack/plugins/fleet/common/services/agent_status.ts#L11 + fleetServerAgent.last_checkin = moment().subtract(6, 'minutes').toISOString(); + break; + + case 'unenrolling': + fleetServerAgent.unenrollment_started_at = fleetServerAgent.updated_at; + fleetServerAgent.unenrolled_at = undefined; + break; + + case 'updating': + fleetServerAgent.upgrade_started_at = fleetServerAgent.updated_at; + fleetServerAgent.upgraded_at = undefined; + break; + + case 'warning': + // NOt able to find anything in fleet + break; + + // default is `online`, which is also the default returned by `generateEsHit()` + } + + return esHit; + } + + public randomAgentStatus() { return this.randomChoice(agentStatusList); } } diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts b/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts index 1743b50ffecd0..cb9a1d98eb326 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts @@ -127,3 +127,15 @@ export const EndpointActionGetFileSchema = { }; export type ResponseActionGetFileRequestBody = TypeOf; + +/** Schema that validates the file download API */ +export const EndpointActionFileDownloadSchema = { + params: schema.object({ + action_id: schema.string({ minLength: 1 }), + agent_id: schema.string({ minLength: 1 }), + }), +}; + +export type EndpointActionFileDownloadParams = TypeOf< + typeof EndpointActionFileDownloadSchema.params +>; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/get_file_download_id.ts b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/get_file_download_id.ts new file mode 100644 index 0000000000000..12d74207c57b9 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/get_file_download_id.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 type { ActionDetails } from '../../types'; + +/** + * Constructs a file ID for a given agent. + * @param action + * @param agentId + */ +export const getFileDownloadId = (action: ActionDetails, agentId?: string): string => { + const { id: actionId, agents } = action; + + if (agentId && !agents.includes(agentId)) { + throw new Error(`Action [${actionId}] was not sent to agent id [${agentId}]`); + } + + return `${actionId}.${agentId ?? agents[0]}`; +}; diff --git a/x-pack/plugins/security_solution/common/types/timeline/index.ts b/x-pack/plugins/security_solution/common/types/timeline/index.ts index 938374b622e79..64621f0a0598d 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/index.ts @@ -14,8 +14,11 @@ import { NoteSavedObjectToReturnRuntimeType } from './note'; import type { PinnedEvent } from './pinned_event'; import { PinnedEventToReturnSavedObjectRuntimeType } from './pinned_event'; import { - alias_purpose as savedObjectResolveAliasPurpose, - outcome as savedObjectResolveOutcome, + SavedObjectResolveAliasPurpose, + SavedObjectResolveAliasTargetId, + SavedObjectResolveOutcome, +} from '../../detection_engine/rule_schema'; +import { success, success_count as successCount, } from '../../detection_engine/schemas/common/schemas'; @@ -375,11 +378,11 @@ export type SingleTimelineResponse = runtimeTypes.TypeOf { 'have.text', `Elastic rules (${expectedNumberOfRulesAfterDeletion})` ); - cy.get(RELOAD_PREBUILT_RULES_BTN).should('exist'); - cy.get(RELOAD_PREBUILT_RULES_BTN).should('have.text', 'Install 1 Elastic prebuilt rule '); + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).should('exist'); + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).should( + 'have.text', + 'Install 1 Elastic prebuilt rule ' + ); reloadDeletedRules(); - cy.get(RELOAD_PREBUILT_RULES_BTN).should('not.exist'); + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).should('not.exist'); cy.get(ELASTIC_RULES_BTN).should( 'have.text', @@ -134,8 +137,8 @@ describe('Prebuilt rules', () => { selectNumberOfRules(numberOfRulesToBeSelected); deleteSelectedRules(); - cy.get(RELOAD_PREBUILT_RULES_BTN).should('exist'); - cy.get(RELOAD_PREBUILT_RULES_BTN).should( + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).should('exist'); + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).should( 'have.text', `Install ${numberOfRulesToBeSelected} Elastic prebuilt rules ` ); @@ -146,7 +149,7 @@ describe('Prebuilt rules', () => { reloadDeletedRules(); - cy.get(RELOAD_PREBUILT_RULES_BTN).should('not.exist'); + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).should('not.exist'); cy.get(ELASTIC_RULES_BTN).should( 'have.text', diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_flyout.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/add_edit_flyout/flyout_validation.cy.ts similarity index 83% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_flyout.cy.ts rename to x-pack/plugins/security_solution/cypress/e2e/exceptions/add_edit_flyout/flyout_validation.cy.ts index 952325ab01559..fcde59d0bd79a 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_flyout.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/exceptions/add_edit_flyout/flyout_validation.cy.ts @@ -5,27 +5,32 @@ * 2.0. */ -import { getNewRule } from '../../objects/rule'; +import { getNewRule } from '../../../objects/rule'; -import { RULE_STATUS } from '../../screens/create_new_rule'; +import { RULE_STATUS } from '../../../screens/create_new_rule'; -import { createCustomRule } from '../../tasks/api_calls/rules'; -import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; -import { esArchiverLoad, esArchiverResetKibana, esArchiverUnload } from '../../tasks/es_archiver'; -import { login, visitWithoutDateRange } from '../../tasks/login'; +import { createCustomRule } from '../../../tasks/api_calls/rules'; +import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; +import { + esArchiverLoad, + esArchiverResetKibana, + esArchiverUnload, +} from '../../../tasks/es_archiver'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; import { openExceptionFlyoutFromEmptyViewerPrompt, goToExceptionsTab, openEditException, -} from '../../tasks/rule_details'; +} from '../../../tasks/rule_details'; import { addExceptionEntryFieldMatchAnyValue, addExceptionEntryFieldValue, addExceptionEntryFieldValueOfItemX, addExceptionEntryFieldValueValue, addExceptionEntryOperatorValue, + addExceptionFlyoutItemName, closeExceptionBuilderFlyout, -} from '../../tasks/exceptions'; +} from '../../../tasks/exceptions'; import { ADD_AND_BTN, ADD_OR_BTN, @@ -34,7 +39,6 @@ import { FIELD_INPUT, LOADING_SPINNER, EXCEPTION_ITEM_CONTAINER, - ADD_EXCEPTIONS_BTN_FROM_EMPTY_PROMPT_BTN, EXCEPTION_FIELD_LIST, EXCEPTION_EDIT_FLYOUT_SAVE_BTN, EXCEPTION_FLYOUT_VERSION_CONFLICT, @@ -42,17 +46,17 @@ import { CONFIRM_BTN, VALUES_INPUT, EXCEPTION_FLYOUT_TITLE, -} from '../../screens/exceptions'; +} from '../../../screens/exceptions'; -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation'; -import { reload } from '../../tasks/common'; +import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; +import { reload } from '../../../tasks/common'; import { createExceptionList, createExceptionListItem, updateExceptionListItem, deleteExceptionList, -} from '../../tasks/api_calls/exceptions'; -import { getExceptionList } from '../../objects/exception'; +} from '../../../tasks/api_calls/exceptions'; +import { getExceptionList } from '../../../objects/exception'; // NOTE: You might look at these tests and feel they're overkill, // but the exceptions flyout has a lot of logic making it difficult @@ -92,12 +96,11 @@ describe('Exceptions flyout', () => { }); it('Validates empty entry values correctly', () => { - cy.root() - .pipe(($el) => { - $el.find(ADD_EXCEPTIONS_BTN_FROM_EMPTY_PROMPT_BTN).trigger('click'); - return $el.find(ADD_AND_BTN); - }) - .should('be.visible'); + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); + + // add exception item name + addExceptionFlyoutItemName('My item name'); // add an entry with a value and submit button should enable addExceptionEntryFieldValue('agent.name', 0); @@ -120,13 +123,27 @@ describe('Exceptions flyout', () => { closeExceptionBuilderFlyout(); }); + it('Validates custom fields correctly', () => { + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); + + // add exception item name + addExceptionFlyoutItemName('My item name'); + + // add an entry with a value and submit button should enable + addExceptionEntryFieldValue('blooberty', 0); + addExceptionEntryFieldValueValue('blah', 0); + cy.get(CONFIRM_BTN).should('be.enabled'); + + closeExceptionBuilderFlyout(); + }); + it('Does not overwrite values and-ed together', () => { - cy.root() - .pipe(($el) => { - $el.find(ADD_EXCEPTIONS_BTN_FROM_EMPTY_PROMPT_BTN).trigger('click'); - return $el.find(ADD_AND_BTN); - }) - .should('be.visible'); + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); + + // add exception item name + addExceptionFlyoutItemName('My item name'); // add multiple entries with invalid field values addExceptionEntryFieldValue('agent.name', 0); @@ -144,12 +161,12 @@ describe('Exceptions flyout', () => { }); it('Does not overwrite values or-ed together', () => { - cy.root() - .pipe(($el) => { - $el.find(ADD_EXCEPTIONS_BTN_FROM_EMPTY_PROMPT_BTN).trigger('click'); - return $el.find(ADD_AND_BTN); - }) - .should('be.visible'); + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); + + // add exception item name + addExceptionFlyoutItemName('My item name'); + // exception item 1 addExceptionEntryFieldValueOfItemX('agent.name', 0, 0); cy.get(ADD_AND_BTN).click(); @@ -265,19 +282,17 @@ describe('Exceptions flyout', () => { }); it('Contains custom index fields', () => { - cy.root() - .pipe(($el) => { - $el.find(ADD_EXCEPTIONS_BTN_FROM_EMPTY_PROMPT_BTN).trigger('click'); - return $el.find(ADD_AND_BTN); - }) - .should('be.visible'); + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); + cy.get(FIELD_INPUT).eq(0).click({ force: true }); cy.get(EXCEPTION_FIELD_LIST).contains('unique_value.test'); closeExceptionBuilderFlyout(); }); - describe('flyout errors', () => { + // TODO - Add back in error states into modal + describe.skip('flyout errors', () => { beforeEach(() => { // create exception item via api createExceptionListItem(getExceptionList().list_id, { diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/add_exception.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/add_exception.cy.ts index f1d6d2f1cc063..213ea64fc4ceb 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/add_exception.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/add_exception.cy.ts @@ -5,98 +5,190 @@ * 2.0. */ -import { getException } from '../../../objects/exception'; +import { ROLES } from '../../../../common/test'; +import { getExceptionList, expectedExportedExceptionList } from '../../../objects/exception'; import { getNewRule } from '../../../objects/rule'; -import { ALERTS_COUNT, EMPTY_ALERT_TABLE, NUMBER_OF_ALERTS } from '../../../screens/alerts'; +import { createCustomRule } from '../../../tasks/api_calls/rules'; +import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../../tasks/login'; +import { EXCEPTIONS_URL } from '../../../urls/navigation'; import { - addExceptionFromFirstAlert, - goToClosedAlerts, - goToOpenedAlerts, -} from '../../../tasks/alerts'; -import { createCustomRuleEnabled } from '../../../tasks/api_calls/rules'; -import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; + deleteExceptionListWithRuleReference, + deleteExceptionListWithoutRuleReference, + exportExceptionList, + searchForExceptionList, + waitForExceptionsTableToBeLoaded, + clearSearchSelection, +} from '../../../tasks/exceptions_table'; import { - esArchiverLoad, - esArchiverUnload, - esArchiverResetKibana, -} from '../../../tasks/es_archiver'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { - addsException, - goToAlertsTab, - goToExceptionsTab, - removeException, - waitForTheRuleToBeExecuted, -} from '../../../tasks/rule_details'; - -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; -import { deleteAlertsAndRules } from '../../../tasks/common'; + EXCEPTIONS_TABLE_DELETE_BTN, + EXCEPTIONS_TABLE_LIST_NAME, + EXCEPTIONS_TABLE_SHOWING_LISTS, +} from '../../../screens/exceptions'; +import { createExceptionList } from '../../../tasks/api_calls/exceptions'; +import { esArchiverResetKibana } from '../../../tasks/es_archiver'; +import { TOASTER } from '../../../screens/alerts_detection_rules'; -describe('Adds rule exception from alerts flow', () => { - const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; +const getExceptionList1 = () => ({ + ...getExceptionList(), + name: 'Test a new list 1', + list_id: 'exception_list_1', +}); +const getExceptionList2 = () => ({ + ...getExceptionList(), + name: 'Test list 2', + list_id: 'exception_list_2', +}); +describe('Exceptions Table', () => { before(() => { esArchiverResetKibana(); - esArchiverLoad('exceptions'); login(); - }); - beforeEach(() => { - deleteAlertsAndRules(); - createCustomRuleEnabled( - { + // Create exception list associated with a rule + createExceptionList(getExceptionList2(), getExceptionList2().list_id).then((response) => + createCustomRule({ ...getNewRule(), - customQuery: 'agent.name:*', - dataSource: { index: ['exceptions*'], type: 'indexPatterns' }, - }, - 'rule_testing', - '1s' + exceptionLists: [ + { + id: response.body.id, + list_id: getExceptionList2().list_id, + type: getExceptionList2().type, + namespace_type: getExceptionList2().namespace_type, + }, + ], + }) ); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(); + + // Create exception list not used by any rules + createExceptionList(getExceptionList1(), getExceptionList1().list_id).as( + 'exceptionListResponse' + ); + + visitWithoutDateRange(EXCEPTIONS_URL); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); + }); + + it('Exports exception list', function () { + cy.intercept(/(\/api\/exception_lists\/_export)/).as('export'); + + visitWithoutDateRange(EXCEPTIONS_URL); + waitForExceptionsTableToBeLoaded(); + exportExceptionList(); + + cy.wait('@export').then(({ response }) => { + cy.wrap(response?.body).should( + 'eql', + expectedExportedExceptionList(this.exceptionListResponse) + ); + + cy.get(TOASTER).should('have.text', 'Exception list export success'); + }); + }); + + it('Filters exception lists on search', () => { + visitWithoutDateRange(EXCEPTIONS_URL); + waitForExceptionsTableToBeLoaded(); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); + + // Single word search + searchForExceptionList('Endpoint'); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1'); + cy.get(EXCEPTIONS_TABLE_LIST_NAME).should('have.text', 'Endpoint Security Exception List'); + + // Multi word search + clearSearchSelection(); + searchForExceptionList('test'); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2'); + cy.get(EXCEPTIONS_TABLE_LIST_NAME).eq(1).should('have.text', 'Test list 2'); + cy.get(EXCEPTIONS_TABLE_LIST_NAME).eq(0).should('have.text', 'Test a new list 1'); + + // Exact phrase search + clearSearchSelection(); + searchForExceptionList(`"${getExceptionList1().name}"`); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1'); + cy.get(EXCEPTIONS_TABLE_LIST_NAME).should('have.text', getExceptionList1().name); + + // Field search + clearSearchSelection(); + searchForExceptionList('list_id:endpoint_list'); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1'); + cy.get(EXCEPTIONS_TABLE_LIST_NAME).should('have.text', 'Endpoint Security Exception List'); + + clearSearchSelection(); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); + }); + + it('Deletes exception list without rule reference', () => { + visitWithoutDateRange(EXCEPTIONS_URL); + waitForExceptionsTableToBeLoaded(); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); + + deleteExceptionListWithoutRuleReference(); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2'); }); - afterEach(() => { - esArchiverUnload('exceptions_2'); + it('Deletes exception list with rule reference', () => { + waitForPageWithoutDateRange(EXCEPTIONS_URL); + waitForExceptionsTableToBeLoaded(); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2'); + + deleteExceptionListWithRuleReference(); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1'); }); +}); + +describe('Exceptions Table - read only', () => { + before(() => { + // First we login as a privileged user to create exception list + esArchiverResetKibana(); + login(ROLES.platform_engineer); + visitWithoutDateRange(EXCEPTIONS_URL, ROLES.platform_engineer); + createExceptionList(getExceptionList(), getExceptionList().list_id); + + // Then we login as read-only user to test. + login(ROLES.reader); + visitWithoutDateRange(EXCEPTIONS_URL, ROLES.reader); + waitForExceptionsTableToBeLoaded(); - after(() => { - esArchiverUnload('exceptions'); + cy.get(EXCEPTIONS_TABLE_SHOWING_LISTS).should('have.text', `Showing 1 list`); }); - it('Creates an exception from an alert and deletes it', () => { - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS); - // Create an exception from the alerts actions menu that matches - // the existing alert - addExceptionFromFirstAlert(); - addsException(getException()); - - // Alerts table should now be empty from having added exception and closed - // matching alert - cy.get(EMPTY_ALERT_TABLE).should('exist'); - - // Closed alert should appear in table - goToClosedAlerts(); - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`); - - // Remove the exception and load an event that would have matched that exception - // to show that said exception now starts to show up again - goToExceptionsTab(); - removeException(); - esArchiverLoad('exceptions_2'); - goToAlertsTab(); - goToOpenedAlerts(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(); - - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', '2 alerts'); + it('Delete icon is not shown', () => { + cy.get(EXCEPTIONS_TABLE_DELETE_BTN).should('not.exist'); }); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_table.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_management_flow/exceptions_table.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_table.cy.ts rename to x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_management_flow/exceptions_table.cy.ts index b037c4f6d62ce..213ea64fc4ceb 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_table.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/exceptions/exceptions_management_flow/exceptions_table.cy.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { ROLES } from '../../../common/test'; -import { getExceptionList, expectedExportedExceptionList } from '../../objects/exception'; -import { getNewRule } from '../../objects/rule'; +import { ROLES } from '../../../../common/test'; +import { getExceptionList, expectedExportedExceptionList } from '../../../objects/exception'; +import { getNewRule } from '../../../objects/rule'; -import { createCustomRule } from '../../tasks/api_calls/rules'; -import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../tasks/login'; +import { createCustomRule } from '../../../tasks/api_calls/rules'; +import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../../tasks/login'; -import { EXCEPTIONS_URL } from '../../urls/navigation'; +import { EXCEPTIONS_URL } from '../../../urls/navigation'; import { deleteExceptionListWithRuleReference, deleteExceptionListWithoutRuleReference, @@ -20,15 +20,15 @@ import { searchForExceptionList, waitForExceptionsTableToBeLoaded, clearSearchSelection, -} from '../../tasks/exceptions_table'; +} from '../../../tasks/exceptions_table'; import { EXCEPTIONS_TABLE_DELETE_BTN, EXCEPTIONS_TABLE_LIST_NAME, EXCEPTIONS_TABLE_SHOWING_LISTS, -} from '../../screens/exceptions'; -import { createExceptionList } from '../../tasks/api_calls/exceptions'; -import { esArchiverResetKibana } from '../../tasks/es_archiver'; -import { TOASTER } from '../../screens/alerts_detection_rules'; +} from '../../../screens/exceptions'; +import { createExceptionList } from '../../../tasks/api_calls/exceptions'; +import { esArchiverResetKibana } from '../../../tasks/es_archiver'; +import { TOASTER } from '../../../screens/alerts_detection_rules'; const getExceptionList1 = () => ({ ...getExceptionList(), diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts new file mode 100644 index 0000000000000..da975710c7f39 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts @@ -0,0 +1,179 @@ +/* + * 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 { getNewRule } from '../../../objects/rule'; + +import { createCustomRule } from '../../../tasks/api_calls/rules'; +import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; +import { + esArchiverLoad, + esArchiverResetKibana, + esArchiverUnload, +} from '../../../tasks/es_archiver'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; +import { + goToEndpointExceptionsTab, + openEditException, + openExceptionFlyoutFromEmptyViewerPrompt, + searchForExceptionItem, +} from '../../../tasks/rule_details'; +import { + addExceptionConditions, + addExceptionFlyoutItemName, + editException, + editExceptionFlyoutItemName, + selectOs, + submitEditedExceptionItem, + submitNewExceptionItem, +} from '../../../tasks/exceptions'; + +import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; +import { deleteAlertsAndRules } from '../../../tasks/common'; +import { + NO_EXCEPTIONS_EXIST_PROMPT, + EXCEPTION_ITEM_VIEWER_CONTAINER, + NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT, + CLOSE_ALERTS_CHECKBOX, + CONFIRM_BTN, + ADD_TO_RULE_OR_LIST_SECTION, + CLOSE_SINGLE_ALERT_CHECKBOX, + EXCEPTION_ITEM_CONTAINER, + VALUES_INPUT, + FIELD_INPUT, + EXCEPTION_CARD_ITEM_NAME, + EXCEPTION_CARD_ITEM_CONDITIONS, +} from '../../../screens/exceptions'; +import { createEndpointExceptionList } from '../../../tasks/api_calls/exceptions'; + +describe('Add endpoint exception from rule details', () => { + const ITEM_NAME = 'Sample Exception List Item'; + + before(() => { + esArchiverResetKibana(); + esArchiverLoad('auditbeat'); + login(); + }); + + before(() => { + deleteAlertsAndRules(); + // create rule with exception + createEndpointExceptionList().then((response) => { + createCustomRule( + { + ...getNewRule(), + customQuery: 'event.code:*', + dataSource: { index: ['auditbeat*'], type: 'indexPatterns' }, + exceptionLists: [ + { + id: response.body.id, + list_id: response.body.list_id, + type: response.body.type, + namespace_type: response.body.namespace_type, + }, + ], + }, + '2' + ); + }); + + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + goToRuleDetails(); + goToEndpointExceptionsTab(); + }); + + after(() => { + esArchiverUnload('auditbeat'); + }); + + it('creates an exception item', () => { + // when no exceptions exist, empty component shows with action to add exception + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); + + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); + + // for endpoint exceptions, must specify OS + selectOs('windows'); + + // add exception item conditions + addExceptionConditions({ + field: 'event.code', + operator: 'is', + values: ['foo'], + }); + + // Name is required so want to check that submit is still disabled + cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); + + // add exception item name + addExceptionFlyoutItemName(ITEM_NAME); + + // Option to add to rule or add to list should NOT appear + cy.get(ADD_TO_RULE_OR_LIST_SECTION).should('not.exist'); + + // not testing close alert functionality here, just ensuring that the options appear as expected + cy.get(CLOSE_SINGLE_ALERT_CHECKBOX).should('not.exist'); + cy.get(CLOSE_ALERTS_CHECKBOX).should('exist'); + + // submit + submitNewExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + }); + + it('edits an endpoint exception item', () => { + const NEW_ITEM_NAME = 'Exception item-EDITED'; + const ITEM_FIELD = 'event.code'; + const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; + + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ` ${ITEM_FIELD}IS foo`); + + // open edit exception modal + openEditException(); + + // edit exception item name + editExceptionFlyoutItemName(NEW_ITEM_NAME); + + // check that the existing item's field is being populated + cy.get(EXCEPTION_ITEM_CONTAINER).eq(0).find(FIELD_INPUT).eq(0).should('have.text', ITEM_FIELD); + cy.get(VALUES_INPUT).should('have.text', 'foo'); + + // edit conditions + editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); + + // submit + submitEditedExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // check that updates stuck + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.nameIS foo'); + }); + + it('allows user to search for items', () => { + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // can search for an exception value + searchForExceptionItem('foo'); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // displays empty search result view if no matches found + searchForExceptionItem('abc'); + + // new exception item displays + cy.get(NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT).should('exist'); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts new file mode 100644 index 0000000000000..64a2e14bbf61f --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts @@ -0,0 +1,336 @@ +/* + * 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 { getException, getExceptionList } from '../../../objects/exception'; +import { getNewRule } from '../../../objects/rule'; + +import { ALERTS_COUNT, EMPTY_ALERT_TABLE, NUMBER_OF_ALERTS } from '../../../screens/alerts'; +import { createCustomRule, createCustomRuleEnabled } from '../../../tasks/api_calls/rules'; +import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; +import { goToClosedAlerts, goToOpenedAlerts } from '../../../tasks/alerts'; +import { + esArchiverLoad, + esArchiverUnload, + esArchiverResetKibana, +} from '../../../tasks/es_archiver'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; +import { + addExceptionFlyoutFromViewerHeader, + goToAlertsTab, + goToExceptionsTab, + openEditException, + openExceptionFlyoutFromEmptyViewerPrompt, + removeException, + searchForExceptionItem, + waitForTheRuleToBeExecuted, +} from '../../../tasks/rule_details'; +import { + addExceptionConditions, + addExceptionFlyoutItemName, + editException, + editExceptionFlyoutItemName, + selectAddToRuleRadio, + selectBulkCloseAlerts, + selectSharedListToAddExceptionTo, + submitEditedExceptionItem, + submitNewExceptionItem, +} from '../../../tasks/exceptions'; +import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; +import { deleteAlertsAndRules } from '../../../tasks/common'; +import { + NO_EXCEPTIONS_EXIST_PROMPT, + EXCEPTION_ITEM_VIEWER_CONTAINER, + NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT, + CLOSE_ALERTS_CHECKBOX, + CONFIRM_BTN, + ADD_TO_SHARED_LIST_RADIO_INPUT, + EXCEPTION_ITEM_CONTAINER, + FIELD_INPUT, + VALUES_MATCH_ANY_INPUT, + EXCEPTION_CARD_ITEM_NAME, + EXCEPTION_CARD_ITEM_CONDITIONS, +} from '../../../screens/exceptions'; +import { + createExceptionList, + createExceptionListItem, + deleteExceptionList, +} from '../../../tasks/api_calls/exceptions'; +import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; + +describe('Add/edit exception from rule details', () => { + const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; + const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; + const ITEM_FIELD = 'unique_value.test'; + + before(() => { + esArchiverResetKibana(); + esArchiverLoad('exceptions'); + login(); + }); + + after(() => { + esArchiverUnload('exceptions'); + }); + + describe('existing list and items', () => { + const exceptionList = getExceptionList(); + beforeEach(() => { + deleteAlertsAndRules(); + deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type); + // create rule with exceptions + createExceptionList(exceptionList, exceptionList.list_id).then((response) => { + createCustomRule( + { + ...getNewRule(), + customQuery: 'agent.name:*', + dataSource: { index: ['exceptions*'], type: 'indexPatterns' }, + exceptionLists: [ + { + id: response.body.id, + list_id: exceptionList.list_id, + type: exceptionList.type, + namespace_type: exceptionList.namespace_type, + }, + ], + }, + '2' + ); + createExceptionListItem(exceptionList.list_id, { + list_id: exceptionList.list_id, + item_id: 'simple_list_item', + tags: [], + type: 'simple', + description: 'Test exception item 2', + name: 'Sample Exception List Item 2', + namespace_type: 'single', + entries: [ + { + field: ITEM_FIELD, + operator: 'included', + type: 'match_any', + value: ['foo'], + }, + ], + }); + }); + + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + goToRuleDetails(); + goToExceptionsTab(); + }); + + it('Edits an exception item', () => { + const NEW_ITEM_NAME = 'Exception item-EDITED'; + const ITEM_NAME = 'Sample Exception List Item 2'; + + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' unique_value.testis one of foo'); + + // open edit exception modal + openEditException(); + + // edit exception item name + editExceptionFlyoutItemName(NEW_ITEM_NAME); + + // check that the existing item's field is being populated + cy.get(EXCEPTION_ITEM_CONTAINER) + .eq(0) + .find(FIELD_INPUT) + .eq(0) + .should('have.text', ITEM_FIELD); + cy.get(VALUES_MATCH_ANY_INPUT).should('have.text', 'foo'); + + // edit conditions + editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); + + // submit + submitEditedExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // check that updates stuck + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.nameIS foo'); + }); + + describe('rule with existing shared exceptions', () => { + it('Creates an exception item to add to shared list', () => { + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + + // open add exception modal + addExceptionFlyoutFromViewerHeader(); + + // add exception item conditions + addExceptionConditions(getException()); + + // Name is required so want to check that submit is still disabled + cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); + + // add exception item name + addExceptionFlyoutItemName('My item name'); + + // select to add exception item to a shared list + selectSharedListToAddExceptionTo(1); + + // not testing close alert functionality here, just ensuring that the options appear as expected + cy.get(CLOSE_ALERTS_CHECKBOX).should('exist'); + cy.get(CLOSE_ALERTS_CHECKBOX).should('not.have.attr', 'disabled'); + + // submit + submitNewExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 2); + }); + + it('Creates an exception item to add to rule only', () => { + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + + // open add exception modal + addExceptionFlyoutFromViewerHeader(); + + // add exception item conditions + addExceptionConditions(getException()); + + // Name is required so want to check that submit is still disabled + cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); + + // add exception item name + addExceptionFlyoutItemName('My item name'); + + // select to add exception item to rule only + selectAddToRuleRadio(); + + // not testing close alert functionality here, just ensuring that the options appear as expected + cy.get(CLOSE_ALERTS_CHECKBOX).should('exist'); + cy.get(CLOSE_ALERTS_CHECKBOX).should('not.have.attr', 'disabled'); + + // submit + submitNewExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 2); + }); + + // Trying to figure out with EUI why the search won't trigger + it('Can search for items', () => { + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + + // can search for an exception value + searchForExceptionItem('foo'); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // displays empty search result view if no matches found + searchForExceptionItem('abc'); + + // new exception item displays + cy.get(NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT).should('exist'); + }); + }); + }); + + describe('rule without existing exceptions', () => { + beforeEach(() => { + deleteAlertsAndRules(); + createCustomRuleEnabled( + { + ...getNewRule(), + customQuery: 'agent.name:*', + dataSource: { index: ['exceptions*'], type: 'indexPatterns' }, + }, + 'rule_testing', + '1s' + ); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + goToRuleDetails(); + goToExceptionsTab(); + }); + + afterEach(() => { + esArchiverUnload('exceptions_2'); + }); + + it('Cannot create an item to add to rule but not shared list as rule has no lists attached', () => { + // when no exceptions exist, empty component shows with action to add exception + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); + + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); + + // add exception item conditions + addExceptionConditions({ + field: 'agent.name', + operator: 'is', + values: ['foo'], + }); + + // Name is required so want to check that submit is still disabled + cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); + + // add exception item name + addExceptionFlyoutItemName('My item name'); + + // select to add exception item to rule only + selectAddToRuleRadio(); + + // Check that add to shared list is disabled, should be unless + // rule has shared lists attached to it already + cy.get(ADD_TO_SHARED_LIST_RADIO_INPUT).should('have.attr', 'disabled'); + + // Close matching alerts + selectBulkCloseAlerts(); + + // submit + submitNewExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // Alerts table should now be empty from having added exception and closed + // matching alert + goToAlertsTab(); + cy.get(EMPTY_ALERT_TABLE).should('exist'); + + // Closed alert should appear in table + goToClosedAlerts(); + cy.get(ALERTS_COUNT).should('exist'); + cy.get(NUMBER_OF_ALERTS).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`); + + // Remove the exception and load an event that would have matched that exception + // to show that said exception now starts to show up again + goToExceptionsTab(); + + // when removing exception and again, no more exist, empty screen shows again + removeException(); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); + + // load more docs + esArchiverLoad('exceptions_2'); + + // now that there are no more exceptions, the docs should match and populate alerts + goToAlertsTab(); + goToOpenedAlerts(); + waitForTheRuleToBeExecuted(); + waitForAlertsToPopulate(); + + cy.get(ALERTS_COUNT).should('exist'); + cy.get(NUMBER_OF_ALERTS).should('have.text', '2 alerts'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_exception_data_view.spect.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts similarity index 63% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_exception_data_view.spect.ts rename to x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts index 05b21abe52565..f17a5e4221a89 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_exception_data_view.spect.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts @@ -10,6 +10,11 @@ import { ALERTS_COUNT, EMPTY_ALERT_TABLE, NUMBER_OF_ALERTS } from '../../../scre import { createCustomRuleEnabled } from '../../../tasks/api_calls/rules'; import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; import { goToClosedAlerts, goToOpenedAlerts } from '../../../tasks/alerts'; +import { + editException, + editExceptionFlyoutItemName, + submitEditedExceptionItem, +} from '../../../tasks/exceptions'; import { esArchiverLoad, esArchiverUnload, @@ -20,6 +25,7 @@ import { addFirstExceptionFromRuleDetails, goToAlertsTab, goToExceptionsTab, + openEditException, removeException, waitForTheRuleToBeExecuted, } from '../../../tasks/rule_details'; @@ -29,11 +35,17 @@ import { postDataView, deleteAlertsAndRules } from '../../../tasks/common'; import { NO_EXCEPTIONS_EXIST_PROMPT, EXCEPTION_ITEM_VIEWER_CONTAINER, + EXCEPTION_CARD_ITEM_NAME, + EXCEPTION_CARD_ITEM_CONDITIONS, + EXCEPTION_ITEM_CONTAINER, + FIELD_INPUT, + VALUES_INPUT, } from '../../../screens/exceptions'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; describe('Add exception using data views from rule details', () => { const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; + const ITEM_NAME = 'Sample Exception List Item'; before(() => { esArchiverResetKibana(); @@ -66,17 +78,20 @@ describe('Add exception using data views from rule details', () => { esArchiverUnload('exceptions_2'); }); - it('Creates an exception item when none exist', () => { + it('Creates an exception item', () => { // when no exceptions exist, empty component shows with action to add exception cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); // clicks prompt button to add first exception that will also select to close // all matching alerts - addFirstExceptionFromRuleDetails({ - field: 'agent.name', - operator: 'is', - values: ['foo'], - }); + addFirstExceptionFromRuleDetails( + { + field: 'agent.name', + operator: 'is', + values: ['foo'], + }, + ITEM_NAME + ); // new exception item displays cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); @@ -111,4 +126,49 @@ describe('Add exception using data views from rule details', () => { cy.get(ALERTS_COUNT).should('exist'); cy.get(NUMBER_OF_ALERTS).should('have.text', '2 alerts'); }); + + it('Edits an exception item', () => { + const NEW_ITEM_NAME = 'Exception item-EDITED'; + const ITEM_FIELD = 'unique_value.test'; + const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; + + // add item to edit + addFirstExceptionFromRuleDetails( + { + field: ITEM_FIELD, + operator: 'is', + values: ['foo'], + }, + ITEM_NAME + ); + + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' unique_value.testIS foo'); + + // open edit exception modal + openEditException(); + + // edit exception item name + editExceptionFlyoutItemName(NEW_ITEM_NAME); + + // check that the existing item's field is being populated + cy.get(EXCEPTION_ITEM_CONTAINER).eq(0).find(FIELD_INPUT).eq(0).should('have.text', ITEM_FIELD); + cy.get(VALUES_INPUT).should('have.text', 'foo'); + + // edit conditions + editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); + + // submit + submitEditedExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // check that updates stuck + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.nameIS foo'); + }); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_exception.spec.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_exception.spec.ts deleted file mode 100644 index 3ea14d8b3ffd4..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_exception.spec.ts +++ /dev/null @@ -1,221 +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 { getException, getExceptionList } from '../../../objects/exception'; -import { getNewRule } from '../../../objects/rule'; - -import { ALERTS_COUNT, EMPTY_ALERT_TABLE, NUMBER_OF_ALERTS } from '../../../screens/alerts'; -import { createCustomRule, createCustomRuleEnabled } from '../../../tasks/api_calls/rules'; -import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -import { goToClosedAlerts, goToOpenedAlerts } from '../../../tasks/alerts'; -import { - esArchiverLoad, - esArchiverUnload, - esArchiverResetKibana, -} from '../../../tasks/es_archiver'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { - addExceptionFromRuleDetails, - addFirstExceptionFromRuleDetails, - goToAlertsTab, - goToExceptionsTab, - removeException, - searchForExceptionItem, - waitForTheRuleToBeExecuted, -} from '../../../tasks/rule_details'; - -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; -import { deleteAlertsAndRules } from '../../../tasks/common'; -import { - NO_EXCEPTIONS_EXIST_PROMPT, - EXCEPTION_ITEM_VIEWER_CONTAINER, - NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT, -} from '../../../screens/exceptions'; -import { - createExceptionList, - createExceptionListItem, - deleteExceptionList, -} from '../../../tasks/api_calls/exceptions'; -import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; - -describe('Add exception from rule details', () => { - const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; - - before(() => { - esArchiverResetKibana(); - esArchiverLoad('exceptions'); - login(); - }); - - after(() => { - esArchiverUnload('exceptions'); - }); - - describe('rule with existing exceptions', () => { - const exceptionList = getExceptionList(); - beforeEach(() => { - deleteAlertsAndRules(); - deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type); - // create rule with exceptions - createExceptionList(exceptionList, exceptionList.list_id).then((response) => { - createCustomRule( - { - ...getNewRule(), - customQuery: 'agent.name:*', - dataSource: { index: ['exceptions*'], type: 'indexPatterns' }, - exceptionLists: [ - { - id: response.body.id, - list_id: exceptionList.list_id, - type: exceptionList.type, - namespace_type: exceptionList.namespace_type, - }, - ], - }, - '2' - ); - createExceptionListItem(exceptionList.list_id, { - list_id: exceptionList.list_id, - item_id: 'simple_list_item', - tags: [], - type: 'simple', - description: 'Test exception item', - name: 'Sample Exception List Item', - namespace_type: 'single', - entries: [ - { - field: 'user.name', - operator: 'included', - type: 'match_any', - value: ['bar'], - }, - ], - }); - createExceptionListItem(exceptionList.list_id, { - list_id: exceptionList.list_id, - item_id: 'simple_list_item_2', - tags: [], - type: 'simple', - description: 'Test exception item 2', - name: 'Sample Exception List Item 2', - namespace_type: 'single', - entries: [ - { - field: 'unique_value.test', - operator: 'included', - type: 'match_any', - value: ['foo'], - }, - ], - }); - }); - - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - goToExceptionsTab(); - }); - - it('Creates an exception item', () => { - // displays existing exception items - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 2); - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); - - // clicks prompt button to add a new exception item - addExceptionFromRuleDetails(getException()); - - // new exception item displays - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 3); - }); - - // Trying to figure out with EUI why the search won't trigger - it('Can search for items', () => { - // displays existing exception items - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 2); - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); - - // can search for an exception value - searchForExceptionItem('foo'); - - // new exception item displays - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - // displays empty search result view if no matches found - searchForExceptionItem('abc'); - - // new exception item displays - cy.get(NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT).should('exist'); - }); - }); - - describe('rule without existing exceptions', () => { - beforeEach(() => { - deleteAlertsAndRules(); - createCustomRuleEnabled( - { - ...getNewRule(), - customQuery: 'agent.name:*', - dataSource: { index: ['exceptions*'], type: 'indexPatterns' }, - }, - 'rule_testing', - '1s' - ); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - goToExceptionsTab(); - }); - - afterEach(() => { - esArchiverUnload('exceptions_2'); - }); - - it('Creates an exception item when none exist', () => { - // when no exceptions exist, empty component shows with action to add exception - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); - - // clicks prompt button to add first exception that will also select to close - // all matching alerts - addFirstExceptionFromRuleDetails({ - field: 'agent.name', - operator: 'is', - values: ['foo'], - }); - - // new exception item displays - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - // Alerts table should now be empty from having added exception and closed - // matching alert - goToAlertsTab(); - cy.get(EMPTY_ALERT_TABLE).should('exist'); - - // Closed alert should appear in table - goToClosedAlerts(); - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`); - - // Remove the exception and load an event that would have matched that exception - // to show that said exception now starts to show up again - goToExceptionsTab(); - - // when removing exception and again, no more exist, empty screen shows again - removeException(); - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); - - // load more docs - esArchiverLoad('exceptions_2'); - - // now that there are no more exceptions, the docs should match and populate alerts - goToAlertsTab(); - goToOpenedAlerts(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(); - - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', '2 alerts'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/edit_exception.spec.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/edit_exception.spec.ts deleted file mode 100644 index ec44e76d09edb..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/edit_exception.spec.ts +++ /dev/null @@ -1,143 +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 { getExceptionList } from '../../../objects/exception'; -import { getNewRule } from '../../../objects/rule'; - -import { createCustomRuleEnabled } from '../../../tasks/api_calls/rules'; -import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -import { goToOpenedAlerts } from '../../../tasks/alerts'; -import { - esArchiverLoad, - esArchiverUnload, - esArchiverResetKibana, -} from '../../../tasks/es_archiver'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { - goToExceptionsTab, - waitForTheRuleToBeExecuted, - openEditException, - goToAlertsTab, -} from '../../../tasks/rule_details'; - -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; -import { deleteAlertsAndRules } from '../../../tasks/common'; -import { - EXCEPTION_ITEM_VIEWER_CONTAINER, - EXCEPTION_ITEM_CONTAINER, - FIELD_INPUT, -} from '../../../screens/exceptions'; -import { - createExceptionList, - createExceptionListItem, - deleteExceptionList, -} from '../../../tasks/api_calls/exceptions'; -import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; -import { editException } from '../../../tasks/exceptions'; -import { ALERTS_COUNT, NUMBER_OF_ALERTS } from '../../../screens/alerts'; - -describe('Edit exception from rule details', () => { - const exceptionList = getExceptionList(); - const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; - const ITEM_FIELD = 'unique_value.test'; - const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; - - before(() => { - esArchiverResetKibana(); - esArchiverLoad('exceptions'); - login(); - }); - - after(() => { - esArchiverUnload('exceptions'); - }); - - beforeEach(() => { - deleteAlertsAndRules(); - deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type); - // create rule with exceptions - createExceptionList(exceptionList, exceptionList.list_id).then((response) => { - createCustomRuleEnabled( - { - ...getNewRule(), - customQuery: 'agent.name:*', - dataSource: { index: ['exceptions*'], type: 'indexPatterns' }, - exceptionLists: [ - { - id: response.body.id, - list_id: exceptionList.list_id, - type: exceptionList.type, - namespace_type: exceptionList.namespace_type, - }, - ], - }, - '2', - '2s' - ); - createExceptionListItem(exceptionList.list_id, { - list_id: exceptionList.list_id, - item_id: 'simple_list_item', - tags: [], - type: 'simple', - description: 'Test exception item', - name: 'Sample Exception List Item', - namespace_type: 'single', - entries: [ - { - field: ITEM_FIELD, - operator: 'included', - type: 'match_any', - value: ['bar'], - }, - ], - }); - }); - - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(); - goToExceptionsTab(); - }); - - afterEach(() => { - esArchiverUnload('exceptions_2'); - }); - - it('Edits an exception item', () => { - // displays existing exception item - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - openEditException(); - - // check that the existing item's field is being populated - cy.get(EXCEPTION_ITEM_CONTAINER).eq(0).find(FIELD_INPUT).eq(0).should('have.text', ITEM_FIELD); - - // check that you can select a different field - editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - // Alerts table should still show single alert - goToAlertsTab(); - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`); - - // load more docs - esArchiverLoad('exceptions_2'); - - // now that 2 more docs have been added, one should match the edited exception - goToAlertsTab(); - goToOpenedAlerts(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(2); - - // there should be 2 alerts, one is the original alert and the second is for the newly - // matching doc - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', '2 alerts'); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/edit_exception_data_view.spec.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/edit_exception_data_view.spec.ts deleted file mode 100644 index 587486d99a068..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/edit_exception_data_view.spec.ts +++ /dev/null @@ -1,144 +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 { getExceptionList } from '../../../objects/exception'; -import { getNewRule } from '../../../objects/rule'; - -import { createCustomRuleEnabled } from '../../../tasks/api_calls/rules'; -import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -import { goToOpenedAlerts } from '../../../tasks/alerts'; -import { - esArchiverLoad, - esArchiverUnload, - esArchiverResetKibana, -} from '../../../tasks/es_archiver'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { - goToExceptionsTab, - waitForTheRuleToBeExecuted, - openEditException, - goToAlertsTab, -} from '../../../tasks/rule_details'; - -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; -import { postDataView, deleteAlertsAndRules } from '../../../tasks/common'; -import { - EXCEPTION_ITEM_VIEWER_CONTAINER, - EXCEPTION_ITEM_CONTAINER, - FIELD_INPUT, -} from '../../../screens/exceptions'; -import { - createExceptionList, - createExceptionListItem, - deleteExceptionList, -} from '../../../tasks/api_calls/exceptions'; -import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; -import { editException } from '../../../tasks/exceptions'; -import { ALERTS_COUNT, NUMBER_OF_ALERTS } from '../../../screens/alerts'; - -describe('Edit exception using data views from rule details', () => { - const exceptionList = getExceptionList(); - const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; - const ITEM_FIELD = 'unique_value.test'; - const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; - - before(() => { - esArchiverResetKibana(); - esArchiverLoad('exceptions'); - login(); - postDataView('exceptions-*'); - }); - - after(() => { - esArchiverUnload('exceptions'); - }); - - beforeEach(() => { - deleteAlertsAndRules(); - deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type); - // create rule with exceptions - createExceptionList(exceptionList, exceptionList.list_id).then((response) => { - createCustomRuleEnabled( - { - ...getNewRule(), - customQuery: 'agent.name:*', - dataSource: { dataView: 'exceptions-*', type: 'dataView' }, - exceptionLists: [ - { - id: response.body.id, - list_id: exceptionList.list_id, - type: exceptionList.type, - namespace_type: exceptionList.namespace_type, - }, - ], - }, - '2', - '2s' - ); - createExceptionListItem(exceptionList.list_id, { - list_id: exceptionList.list_id, - item_id: 'simple_list_item', - tags: [], - type: 'simple', - description: 'Test exception item', - name: 'Sample Exception List Item', - namespace_type: 'single', - entries: [ - { - field: ITEM_FIELD, - operator: 'included', - type: 'match_any', - value: ['bar'], - }, - ], - }); - }); - - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(); - goToExceptionsTab(); - }); - - afterEach(() => { - esArchiverUnload('exceptions_2'); - }); - - it('Edits an exception item', () => { - // displays existing exception item - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - openEditException(); - - // check that the existing item's field is being populated - cy.get(EXCEPTION_ITEM_CONTAINER).eq(0).find(FIELD_INPUT).eq(0).should('have.text', ITEM_FIELD); - - // check that you can select a different field - editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - // Alerts table should still show single alert - goToAlertsTab(); - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`); - - // load more docs - esArchiverLoad('exceptions_2'); - - // now that 2 more docs have been added, one should match the edited exception - goToAlertsTab(); - goToOpenedAlerts(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(2); - - // there should be 2 alerts, one is the original alert and the second is for the newly - // matching doc - cy.get(ALERTS_COUNT).should('exist'); - cy.get(NUMBER_OF_ALERTS).should('have.text', '2 alerts'); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/read_only_view.spect.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/read_only_view.spect.ts rename to x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts diff --git a/x-pack/plugins/security_solution/cypress/objects/rule.ts b/x-pack/plugins/security_solution/cypress/objects/rule.ts index 53cbdc7e84c48..59464a3ceda2f 100644 --- a/x-pack/plugins/security_solution/cypress/objects/rule.ts +++ b/x-pack/plugins/security_solution/cypress/objects/rule.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { Throttle } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { RuleActionThrottle } from '@kbn/securitysolution-io-ts-alerting-types'; import { getMockThreatData } from '../../public/detections/mitre/mitre_tactics_techniques'; import type { CompleteTimeline } from './timeline'; import { getTimeline, getIndicatorMatchTimelineTemplate } from './timeline'; -import type { FullResponseSchema } from '../../common/detection_engine/schemas/request'; +import type { RuleResponse } from '../../common/detection_engine/rule_schema'; import type { Connectors } from './connector'; const ccsRemoteName: string = Cypress.env('CCS_REMOTE_NAME'); @@ -36,7 +36,7 @@ interface Interval { } export interface Actions { - throttle: Throttle; + throttle: RuleActionThrottle; connectors: Connectors[]; } @@ -506,9 +506,7 @@ export const getEditedRule = (): CustomRule => ({ tags: [...(getExistingRule().tags || []), 'edited'], }); -export const expectedExportedRule = ( - ruleResponse: Cypress.Response -): string => { +export const expectedExportedRule = (ruleResponse: Cypress.Response): string => { const { id, updated_at: updatedAt, @@ -531,7 +529,7 @@ export const expectedExportedRule = ( // NOTE: Order of the properties in this object matters for the tests to work. // TODO: Follow up https://github.com/elastic/kibana/pull/137628 and add an explicit type to this object // without using Partial - const rule: Partial = { + const rule: Partial = { id, updated_at: updatedAt, updated_by: updatedBy, diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts.ts b/x-pack/plugins/security_solution/cypress/screens/alerts.ts index 2ceeaac0e8ca7..2434b713a6452 100644 --- a/x-pack/plugins/security_solution/cypress/screens/alerts.ts +++ b/x-pack/plugins/security_solution/cypress/screens/alerts.ts @@ -7,6 +7,8 @@ export const ADD_EXCEPTION_BTN = '[data-test-subj="add-exception-menu-item"]'; +export const ADD_ENDPOINT_EXCEPTION_BTN = '[data-test-subj="add-endpoint-exception-menu-item"]'; + export const ALERT_COUNT_TABLE_FIRST_ROW_COUNT = '[data-test-subj="alertsCountTable"] tr:nth-child(1) td:nth-child(2) .euiTableCellContent__text'; @@ -22,6 +24,8 @@ export const ALERT_SEVERITY = '[data-test-subj="formatted-field-kibana.alert.sev export const ALERT_DATA_GRID = '[data-test-subj="euiDataGridBody"]'; +export const ALERTS = '[data-test-subj="events-viewer-panel"][data-test-subj="event"]'; + export const ALERTS_COUNT = '[data-test-subj="events-viewer-panel"] [data-test-subj="server-side-event-count"]'; @@ -42,6 +46,10 @@ export const EMPTY_ALERT_TABLE = '[data-test-subj="tGridEmptyState"]'; export const EXPAND_ALERT_BTN = '[data-test-subj="expand-event"]'; +export const TAKE_ACTION_BTN = '[data-test-subj="take-action-dropdown-btn"]'; + +export const TAKE_ACTION_MENU = '[data-test-subj="takeActionPanelMenu"]'; + export const CLOSE_FLYOUT = '[data-test-subj="euiFlyoutCloseButton"]'; export const GROUP_BY_TOP_INPUT = '[data-test-subj="groupByTop"] [data-test-subj="comboBoxInput"]'; diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts index 8b717d7f6bd22..5452d59b68c07 100644 --- a/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts @@ -58,8 +58,6 @@ export const RULES_TABLE_AUTOREFRESH_INDICATOR = '[data-test-subj="loadingRulesI export const RISK_SCORE = '[data-test-subj="riskScore"]'; -export const RELOAD_PREBUILT_RULES_BTN = '[data-test-subj="reloadPrebuiltRulesBtn"]'; - export const SECOND_RULE = 1; export const RULE_CHECKBOX = '.euiTableRow .euiCheckbox__input'; diff --git a/x-pack/plugins/security_solution/cypress/screens/exceptions.ts b/x-pack/plugins/security_solution/cypress/screens/exceptions.ts index 1ca8ded946300..bf97d3e2e2039 100644 --- a/x-pack/plugins/security_solution/cypress/screens/exceptions.ts +++ b/x-pack/plugins/security_solution/cypress/screens/exceptions.ts @@ -5,10 +5,11 @@ * 2.0. */ -export const CLOSE_ALERTS_CHECKBOX = - '[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]'; +export const CLOSE_ALERTS_CHECKBOX = '[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]'; -export const CONFIRM_BTN = '[data-test-subj="add-exception-confirm-button"]'; +export const CLOSE_SINGLE_ALERT_CHECKBOX = '[data-test-subj="closeAlertOnAddExceptionCheckbox"]'; + +export const CONFIRM_BTN = '[data-test-subj="addExceptionConfirmButton"]'; export const FIELD_INPUT = '[data-test-subj="fieldAutocompleteComboBox"] [data-test-subj="comboBoxInput"]'; @@ -57,9 +58,9 @@ export const EXCEPTION_ITEM_CONTAINER = '[data-test-subj="exceptionEntriesContai export const EXCEPTION_FIELD_LIST = '[data-test-subj="comboBoxOptionsList fieldAutocompleteComboBox-optionsList"]'; -export const EXCEPTION_FLYOUT_TITLE = '[data-test-subj="exception-flyout-title"]'; +export const EXCEPTION_FLYOUT_TITLE = '[data-test-subj="exceptionFlyoutTitle"]'; -export const EXCEPTION_EDIT_FLYOUT_SAVE_BTN = '[data-test-subj="edit-exception-confirm-button"]'; +export const EXCEPTION_EDIT_FLYOUT_SAVE_BTN = '[data-test-subj="editExceptionConfirmButton"]'; export const EXCEPTION_FLYOUT_VERSION_CONFLICT = '[data-test-subj="exceptionsFlyoutVersionConflict"]'; @@ -68,7 +69,7 @@ export const EXCEPTION_FLYOUT_LIST_DELETED_ERROR = '[data-test-subj="errorCallou // Exceptions all items view export const NO_EXCEPTIONS_EXIST_PROMPT = - '[data-test-subj="exceptionItemViewerEmptyPrompts-empty-detection"]'; + '[data-test-subj="exceptionItemViewerEmptyPrompts-empty"]'; export const ADD_EXCEPTIONS_BTN_FROM_EMPTY_PROMPT_BTN = '[data-test-subj="exceptionsEmptyPromptButton"]'; @@ -82,3 +83,25 @@ export const NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT = '[data-test-subj="exceptionItemViewerEmptyPrompts-emptySearch"]'; export const EXCEPTION_ITEM_VIEWER_SEARCH = 'input[data-test-subj="exceptionsViewerSearchBar"]'; + +export const EXCEPTION_CARD_ITEM_NAME = '[data-test-subj="exceptionItemCardHeader-title"]'; + +export const EXCEPTION_CARD_ITEM_CONDITIONS = + '[data-test-subj="exceptionItemCardConditions-condition"]'; + +// Exception flyout components +export const EXCEPTION_ITEM_NAME_INPUT = 'input[data-test-subj="exceptionFlyoutNameInput"]'; + +export const ADD_TO_SHARED_LIST_RADIO_LABEL = '[data-test-subj="addToListsRadioOption"] label'; + +export const ADD_TO_SHARED_LIST_RADIO_INPUT = 'input[id="add_to_lists"]'; + +export const SHARED_LIST_CHECKBOX = '.euiTableRow .euiCheckbox__input'; + +export const ADD_TO_RULE_RADIO_LABEL = 'label [data-test-subj="addToRuleRadioOption"]'; + +export const ADD_TO_RULE_OR_LIST_SECTION = '[data-test-subj="exceptionItemAddToRuleOrListSection"]'; + +export const OS_SELECTION_SECTION = '[data-test-subj="osSelectionDropdown"]'; + +export const OS_INPUT = '[data-test-subj="osSelectionDropdown"] [data-test-subj="comboBoxInput"]'; diff --git a/x-pack/plugins/security_solution/cypress/screens/rule_details.ts b/x-pack/plugins/security_solution/cypress/screens/rule_details.ts index bad0770ffd763..606ee4ae7a043 100644 --- a/x-pack/plugins/security_solution/cypress/screens/rule_details.ts +++ b/x-pack/plugins/security_solution/cypress/screens/rule_details.ts @@ -43,6 +43,8 @@ export const FALSE_POSITIVES_DETAILS = 'False positive examples'; export const INDEX_PATTERNS_DETAILS = 'Index patterns'; +export const ENDPOINT_EXCEPTIONS_TAB = 'a[data-test-subj="navigation-endpoint_exceptions"]'; + export const INDICATOR_INDEX_PATTERNS = 'Indicator index patterns'; export const INDICATOR_INDEX_QUERY = 'Indicator index query'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts.ts index 9df0fb86f218c..8003f1ba3c304 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts.ts @@ -16,6 +16,7 @@ import { GROUP_BY_TOP_INPUT, ACKNOWLEDGED_ALERTS_FILTER_BTN, LOADING_ALERTS_PANEL, + MANAGE_ALERT_DETECTION_RULES_BTN, MARK_ALERT_ACKNOWLEDGED_BTN, OPEN_ALERT_BTN, OPENED_ALERTS_FILTER_BTN, @@ -25,6 +26,9 @@ import { TIMELINE_CONTEXT_MENU_BTN, CLOSE_FLYOUT, OPEN_ANALYZER_BTN, + TAKE_ACTION_BTN, + TAKE_ACTION_MENU, + ADD_ENDPOINT_EXCEPTION_BTN, } from '../screens/alerts'; import { REFRESH_BUTTON } from '../screens/security_header'; import { @@ -41,10 +45,44 @@ import { CELL_EXPANSION_POPOVER, USER_DETAILS_LINK, } from '../screens/alerts_details'; +import { FIELD_INPUT } from '../screens/exceptions'; export const addExceptionFromFirstAlert = () => { cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click({ force: true }); - cy.get(ADD_EXCEPTION_BTN).click(); + cy.root() + .pipe(($el) => { + $el.find(ADD_EXCEPTION_BTN).trigger('click'); + return $el.find(FIELD_INPUT); + }) + .should('be.visible'); +}; + +export const openAddEndpointExceptionFromFirstAlert = () => { + cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click({ force: true }); + cy.root() + .pipe(($el) => { + $el.find(ADD_ENDPOINT_EXCEPTION_BTN).trigger('click'); + return $el.find(FIELD_INPUT); + }) + .should('be.visible'); +}; + +export const openAddExceptionFromAlertDetails = () => { + cy.get(EXPAND_ALERT_BTN).first().click({ force: true }); + + cy.root() + .pipe(($el) => { + $el.find(TAKE_ACTION_BTN).trigger('click'); + return $el.find(TAKE_ACTION_MENU); + }) + .should('be.visible'); + + cy.root() + .pipe(($el) => { + $el.find(ADD_EXCEPTION_BTN).trigger('click'); + return $el.find(ADD_EXCEPTION_BTN); + }) + .should('not.be.visible'); }; export const closeFirstAlert = () => { @@ -106,6 +144,10 @@ export const goToClosedAlerts = () => { cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist'); }; +export const goToManageAlertsDetectionRules = () => { + cy.get(MANAGE_ALERT_DETECTION_RULES_BTN).should('exist').click({ force: true }); +}; + export const goToOpenedAlerts = () => { cy.get(OPENED_ALERTS_FILTER_BTN).click({ force: true }); cy.get(REFRESH_BUTTON).should('not.have.attr', 'aria-label', 'Needs updating'); diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts index 13c0c7a7735bc..2bc4badf3cfa1 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts @@ -18,7 +18,6 @@ import { RULES_TABLE_REFRESH_INDICATOR, RULES_TABLE_AUTOREFRESH_INDICATOR, PAGINATION_POPOVER_BTN, - RELOAD_PREBUILT_RULES_BTN, RULE_CHECKBOX, RULE_NAME, RULE_SWITCH, @@ -194,7 +193,7 @@ export const openIntegrationsPopover = () => { }; export const reloadDeletedRules = () => { - cy.get(RELOAD_PREBUILT_RULES_BTN).click({ force: true }); + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).click({ force: true }); }; /** diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/exceptions.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/exceptions.ts index 68909d37dd1e4..fd070cfcda55e 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/exceptions.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/exceptions.ts @@ -7,6 +7,14 @@ import type { ExceptionList, ExceptionListItem } from '../../objects/exception'; +export const createEndpointExceptionList = () => + cy.request({ + method: 'POST', + url: '/api/endpoint_list', + headers: { 'kbn-xsrf': 'cypress-creds' }, + failOnStatusCode: false, + }); + export const createExceptionList = ( exceptionList: ExceptionList, exceptionListId = 'exception_list_testing' diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/prebuilt_rules.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/prebuilt_rules.ts index 57197fe512946..f8a48dd9c8239 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/prebuilt_rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/prebuilt_rules.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PrePackagedRulesStatusResponse } from '../../../public/detections/containers/detection_engine/rules/types'; +import type { PrePackagedRulesStatusResponse } from '../../../public/detection_engine/rule_management/logic/types'; export const getPrebuiltRulesStatus = () => { return cy.request({ diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts index 82eb2f9255b0f..099736e4f1003 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { Actions } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types'; import type { CustomRule, @@ -258,7 +258,7 @@ export const createCustomRuleEnabled = ( ruleId = '1', interval = '100m', maxSignals = 500, - actions?: Actions + actions?: RuleActionArray ) => { const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined; const severity = rule.severity != null ? rule.severity.toLocaleLowerCase() : undefined; diff --git a/x-pack/plugins/security_solution/cypress/tasks/exceptions.ts b/x-pack/plugins/security_solution/cypress/tasks/exceptions.ts index 5525fdcca8fcf..1e89e14c1280e 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/exceptions.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/exceptions.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { Exception } from '../objects/exception'; import { FIELD_INPUT, OPERATOR_INPUT, @@ -14,6 +15,15 @@ import { VALUES_INPUT, VALUES_MATCH_ANY_INPUT, EXCEPTION_EDIT_FLYOUT_SAVE_BTN, + CLOSE_ALERTS_CHECKBOX, + CONFIRM_BTN, + EXCEPTION_ITEM_NAME_INPUT, + CLOSE_SINGLE_ALERT_CHECKBOX, + ADD_TO_RULE_RADIO_LABEL, + ADD_TO_SHARED_LIST_RADIO_LABEL, + SHARED_LIST_CHECKBOX, + OS_SELECTION_SECTION, + OS_INPUT, } from '../screens/exceptions'; export const addExceptionEntryFieldValueOfItemX = ( @@ -56,8 +66,72 @@ export const closeExceptionBuilderFlyout = () => { export const editException = (updatedField: string, itemIndex = 0, fieldIndex = 0) => { addExceptionEntryFieldValueOfItemX(`${updatedField}{downarrow}{enter}`, itemIndex, fieldIndex); addExceptionEntryFieldValueValue('foo', itemIndex); +}; + +export const addExceptionFlyoutItemName = (name: string) => { + cy.root() + .pipe(($el) => { + return $el.find(EXCEPTION_ITEM_NAME_INPUT); + }) + .type(`${name}{enter}`) + .should('have.value', name); +}; + +export const editExceptionFlyoutItemName = (name: string) => { + cy.root() + .pipe(($el) => { + return $el.find(EXCEPTION_ITEM_NAME_INPUT); + }) + .clear() + .type(`${name}{enter}`) + .should('have.value', name); +}; +export const selectBulkCloseAlerts = () => { + cy.get(CLOSE_ALERTS_CHECKBOX).click({ force: true }); +}; + +export const selectCloseSingleAlerts = () => { + cy.get(CLOSE_SINGLE_ALERT_CHECKBOX).click({ force: true }); +}; + +export const addExceptionConditions = (exception: Exception) => { + cy.root() + .pipe(($el) => { + return $el.find(FIELD_INPUT); + }) + .type(`${exception.field}{downArrow}{enter}`); + cy.get(OPERATOR_INPUT).type(`${exception.operator}{enter}`); + exception.values.forEach((value) => { + cy.get(VALUES_INPUT).type(`${value}{enter}`); + }); +}; + +export const submitNewExceptionItem = () => { + cy.get(CONFIRM_BTN).click(); + cy.get(CONFIRM_BTN).should('not.exist'); +}; + +export const submitEditedExceptionItem = () => { cy.get(EXCEPTION_EDIT_FLYOUT_SAVE_BTN).click(); - cy.get(EXCEPTION_EDIT_FLYOUT_SAVE_BTN).should('have.attr', 'disabled'); cy.get(EXCEPTION_EDIT_FLYOUT_SAVE_BTN).should('not.exist'); }; + +export const selectAddToRuleRadio = () => { + cy.get(ADD_TO_RULE_RADIO_LABEL).click(); +}; + +export const selectSharedListToAddExceptionTo = (numListsToCheck = 1) => { + cy.get(ADD_TO_SHARED_LIST_RADIO_LABEL).click(); + for (let i = 0; i < numListsToCheck; i++) { + cy.get(SHARED_LIST_CHECKBOX) + .eq(i) + .pipe(($el) => $el.trigger('click')) + .should('be.checked'); + } +}; + +export const selectOs = (os: string) => { + cy.get(OS_SELECTION_SECTION).should('exist'); + cy.get(OS_INPUT).type(`${os}{downArrow}{enter}`); +}; diff --git a/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts b/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts index 3f7d31f060473..3d4f25d248e6a 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts @@ -10,13 +10,8 @@ import { RULE_STATUS } from '../screens/create_new_rule'; import { ADD_EXCEPTIONS_BTN_FROM_EMPTY_PROMPT_BTN, ADD_EXCEPTIONS_BTN_FROM_VIEWER_HEADER, - CLOSE_ALERTS_CHECKBOX, - CONFIRM_BTN, EXCEPTION_ITEM_VIEWER_SEARCH, FIELD_INPUT, - LOADING_SPINNER, - OPERATOR_INPUT, - VALUES_INPUT, } from '../screens/exceptions'; import { ALERTS_TAB, @@ -32,8 +27,15 @@ import { DETAILS_DESCRIPTION, EXCEPTION_ITEM_ACTIONS_BUTTON, EDIT_EXCEPTION_BTN, + ENDPOINT_EXCEPTIONS_TAB, EDIT_RULE_SETTINGS_LINK, } from '../screens/rule_details'; +import { + addExceptionConditions, + addExceptionFlyoutItemName, + selectBulkCloseAlerts, + submitNewExceptionItem, +} from './exceptions'; import { addsFields, closeFieldsBrowser, filterFieldsBrowser } from './fields_browser'; export const enablesRule = () => { @@ -46,21 +48,6 @@ export const enablesRule = () => { }); }; -export const addsException = (exception: Exception) => { - cy.get(LOADING_SPINNER).should('exist'); - cy.get(LOADING_SPINNER).should('not.exist'); - cy.get(FIELD_INPUT).should('exist'); - cy.get(FIELD_INPUT).type(`${exception.field}{enter}`); - cy.get(OPERATOR_INPUT).type(`${exception.operator}{enter}`); - exception.values.forEach((value) => { - cy.get(VALUES_INPUT).type(`${value}{enter}`); - }); - cy.get(CLOSE_ALERTS_CHECKBOX).click({ force: true }); - cy.get(CONFIRM_BTN).click(); - cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); - cy.get(CONFIRM_BTN).should('not.exist'); -}; - export const addsFieldsToTimeline = (search: string, fields: string[]) => { cy.get(FIELDS_BROWSER_BTN).click(); filterFieldsBrowser(search); @@ -86,7 +73,7 @@ export const searchForExceptionItem = (query: string) => { }); }; -const addExceptionFlyoutFromViewerHeader = () => { +export const addExceptionFlyoutFromViewerHeader = () => { cy.root() .pipe(($el) => { $el.find(ADD_EXCEPTIONS_BTN_FROM_VIEWER_HEADER).trigger('click'); @@ -97,28 +84,16 @@ const addExceptionFlyoutFromViewerHeader = () => { export const addExceptionFromRuleDetails = (exception: Exception) => { addExceptionFlyoutFromViewerHeader(); - cy.get(FIELD_INPUT).type(`${exception.field}{downArrow}{enter}`); - cy.get(OPERATOR_INPUT).type(`${exception.operator}{enter}`); - exception.values.forEach((value) => { - cy.get(VALUES_INPUT).type(`${value}{enter}`); - }); - cy.get(CLOSE_ALERTS_CHECKBOX).click({ force: true }); - cy.get(CONFIRM_BTN).click(); - cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); - cy.get(CONFIRM_BTN).should('not.exist'); + addExceptionConditions(exception); + submitNewExceptionItem(); }; -export const addFirstExceptionFromRuleDetails = (exception: Exception) => { +export const addFirstExceptionFromRuleDetails = (exception: Exception, name: string) => { openExceptionFlyoutFromEmptyViewerPrompt(); - cy.get(FIELD_INPUT).type(`${exception.field}{downArrow}{enter}`); - cy.get(OPERATOR_INPUT).type(`${exception.operator}{enter}`); - exception.values.forEach((value) => { - cy.get(VALUES_INPUT).type(`${value}{enter}`); - }); - cy.get(CLOSE_ALERTS_CHECKBOX).click({ force: true }); - cy.get(CONFIRM_BTN).click(); - cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); - cy.get(CONFIRM_BTN).should('not.exist'); + addExceptionFlyoutItemName(name); + addExceptionConditions(exception); + selectBulkCloseAlerts(); + submitNewExceptionItem(); }; export const goToAlertsTab = () => { @@ -130,9 +105,13 @@ export const goToExceptionsTab = () => { cy.get(EXCEPTIONS_TAB).click(); }; +export const goToEndpointExceptionsTab = () => { + cy.get(ENDPOINT_EXCEPTIONS_TAB).should('exist'); + cy.get(ENDPOINT_EXCEPTIONS_TAB).click(); +}; + export const openEditException = (index = 0) => { cy.get(EXCEPTION_ITEM_ACTIONS_BUTTON).eq(index).click({ force: true }); - cy.get(EDIT_EXCEPTION_BTN).eq(index).click({ force: true }); }; @@ -157,7 +136,7 @@ export const goBackToAllRulesTable = () => { }; export const getDetails = (title: string | RegExp) => - cy.get(DETAILS_TITLE).contains(title).next(DETAILS_DESCRIPTION); + cy.contains(DETAILS_TITLE, title).next(DETAILS_DESCRIPTION); export const assertDetailsNotExist = (title: string | RegExp) => cy.get(DETAILS_TITLE).contains(title).should('not.exist'); diff --git a/x-pack/plugins/security_solution/kibana.json b/x-pack/plugins/security_solution/kibana.json index 4dce859a3efd6..4a6e3a105ee72 100644 --- a/x-pack/plugins/security_solution/kibana.json +++ b/x-pack/plugins/security_solution/kibana.json @@ -31,7 +31,8 @@ "timelines", "triggersActionsUi", "uiActions", - "unifiedSearch" + "unifiedSearch", + "files" ], "optionalPlugins": [ "cloudExperiments", diff --git a/x-pack/plugins/security_solution/public/cases/pages/index.tsx b/x-pack/plugins/security_solution/public/cases/pages/index.tsx index 9e4de0cbf9c0e..5db5185679ab3 100644 --- a/x-pack/plugins/security_solution/public/cases/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/pages/index.tsx @@ -76,7 +76,7 @@ const CaseContainerComponent: React.FC = () => { selected_endpoint: endpointId, }), }); - + // TO-DO: onComponentInitialized not needed after removing the expandedEvent state from timeline const onComponentInitialized = useCallback(() => { dispatch( timelineActions.createTimeline({ diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.test.tsx index e860713e5ce0c..662e1983680bd 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.test.tsx @@ -11,7 +11,7 @@ import { waitFor, render, act } from '@testing-library/react'; import { AlertSummaryView } from './alert_summary_view'; import { mockAlertDetailsData } from './__mocks__'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; -import { useRuleWithFallback } from '../../../detections/containers/detection_engine/rules/use_rule_with_fallback'; +import { useRuleWithFallback } from '../../../detection_engine/rule_management/logic/use_rule_with_fallback'; import { TestProviders, TestProvidersComponent } from '../../mock'; import { TimelineId } from '../../../../common/types'; @@ -20,7 +20,7 @@ import * as i18n from './translations'; jest.mock('../../lib/kibana'); -jest.mock('../../../detections/containers/detection_engine/rules/use_rule_with_fallback', () => { +jest.mock('../../../detection_engine/rule_management/logic/use_rule_with_fallback', () => { return { useRuleWithFallback: jest.fn(), }; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx index 3da1cfdb3c6de..2b8c0d534228d 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx @@ -51,7 +51,7 @@ mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCa jest.mock('../../containers/cti/event_enrichment'); -jest.mock('../../../detections/containers/detection_engine/rules/use_rule_with_fallback', () => { +jest.mock('../../../detection_engine/rule_management/logic/use_rule_with_fallback', () => { return { useRuleWithFallback: jest.fn().mockReturnValue({ rule: { diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/investigation_guide_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/investigation_guide_view.tsx index 4e9ff49a2b1dd..5e2827c396f74 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/investigation_guide_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/investigation_guide_view.tsx @@ -13,7 +13,7 @@ import styled from 'styled-components'; import type { GetBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; import * as i18n from './translations'; -import { useRuleWithFallback } from '../../../detections/containers/detection_engine/rules/use_rule_with_fallback'; +import { useRuleWithFallback } from '../../../detection_engine/rule_management/logic/use_rule_with_fallback'; import { MarkdownRenderer } from '../markdown_editor'; import { LineClamp } from '../line_clamp'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; diff --git a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx index bb6b8cd5dbeab..35f48c9702333 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.test.tsx @@ -80,6 +80,7 @@ describe('EventsQueryTabBody', () => { type: HostsType.page, endDate: new Date('2000').toISOString(), startDate: new Date('2000').toISOString(), + additionalFilters: [], }; beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx index 68426e6a4b474..e8f9478ba4578 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx @@ -52,10 +52,9 @@ export const ALERTS_EVENTS_HISTOGRAM_ID = 'alertsOrEventsHistogramQuery'; type QueryTabBodyProps = UserQueryTabBodyProps | HostQueryTabBodyProps | NetworkQueryTabBodyProps; export type EventsQueryTabBodyComponentProps = QueryTabBodyProps & { + additionalFilters: Filter[]; deleteQuery?: GlobalTimeArgs['deleteQuery']; indexNames: string[]; - pageFilters?: Filter[]; - externalAlertPageFilters?: Filter[]; setQuery: GlobalTimeArgs['setQuery']; tableId: TableId; }; @@ -63,12 +62,11 @@ export type EventsQueryTabBodyComponentProps = QueryTabBodyProps & { const EXTERNAL_ALERTS_URL_PARAM = 'onlyExternalAlerts'; const EventsQueryTabBodyComponent: React.FC = ({ + additionalFilters, deleteQuery, endDate, filterQuery, indexNames, - externalAlertPageFilters = [], - pageFilters = [], setQuery, startDate, tableId, @@ -110,6 +108,7 @@ const EventsQueryTabBodyComponent: React.FC = } : c ), + title: i18n.EVENTS_GRAPH_TITLE, }) ); }, [dispatch, showExternalAlerts, tGridEnabled, tableId]); @@ -122,7 +121,7 @@ const EventsQueryTabBodyComponent: React.FC = }; }, [deleteQuery]); - const additionalFilters = useMemo( + const toggleExternalAlertsCheckbox = useMemo( () => ( = ); const composedPageFilters = useMemo( - () => [ - ...pageFilters, - ...(showExternalAlerts ? [defaultAlertsFilters, ...externalAlertPageFilters] : []), - ], - [showExternalAlerts, externalAlertPageFilters, pageFilters] + () => (showExternalAlerts ? [defaultAlertsFilters, ...additionalFilters] : additionalFilters), + [additionalFilters, showExternalAlerts] ); return ( @@ -168,7 +164,7 @@ const EventsQueryTabBodyComponent: React.FC = /> )} string, diff --git a/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.test.ts b/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.test.ts index 49be1077da393..430fddcd36fc6 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.test.ts @@ -4,27 +4,26 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -// import React from 'react'; -import type { RenderResult } from '@testing-library/react-hooks'; import { act, renderHook } from '@testing-library/react-hooks'; import { TestProviders } from '../../../mock'; -import type { Refetch } from '../../../store/inputs/model'; -import type { AnomaliesCount } from './use_anomalies_search'; -import { useNotableAnomaliesSearch, AnomalyJobStatus, AnomalyEntity } from './use_anomalies_search'; +import { useNotableAnomaliesSearch, AnomalyEntity } from './use_anomalies_search'; const jobId = 'auth_rare_source_ip_for_a_user'; const from = 'now-24h'; const to = 'now'; -const JOBS = [{ id: jobId, jobState: 'started', datafeedState: 'started' }]; +const job = { id: jobId, jobState: 'started', datafeedState: 'started' }; +const JOBS = [job]; +const useSecurityJobsRefetch = jest.fn(); -const mockuseInstalledSecurityJobs = jest.fn().mockReturnValue({ +const mockUseSecurityJobs = jest.fn().mockReturnValue({ loading: false, - isMlUser: true, + isMlAdmin: true, jobs: JOBS, + refetch: useSecurityJobsRefetch, }); -jest.mock('../hooks/use_installed_security_jobs', () => ({ - useInstalledSecurityJobs: () => mockuseInstalledSecurityJobs(), +jest.mock('../../ml_popover/hooks/use_security_jobs', () => ({ + useSecurityJobs: () => mockUseSecurityJobs(), })); const mockAddToastError = jest.fn(); @@ -72,14 +71,7 @@ describe('useNotableAnomaliesSearch', () => { expect(mockNotableAnomaliesSearch).not.toHaveBeenCalled(); }); - it('refetch calls notableAnomaliesSearch', async () => { - let renderResult: RenderResult<{ - isLoading: boolean; - data: AnomaliesCount[]; - refetch: Refetch; - }>; - - // first notableAnomaliesSearch call + it('refetch calls useSecurityJobs().refetch', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useNotableAnomaliesSearch({ skip: false, from, to }), @@ -87,17 +79,13 @@ describe('useNotableAnomaliesSearch', () => { wrapper: TestProviders, } ); - renderResult = result; await waitForNextUpdate(); - }); - await act(async () => { - mockNotableAnomaliesSearch.mockClear(); // clear the first notableAnomaliesSearch call - await renderResult.current.refetch(); + result.current.refetch(); }); - expect(mockNotableAnomaliesSearch).toHaveBeenCalled(); + expect(useSecurityJobsRefetch).toHaveBeenCalled(); }); it('returns formated data', async () => { @@ -119,9 +107,8 @@ describe('useNotableAnomaliesSearch', () => { expect.arrayContaining([ { count: 99, - jobId, name: jobId, - status: AnomalyJobStatus.enabled, + job, entity: AnomalyEntity.Host, }, ]) @@ -129,11 +116,28 @@ describe('useNotableAnomaliesSearch', () => { }); }); + it('does not throw error when aggregations is undefined', async () => { + await act(async () => { + mockNotableAnomaliesSearch.mockResolvedValue({}); + const { waitForNextUpdate } = renderHook( + () => useNotableAnomaliesSearch({ skip: false, from, to }), + { + wrapper: TestProviders, + } + ); + await waitForNextUpdate(); + await waitForNextUpdate(); + + expect(mockAddToastError).not.toBeCalled(); + }); + }); + it('returns uninstalled jobs', async () => { - mockuseInstalledSecurityJobs.mockReturnValue({ + mockUseSecurityJobs.mockReturnValue({ loading: false, - isMlUser: true, + isMlAdmin: true, jobs: [], + refetch: useSecurityJobsRefetch, }); await act(async () => { @@ -153,9 +157,8 @@ describe('useNotableAnomaliesSearch', () => { expect.arrayContaining([ { count: 0, - jobId: undefined, - name: jobId, - status: AnomalyJobStatus.uninstalled, + name: job.id, + job: undefined, entity: AnomalyEntity.Host, }, ]) @@ -169,16 +172,18 @@ describe('useNotableAnomaliesSearch', () => { mockNotableAnomaliesSearch.mockResolvedValue({ aggregations: { number_of_anomalies: { buckets: [jobCount] } }, }); - mockuseInstalledSecurityJobs.mockReturnValue({ + + const customJob = { + id: customJobId, + jobState: 'started', + datafeedState: 'started', + }; + + mockUseSecurityJobs.mockReturnValue({ loading: false, - isMlUser: true, - jobs: [ - { - id: customJobId, - jobState: 'started', - datafeedState: 'started', - }, - ], + isMlAdmin: true, + jobs: [customJob], + refetch: useSecurityJobsRefetch, }); await act(async () => { @@ -196,9 +201,8 @@ describe('useNotableAnomaliesSearch', () => { expect.arrayContaining([ { count: 99, - jobId: customJobId, - name: jobId, - status: AnomalyJobStatus.enabled, + name: job.id, + job: customJob, entity: AnomalyEntity.Host, }, ]) @@ -209,6 +213,12 @@ describe('useNotableAnomaliesSearch', () => { it('returns the most recent job when there are multiple jobs matching one notable job id`', async () => { const mostRecentJobId = `mostRecent_${jobId}`; const leastRecentJobId = `leastRecent_${jobId}`; + const mostRecentJob = { + id: mostRecentJobId, + jobState: 'started', + datafeedState: 'started', + latestTimestampSortValue: 1661731200000, // 2022-08-29 + }; mockNotableAnomaliesSearch.mockResolvedValue({ aggregations: { @@ -221,9 +231,9 @@ describe('useNotableAnomaliesSearch', () => { }, }); - mockuseInstalledSecurityJobs.mockReturnValue({ + mockUseSecurityJobs.mockReturnValue({ loading: false, - isMlUser: true, + isMlAdmin: true, jobs: [ { id: leastRecentJobId, @@ -231,13 +241,9 @@ describe('useNotableAnomaliesSearch', () => { datafeedState: 'started', latestTimestampSortValue: 1661644800000, // 2022-08-28 }, - { - id: mostRecentJobId, - jobState: 'started', - datafeedState: 'started', - latestTimestampSortValue: 1661731200000, // 2022-08-29 - }, + mostRecentJob, ], + refetch: useSecurityJobsRefetch, }); await act(async () => { @@ -254,9 +260,8 @@ describe('useNotableAnomaliesSearch', () => { expect.arrayContaining([ { count: 99, - jobId: mostRecentJobId, name: jobId, - status: AnomalyJobStatus.enabled, + job: mostRecentJob, entity: AnomalyEntity.Host, }, ]) diff --git a/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.ts b/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.ts index 1a95f56465ba8..90025eb8d65fe 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_search.ts @@ -5,28 +5,20 @@ * 2.0. */ -import { useState, useEffect, useMemo, useRef } from 'react'; -import { filter, head, noop, orderBy, pipe, has } from 'lodash/fp'; -import type { MlSummaryJob } from '@kbn/ml-plugin/common'; +import { useState, useEffect, useMemo } from 'react'; +import { filter, head, orderBy, pipe, has } from 'lodash/fp'; import { DEFAULT_ANOMALY_SCORE } from '../../../../../common/constants'; import * as i18n from './translations'; import { useUiSetting$ } from '../../../lib/kibana'; import { useAppToasts } from '../../../hooks/use_app_toasts'; -import { useInstalledSecurityJobs } from '../hooks/use_installed_security_jobs'; import { notableAnomaliesSearch } from '../api/anomalies_search'; import type { NotableAnomaliesJobId } from '../../../../overview/components/entity_analytics/anomalies/config'; import { NOTABLE_ANOMALIES_IDS } from '../../../../overview/components/entity_analytics/anomalies/config'; import { getAggregatedAnomaliesQuery } from '../../../../overview/components/entity_analytics/anomalies/query'; import type { inputsModel } from '../../../store'; -import { isJobFailed, isJobStarted } from '../../../../../common/machine_learning/helpers'; - -export enum AnomalyJobStatus { - 'enabled', - 'disabled', - 'uninstalled', - 'failed', -} +import { useSecurityJobs } from '../../ml_popover/hooks/use_security_jobs'; +import type { SecurityJob } from '../../ml_popover/types'; export const enum AnomalyEntity { User, @@ -35,10 +27,9 @@ export const enum AnomalyEntity { export interface AnomaliesCount { name: NotableAnomaliesJobId; - jobId?: string; count: number; - status: AnomalyJobStatus; entity: AnomalyEntity; + job?: SecurityJob; } interface UseNotableAnomaliesSearchProps { @@ -57,19 +48,20 @@ export const useNotableAnomaliesSearch = ({ refetch: inputsModel.Refetch; } => { const [data, setData] = useState(formatResultData([], [])); - const refetch = useRef(noop); const { - loading: installedJobsLoading, - isMlUser, - jobs: installedSecurityJobs, - } = useInstalledSecurityJobs(); + loading: jobsLoading, + isMlAdmin: isMlUser, + jobs: securityJobs, + refetch: refetchJobs, + } = useSecurityJobs(); + const [loading, setLoading] = useState(true); const { addError } = useAppToasts(); const [anomalyScoreThreshold] = useUiSetting$(DEFAULT_ANOMALY_SCORE); const { notableAnomaliesJobs, query } = useMemo(() => { - const newNotableAnomaliesJobs = installedSecurityJobs.filter(({ id }) => + const newNotableAnomaliesJobs = securityJobs.filter(({ id }) => NOTABLE_ANOMALIES_IDS.some((notableJobId) => matchJobId(id, notableJobId)) ); @@ -84,7 +76,7 @@ export const useNotableAnomaliesSearch = ({ query: newQuery, notableAnomaliesJobs: newNotableAnomaliesJobs, }; - }, [installedSecurityJobs, anomalyScoreThreshold, from, to]); + }, [securityJobs, anomalyScoreThreshold, from, to]); useEffect(() => { let isSubscribed = true; @@ -102,7 +94,7 @@ export const useNotableAnomaliesSearch = ({ try { const response = await notableAnomaliesSearch( { - jobIds: notableAnomaliesJobs.map(({ id }) => id), + jobIds: notableAnomaliesJobs.filter((job) => job.isInstalled).map(({ id }) => id), query, }, abortCtrl.signal @@ -110,7 +102,7 @@ export const useNotableAnomaliesSearch = ({ if (isSubscribed) { setLoading(false); - const buckets = response.aggregations.number_of_anomalies.buckets; + const buckets = response.aggregations?.number_of_anomalies.buckets ?? []; setData(formatResultData(buckets, notableAnomaliesJobs)); } } catch (error) { @@ -122,32 +114,14 @@ export const useNotableAnomaliesSearch = ({ } fetchAnomaliesSearch(); - refetch.current = fetchAnomaliesSearch; + return () => { isSubscribed = false; abortCtrl.abort(); }; - }, [skip, isMlUser, addError, query, notableAnomaliesJobs]); + }, [skip, isMlUser, addError, query, notableAnomaliesJobs, refetchJobs]); - return { isLoading: loading || installedJobsLoading, data, refetch: refetch.current }; -}; - -const getMLJobStatus = ( - notableJobId: NotableAnomaliesJobId, - job: MlSummaryJob | undefined, - notableAnomaliesJobs: MlSummaryJob[] -) => { - if (job) { - if (isJobStarted(job.jobState, job.datafeedState)) { - return AnomalyJobStatus.enabled; - } - if (isJobFailed(job.jobState, job.datafeedState)) { - return AnomalyJobStatus.failed; - } - } - return notableAnomaliesJobs.some(({ id }) => matchJobId(id, notableJobId)) - ? AnomalyJobStatus.disabled - : AnomalyJobStatus.uninstalled; + return { isLoading: loading || jobsLoading, data, refetch: refetchJobs }; }; function formatResultData( @@ -155,7 +129,7 @@ function formatResultData( key: string; doc_count: number; }>, - notableAnomaliesJobs: MlSummaryJob[] + notableAnomaliesJobs: SecurityJob[] ): AnomaliesCount[] { return NOTABLE_ANOMALIES_IDS.map((notableJobId) => { const job = findJobWithId(notableJobId)(notableAnomaliesJobs); @@ -164,10 +138,9 @@ function formatResultData( return { name: notableJobId, - jobId: job?.id, count: bucket?.doc_count ?? 0, - status: getMLJobStatus(notableJobId, job, notableAnomaliesJobs), entity: hasUserName ? AnomalyEntity.User : AnomalyEntity.Host, + job, }; }); } @@ -183,8 +156,8 @@ const matchJobId = (jobId: string, notableJobId: NotableAnomaliesJobId) => * When multiple jobs match a notable job id, it returns the most recent one. */ const findJobWithId = (notableJobId: NotableAnomaliesJobId) => - pipe( - filter(({ id }) => matchJobId(id, notableJobId)), - orderBy('latestTimestampSortValue', 'desc'), + pipe( + filter(({ id }) => matchJobId(id, notableJobId)), + orderBy('latestTimestampSortValue', 'desc'), head ); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/api/anomalies_search.ts b/x-pack/plugins/security_solution/public/common/components/ml/api/anomalies_search.ts index 2431b3da3220d..966137c616f99 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/api/anomalies_search.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/api/anomalies_search.ts @@ -14,7 +14,7 @@ export interface Body { } export interface AnomaliesSearchResponse { - aggregations: { + aggregations?: { number_of_anomalies: { buckets: Array<{ key: NotableAnomaliesJobId; diff --git a/x-pack/plugins/security_solution/public/common/components/ml/api/errors.ts b/x-pack/plugins/security_solution/public/common/components/ml/api/errors.ts index b289890bb4335..5fad08ed0979a 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/api/errors.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/api/errors.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { ErrorResponseBase } from '@elastic/elasticsearch/lib/api/types'; import { has } from 'lodash/fp'; import type { MlError } from '../types'; @@ -19,3 +20,6 @@ export interface MlStartJobError { // Otherwise for now, has will work ok even though it casts 'unknown' to 'any' export const isMlStartJobError = (value: unknown): value is MlStartJobError => has('error.msg', value) && has('error.response', value) && has('error.statusCode', value); + +export const isUnknownError = (value: unknown): value is ErrorResponseBase => + has('error.error.reason', value); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/api/throw_if_not_ok.ts b/x-pack/plugins/security_solution/public/common/components/ml/api/throw_if_not_ok.ts index c4bd1888627f3..f88de77348322 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/api/throw_if_not_ok.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/api/throw_if_not_ok.ts @@ -8,7 +8,7 @@ import * as i18n from './translations'; import { ToasterError } from '../../toasters'; import type { SetupMlResponse } from '../../ml_popover/types'; -import { isMlStartJobError } from './errors'; +import { isMlStartJobError, isUnknownError } from './errors'; export const tryParseResponse = (response: string): string => { try { @@ -22,18 +22,21 @@ export const throwIfErrorAttachedToSetup = ( setupResponse: SetupMlResponse, jobIdErrorFilter: string[] = [] ): void => { - const jobErrors = setupResponse.jobs.reduce( - (accum, job) => - job.error != null && jobIdErrorFilter.includes(job.id) - ? [ - ...accum, - job.error.msg, - tryParseResponse(job.error.response), - `${i18n.STATUS_CODE} ${job.error.statusCode}`, - ] - : accum, - [] - ); + const jobErrors = setupResponse.jobs.reduce((accum, job) => { + if (job.error != null && jobIdErrorFilter.includes(job.id)) { + if (isMlStartJobError(job)) { + return [ + ...accum, + job.error.msg, + tryParseResponse(job.error.response), + `${i18n.STATUS_CODE} ${job.error.statusCode}`, + ]; + } else if (isUnknownError(job)) { + return [job.error.error.reason]; + } + } + return accum; + }, []); const dataFeedErrors = setupResponse.datafeeds.reduce( (accum, dataFeed) => @@ -67,6 +70,8 @@ export const throwIfErrorAttached = ( tryParseResponse(dataFeed.error.response), `${i18n.STATUS_CODE} ${dataFeed.error.statusCode}`, ]; + } else if (isUnknownError(dataFeed)) { + return [dataFeed.error.error.reason]; } else { return accum; } diff --git a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs.ts b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs.ts index ec87d2e2c22a5..0fcbe7eb39850 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs.ts @@ -28,6 +28,7 @@ export interface UseGetInstalledJobReturn { isLicensed: boolean; } +// TODO react-query export const useGetInstalledJob = (jobIds: string[]): UseGetInstalledJobReturn => { const [jobs, setJobs] = useState([]); const { addError } = useAppToasts(); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts index 129e41f575318..9d0a3870aca13 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts @@ -10,4 +10,5 @@ import { getJobsSummary } from '../api/get_jobs_summary'; const _getJobsSummary = withOptionalSignal(getJobsSummary); +// TODO rewrite to react-query export const useGetJobsSummary = () => useAsync(_getJobsSummary); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/translations.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/translations.ts new file mode 100644 index 0000000000000..0553ab20985b1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/translations.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 { i18n } from '@kbn/i18n'; + +export const START_JOB_FAILURE = i18n.translate( + 'xpack.securitySolution.components.mlPopup.hooks.errors.startJobFailureTitle', + { + defaultMessage: 'Start job failure', + } +); + +export const STOP_JOB_FAILURE = i18n.translate( + 'xpack.securitySolution.components.mlPopup.hooks.errors.stopJobFailureTitle', + { + defaultMessage: 'Stop job failure', + } +); + +export const CREATE_JOB_FAILURE = i18n.translate( + 'xpack.securitySolution.components.mlPopup.hooks.errors.createJobFailureTitle', + { + defaultMessage: 'Create job failure', + } +); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx new file mode 100644 index 0000000000000..0f5289ae587d7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx @@ -0,0 +1,146 @@ +/* + * 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 React from 'react'; +import { renderHook, act } from '@testing-library/react-hooks'; +import { useEnableDataFeed } from './use_enable_data_feed'; +import { + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, + TestProviders, +} from '../../../mock'; +import { createStore } from '../../../store'; +import type { State } from '../../../store'; + +import type { SecurityJob } from '../types'; +import { tGridReducer } from '@kbn/timelines-plugin/public'; + +const state: State = mockGlobalState; +const { storage } = createSecuritySolutionStorageMock(); +const store = createStore( + state, + SUB_PLUGINS_REDUCER, + { dataTable: tGridReducer }, + kibanaObservable, + storage +); + +const wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} +); + +const TIMESTAMP = 99999999; +const JOB = { + isInstalled: false, + datafeedState: 'failed', + jobState: 'failed', + isCompatible: true, +} as SecurityJob; + +const mockSetupMlJob = jest.fn().mockReturnValue(Promise.resolve()); +const mockStartDatafeeds = jest.fn().mockReturnValue(Promise.resolve()); +const mockStopDatafeeds = jest.fn().mockReturnValue(Promise.resolve()); + +jest.mock('../api', () => ({ + setupMlJob: () => mockSetupMlJob(), + startDatafeeds: (...params: unknown[]) => mockStartDatafeeds(...params), + stopDatafeeds: () => mockStopDatafeeds(), +})); + +describe('useSecurityJobsHelpers', () => { + afterEach(() => { + mockSetupMlJob.mockReset(); + mockStartDatafeeds.mockReset(); + mockStopDatafeeds.mockReset(); + }); + + it('renders isLoading=true when installing job', async () => { + let resolvePromiseCb: (value: unknown) => void; + mockSetupMlJob.mockReturnValue( + new Promise((resolve) => { + resolvePromiseCb = resolve; + }) + ); + const { result, waitForNextUpdate } = renderHook(() => useEnableDataFeed(), { + wrapper, + }); + expect(result.current.isLoading).toBe(false); + + await act(async () => { + const enableDataFeedPromise = result.current.enableDatafeed(JOB, TIMESTAMP, false); + + await waitForNextUpdate(); + expect(result.current.isLoading).toBe(true); + + resolvePromiseCb({}); + await enableDataFeedPromise; + expect(result.current.isLoading).toBe(false); + }); + }); + + it('does not call setupMlJob if job is already installed', async () => { + mockSetupMlJob.mockReturnValue(Promise.resolve()); + const { result } = renderHook(() => useEnableDataFeed(), { + wrapper, + }); + + await act(async () => { + await result.current.enableDatafeed({ ...JOB, isInstalled: true }, TIMESTAMP, false); + }); + + expect(mockSetupMlJob).not.toBeCalled(); + }); + + it('calls setupMlJob if job is uninstalled', async () => { + mockSetupMlJob.mockReturnValue(Promise.resolve()); + const { result } = renderHook(() => useEnableDataFeed(), { + wrapper, + }); + await act(async () => { + await result.current.enableDatafeed({ ...JOB, isInstalled: false }, TIMESTAMP, false); + }); + expect(mockSetupMlJob).toBeCalled(); + }); + + it('calls startDatafeeds if enable param is true', async () => { + const { result } = renderHook(() => useEnableDataFeed(), { + wrapper, + }); + await act(async () => { + await result.current.enableDatafeed(JOB, TIMESTAMP, true); + }); + expect(mockStartDatafeeds).toBeCalled(); + expect(mockStopDatafeeds).not.toBeCalled(); + }); + + it('calls stopDatafeeds if enable param is false', async () => { + const { result } = renderHook(() => useEnableDataFeed(), { + wrapper, + }); + await act(async () => { + await result.current.enableDatafeed(JOB, TIMESTAMP, false); + }); + expect(mockStartDatafeeds).not.toBeCalled(); + expect(mockStopDatafeeds).toBeCalled(); + }); + + it('calls startDatafeeds with 2 weeks old start date', async () => { + jest.useFakeTimers('modern').setSystemTime(new Date('1989-03-07')); + + const { result } = renderHook(() => useEnableDataFeed(), { + wrapper, + }); + await act(async () => { + await result.current.enableDatafeed(JOB, TIMESTAMP, true); + }); + expect(mockStartDatafeeds).toBeCalledWith({ + datafeedIds: [`datafeed-undefined`], + start: new Date('1989-02-21').getTime(), + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.ts new file mode 100644 index 0000000000000..2d73d07c1787c --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.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 { useCallback, useState } from 'react'; +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../lib/telemetry'; +import { setupMlJob, startDatafeeds, stopDatafeeds } from '../api'; +import type { SecurityJob } from '../types'; +import * as i18n from './translations'; + +// Enable/Disable Job & Datafeed -- passed to JobsTable for use as callback on JobSwitch +export const useEnableDataFeed = () => { + const { addError } = useAppToasts(); + const [isLoading, setIsLoading] = useState(false); + + const enableDatafeed = useCallback( + async (job: SecurityJob, latestTimestampMs: number, enable: boolean) => { + submitTelemetry(job, enable); + + if (!job.isInstalled) { + setIsLoading(true); + try { + await setupMlJob({ + configTemplate: job.moduleId, + indexPatternName: job.defaultIndexPattern, + jobIdErrorFilter: [job.id], + groups: job.groups, + }); + setIsLoading(false); + } catch (error) { + addError(error, { title: i18n.CREATE_JOB_FAILURE }); + setIsLoading(false); + return; + } + } + + // Max start time for job is no more than two weeks ago to ensure job performance + const date = new Date(); + const maxStartTime = date.setDate(date.getDate() - 14); + + setIsLoading(true); + if (enable) { + const startTime = Math.max(latestTimestampMs, maxStartTime); + try { + await startDatafeeds({ datafeedIds: [`datafeed-${job.id}`], start: startTime }); + } catch (error) { + track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_ENABLE_FAILURE); + addError(error, { title: i18n.START_JOB_FAILURE }); + } + } else { + try { + await stopDatafeeds({ datafeedIds: [`datafeed-${job.id}`] }); + } catch (error) { + track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_DISABLE_FAILURE); + addError(error, { title: i18n.STOP_JOB_FAILURE }); + } + } + setIsLoading(false); + }, + [addError] + ); + + return { enableDatafeed, isLoading }; +}; + +const submitTelemetry = (job: SecurityJob, enabled: boolean) => { + // Report type of job enabled/disabled + track( + METRIC_TYPE.COUNT, + job.isElasticJob + ? enabled + ? TELEMETRY_EVENT.SIEM_JOB_ENABLED + : TELEMETRY_EVENT.SIEM_JOB_DISABLED + : enabled + ? TELEMETRY_EVENT.CUSTOM_JOB_ENABLED + : TELEMETRY_EVENT.CUSTOM_JOB_DISABLED + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts index db564d13456a0..23b284264387b 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts @@ -71,7 +71,7 @@ describe('useSecurityJobs', () => { bucketSpanSeconds: 900, }; - const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(false)); + const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs()); await waitForNextUpdate(); expect(result.current.jobs).toHaveLength(6); @@ -79,7 +79,7 @@ describe('useSecurityJobs', () => { }); it('returns those permissions', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(false)); + const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs()); await waitForNextUpdate(); expect(result.current.isMlAdmin).toEqual(true); @@ -88,7 +88,7 @@ describe('useSecurityJobs', () => { it('renders a toast error if an ML call fails', async () => { (getModules as jest.Mock).mockRejectedValue('whoops'); - const { waitForNextUpdate } = renderHook(() => useSecurityJobs(false)); + const { waitForNextUpdate } = renderHook(() => useSecurityJobs()); await waitForNextUpdate(); expect(appToastsMock.addError).toHaveBeenCalledWith('whoops', { @@ -104,7 +104,7 @@ describe('useSecurityJobs', () => { }); it('returns empty jobs and false predicates', () => { - const { result } = renderHook(() => useSecurityJobs(false)); + const { result } = renderHook(() => useSecurityJobs()); expect(result.current.jobs).toEqual([]); expect(result.current.isMlAdmin).toEqual(false); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts index c7d2c07eec2dd..4f39fd1a746c8 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; +import { noop } from 'lodash/fp'; import { DEFAULT_INDEX_KEY } from '../../../../../common/constants'; import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; @@ -18,12 +19,14 @@ import { createSecurityJobs } from './use_security_jobs_helpers'; import { useMlCapabilities } from '../../ml/hooks/use_ml_capabilities'; import * as i18n from '../../ml/translations'; import { getJobsSummary } from '../../ml/api/get_jobs_summary'; +import type { inputsModel } from '../../../store'; export interface UseSecurityJobsReturn { loading: boolean; jobs: SecurityJob[]; isMlAdmin: boolean; isLicensed: boolean; + refetch: inputsModel.Refetch; } /** @@ -35,25 +38,24 @@ export interface UseSecurityJobsReturn { * NOTE: If the user is not an ml admin, jobs will be empty and isMlAdmin will be false. * If you only need installed jobs, try the {@link useInstalledSecurityJobs} hook. * - * @param refetchData */ -export const useSecurityJobs = (refetchData: boolean): UseSecurityJobsReturn => { +export const useSecurityJobs = (): UseSecurityJobsReturn => { const [jobs, setJobs] = useState([]); const [loading, setLoading] = useState(true); const mlCapabilities = useMlCapabilities(); const [securitySolutionDefaultIndex] = useUiSetting$(DEFAULT_INDEX_KEY); const http = useHttp(); const { addError } = useAppToasts(); - + const refetch = useRef(noop); const isMlAdmin = hasMlAdminPermissions(mlCapabilities); const isLicensed = hasMlLicense(mlCapabilities); useEffect(() => { let isSubscribed = true; const abortCtrl = new AbortController(); - setLoading(true); async function fetchSecurityJobIdsFromGroupsData() { + setLoading(true); if (isMlAdmin && isLicensed) { try { // Batch fetch all installed jobs, ML modules, and check which modules are compatible with securitySolutionDefaultIndex @@ -87,11 +89,13 @@ export const useSecurityJobs = (refetchData: boolean): UseSecurityJobsReturn => } fetchSecurityJobIdsFromGroupsData(); + + refetch.current = fetchSecurityJobIdsFromGroupsData; return () => { isSubscribed = false; abortCtrl.abort(); }; - }, [refetchData, isMlAdmin, isLicensed, securitySolutionDefaultIndex, addError, http]); + }, [isMlAdmin, isLicensed, securitySolutionDefaultIndex, addError, http]); - return { isLicensed, isMlAdmin, jobs, loading }; + return { isLicensed, isMlAdmin, jobs, loading, refetch: refetch.current }; }; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx index accb9eb6d7387..9483c549485de 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx @@ -13,17 +13,10 @@ import { EuiSpacer, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import moment from 'moment'; -import type { Dispatch } from 'react'; -import React, { useCallback, useReducer, useState, useMemo } from 'react'; +import React, { useCallback, useState, useMemo } from 'react'; import styled from 'styled-components'; - import { MLJobsAwaitingNodeWarning } from '@kbn/ml-plugin/public'; import { useKibana } from '../../lib/kibana'; -import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../lib/telemetry'; -import type { ActionToaster } from '../toasters'; -import { errorToToaster, useStateToaster } from '../toasters'; -import { setupMlJob, startDatafeeds, stopDatafeeds } from './api'; import { filterJobs } from './helpers'; import { JobsTableFilters } from './jobs_table/filters/jobs_table_filters'; import { JobsTable } from './jobs_table/jobs_table'; @@ -33,6 +26,7 @@ import * as i18n from './translations'; import type { JobsFilters, SecurityJob } from './types'; import { UpgradeContents } from './upgrade_contents'; import { useSecurityJobs } from './hooks/use_security_jobs'; +import { useEnableDataFeed } from './hooks/use_enable_data_feed'; const PopoverContentsDiv = styled.div` max-width: 684px; @@ -44,49 +38,6 @@ const PopoverContentsDiv = styled.div` PopoverContentsDiv.displayName = 'PopoverContentsDiv'; -interface State { - isLoading: boolean; - refreshToggle: boolean; -} - -type Action = { type: 'refresh' } | { type: 'loading' } | { type: 'success' } | { type: 'failure' }; - -function mlPopoverReducer(state: State, action: Action): State { - switch (action.type) { - case 'refresh': { - return { - ...state, - refreshToggle: !state.refreshToggle, - }; - } - case 'loading': { - return { - ...state, - isLoading: true, - }; - } - case 'success': { - return { - ...state, - isLoading: false, - }; - } - case 'failure': { - return { - ...state, - isLoading: false, - }; - } - default: - return state; - } -} - -const initialState: State = { - isLoading: false, - refreshToggle: true, -}; - const defaultFilterProps: JobsFilters = { filterQuery: '', showCustomJobs: false, @@ -95,8 +46,6 @@ const defaultFilterProps: JobsFilters = { }; export const MlPopover = React.memo(() => { - const [{ isLoading, refreshToggle }, dispatch] = useReducer(mlPopoverReducer, initialState); - const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [filterProperties, setFilterProperties] = useState(defaultFilterProps); const { @@ -104,13 +53,18 @@ export const MlPopover = React.memo(() => { isLicensed, loading: isLoadingSecurityJobs, jobs, - } = useSecurityJobs(refreshToggle); - const [, dispatchToaster] = useStateToaster(); + refetch: refreshJobs, + } = useSecurityJobs(); + const docLinks = useKibana().services.docLinks; + const { enableDatafeed, isLoading: isLoadingEnableDataFeed } = useEnableDataFeed(); const handleJobStateChange = useCallback( - (job: SecurityJob, latestTimestampMs: number, enable: boolean) => - enableDatafeed(job, latestTimestampMs, enable, dispatch, dispatchToaster), - [dispatch, dispatchToaster] + async (job: SecurityJob, latestTimestampMs: number, enable: boolean) => { + const result = await enableDatafeed(job, latestTimestampMs, enable); + refreshJobs(); + return result; + }, + [refreshJobs, enableDatafeed] ); const filteredJobs = filterJobs({ @@ -169,7 +123,7 @@ export const MlPopover = React.memo(() => { iconSide="right" onClick={() => { setIsPopoverOpen(!isPopoverOpen); - dispatch({ type: 'refresh' }); + refreshJobs(); }} textProps={{ style: { fontSize: '1rem' } }} > @@ -225,7 +179,7 @@ export const MlPopover = React.memo(() => { @@ -238,68 +192,4 @@ export const MlPopover = React.memo(() => { } }); -// Enable/Disable Job & Datafeed -- passed to JobsTable for use as callback on JobSwitch -const enableDatafeed = async ( - job: SecurityJob, - latestTimestampMs: number, - enable: boolean, - dispatch: Dispatch, - dispatchToaster: Dispatch -) => { - submitTelemetry(job, enable); - - if (!job.isInstalled) { - dispatch({ type: 'loading' }); - try { - await setupMlJob({ - configTemplate: job.moduleId, - indexPatternName: job.defaultIndexPattern, - jobIdErrorFilter: [job.id], - groups: job.groups, - }); - dispatch({ type: 'success' }); - } catch (error) { - errorToToaster({ title: i18n.CREATE_JOB_FAILURE, error, dispatchToaster }); - dispatch({ type: 'failure' }); - dispatch({ type: 'refresh' }); - return; - } - } - - // Max start time for job is no more than two weeks ago to ensure job performance - const maxStartTime = moment.utc().subtract(14, 'days').valueOf(); - - if (enable) { - const startTime = Math.max(latestTimestampMs, maxStartTime); - try { - await startDatafeeds({ datafeedIds: [`datafeed-${job.id}`], start: startTime }); - } catch (error) { - track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_ENABLE_FAILURE); - errorToToaster({ title: i18n.START_JOB_FAILURE, error, dispatchToaster }); - } - } else { - try { - await stopDatafeeds({ datafeedIds: [`datafeed-${job.id}`] }); - } catch (error) { - track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_DISABLE_FAILURE); - errorToToaster({ title: i18n.STOP_JOB_FAILURE, error, dispatchToaster }); - } - } - dispatch({ type: 'refresh' }); -}; - -const submitTelemetry = (job: SecurityJob, enabled: boolean) => { - // Report type of job enabled/disabled - track( - METRIC_TYPE.COUNT, - job.isElasticJob - ? enabled - ? TELEMETRY_EVENT.SIEM_JOB_ENABLED - : TELEMETRY_EVENT.SIEM_JOB_DISABLED - : enabled - ? TELEMETRY_EVENT.CUSTOM_JOB_ENABLED - : TELEMETRY_EVENT.CUSTOM_JOB_DISABLED - ); -}; - MlPopover.displayName = 'MlPopover'; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts index 08df99d5cebeb..2fa1178060005 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/translations.ts @@ -41,24 +41,3 @@ export const MODULE_NOT_COMPATIBLE_TITLE = (incompatibleJobCount: number) => defaultMessage: '{incompatibleJobCount} {incompatibleJobCount, plural, =1 {job} other {jobs}} are currently unavailable', }); - -export const START_JOB_FAILURE = i18n.translate( - 'xpack.securitySolution.components.mlPopup.errors.startJobFailureTitle', - { - defaultMessage: 'Start job failure', - } -); - -export const STOP_JOB_FAILURE = i18n.translate( - 'xpack.securitySolution.containers.errors.stopJobFailureTitle', - { - defaultMessage: 'Stop job failure', - } -); - -export const CREATE_JOB_FAILURE = i18n.translate( - 'xpack.securitySolution.components.mlPopup.errors.createJobFailureTitle', - { - defaultMessage: 'Create job failure', - } -); diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx index a4364c8564529..3c043950b758c 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx +++ b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx @@ -133,6 +133,7 @@ function usePrimaryNavigationItemsToDisplay(navTabs: Record) { { ...securityNavGroup[SecurityNavGroupKey.manage], items: [ + // TODO: also hide other management pages based on authz privileges navTabs[SecurityPageName.endpoints], ...(isPolicyListEnabled ? [navTabs[SecurityPageName.policies]] : []), navTabs[SecurityPageName.trustedApps], diff --git a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.tsx index 857b4b11b4d88..dcd152bca45b6 100644 --- a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useMemo, useEffect } from 'react'; +import { useDispatch } from 'react-redux'; import type { Filter } from '@kbn/es-query'; import { EVENT_ACTION } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { ENTRY_SESSION_ENTITY_ID_PROPERTY, EventAction } from '@kbn/session-view-plugin/public'; @@ -21,6 +22,7 @@ import { getDefaultControlColumn } from '../../../timelines/components/timeline/ import { useLicense } from '../../hooks/use_license'; import { TableId } from '../../../../common/types/timeline'; export const TEST_ID = 'security_solution:sessions_viewer:sessions_view'; +import { dataTableActions } from '../../store/data_table'; export const defaultSessionsFilter: Required> = { query: { @@ -102,6 +104,17 @@ const SessionsViewComponent: React.FC = ({ const unit = (c: number) => c > 1 ? i18n.TOTAL_COUNT_OF_SESSIONS : i18n.SINGLE_COUNT_OF_SESSIONS; + const dispatch = useDispatch(); + + useEffect(() => { + dispatch( + dataTableActions.initializeTGridSettings({ + id: tableId, + title: i18n.SESSIONS_TITLE, + }) + ); + }, [dispatch, tableId]); + return (

    ] : []; -export const filterNetworkExternalAlertData: Filter[] = [ +export const sourceOrDestinationIpExistsFilter: Filter[] = [ { query: { bool: { - filter: [ + should: [ { - bool: { - should: [ - { - bool: { - should: [ - { - exists: { - field: 'source.ip', - }, - }, - ], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [ - { - exists: { - field: 'destination.ip', - }, - }, - ], - minimum_should_match: 1, - }, - }, - ], - minimum_should_match: 1, + exists: { + field: 'source.ip', + }, + }, + { + exists: { + field: 'destination.ip', }, }, ], + minimum_should_match: 1, }, }, meta: { diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_invalid_filter_query.tsx b/x-pack/plugins/security_solution/public/common/hooks/use_invalid_filter_query.tsx index a0cb9f941783e..04165a66154e0 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/use_invalid_filter_query.tsx +++ b/x-pack/plugins/security_solution/public/common/hooks/use_invalid_filter_query.tsx @@ -36,10 +36,13 @@ export const useInvalidFilterQuery = ({ const getErrorsSelector = useMemo(() => appSelectors.errorsSelector(), []); const errors = useDeepEqualSelector(getErrorsSelector); + const name = kqlError?.name; + const message = kqlError?.message; + useEffect(() => { - if (filterQuery === undefined && kqlError != null) { + if (!filterQuery && message && name) { // Local util for creating an replicatable error hash - const hashCode = kqlError.message + const hashCode = message .split('') // eslint-disable-next-line no-bitwise .reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0) @@ -48,14 +51,12 @@ export const useInvalidFilterQuery = ({ appActions.addErrorHash({ id, hash: hashCode, - title: kqlError.name, - message: [kqlError.message], + title: name, + message: [message], }) ); } - // This disable is required to only trigger the toast once per render - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [id, filterQuery, addError, query, startDate, endDate]); + }, [id, filterQuery, addError, query, startDate, endDate, dispatch, message, name]); useEffect(() => { const myError = errors.find((e) => e.id === id); diff --git a/x-pack/plugins/security_solution/public/common/utils/privileges/index.test.ts b/x-pack/plugins/security_solution/public/common/utils/privileges/index.test.ts new file mode 100644 index 0000000000000..34abe0dd52c9a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/utils/privileges/index.test.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 { hasUserCRUDPermission } from '.'; + +describe('privileges utils', () => { + describe('hasUserCRUDPermission', () => { + test("returns true when user's CRUD operations are null", () => { + const result = hasUserCRUDPermission(null); + + expect(result).toBeTruthy(); + }); + + test('returns false when user cannot CRUD', () => { + const result = hasUserCRUDPermission(false); + + expect(result).toBeFalsy(); + }); + + test('returns true when user can CRUD', () => { + const result = hasUserCRUDPermission(true); + + expect(result).toBeTruthy(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts b/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts index de8ad087f27e6..817bbc5f5f296 100644 --- a/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts +++ b/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { Rule } from '../../../detections/containers/detection_engine/rules'; -import * as i18n from '../../../detections/pages/detection_engine/rules/translations'; +import type { Rule } from '../../../detection_engine/rule_management/logic'; +import * as i18nActions from '../../../detections/pages/detection_engine/rules/translations'; import { isMlRule } from '../../../../common/machine_learning/helpers'; import * as detectionI18n from '../../../detections/pages/detection_engine/translations'; @@ -29,21 +29,28 @@ export const canEditRuleWithActions = ( return true; }; -export const getToolTipContent = ( +// typed as null not undefined as the initial state for this value is null. +export const hasUserCRUDPermission = (canUserCRUD: boolean | null): boolean => + canUserCRUD != null ? canUserCRUD : true; + +export const explainLackOfPermission = ( rule: Rule | null | undefined, hasMlPermissions: boolean, hasReadActionsPrivileges: | boolean | Readonly<{ [x: string]: boolean; - }> + }>, + canUserCRUD: boolean | null ): string | undefined => { if (rule == null) { return undefined; } else if (isMlRule(rule.type) && !hasMlPermissions) { return detectionI18n.ML_RULES_DISABLED_MESSAGE; } else if (!canEditRuleWithActions(rule, hasReadActionsPrivileges)) { - return i18n.EDIT_RULE_SETTINGS_TOOLTIP; + return i18nActions.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES; + } else if (!hasUserCRUDPermission(canUserCRUD)) { + return i18nActions.LACK_OF_KIBANA_SECURITY_PRIVILEGES; } else { return undefined; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/api_client.ts b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/api_client.ts new file mode 100644 index 0000000000000..e2d98118c593e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/api_client.ts @@ -0,0 +1,35 @@ +/* + * 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 { GetInstalledIntegrationsResponse } from '../../../../../common/detection_engine/fleet_integrations'; +import type { + FetchInstalledIntegrationsArgs, + IFleetIntegrationsApiClient, +} from '../api_client_interface'; + +export const fleetIntegrationsApi: jest.Mocked = { + fetchInstalledIntegrations: jest + .fn, [FetchInstalledIntegrationsArgs]>() + .mockResolvedValue({ + installed_integrations: [ + { + package_name: 'atlassian_bitbucket', + package_title: 'Atlassian Bitbucket', + package_version: '1.0.1', + integration_name: 'audit', + integration_title: 'Audit Logs', + is_enabled: true, + }, + { + package_name: 'system', + package_title: 'System', + package_version: '1.6.4', + is_enabled: true, + }, + ], + }), +}; diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/index.ts b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/index.ts similarity index 81% rename from x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/index.ts index 7bbcc43230a44..ebfcff4941a99 100644 --- a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { AlertsTableTGrid } from './alerts_table_t_grid'; +export * from './api_client'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/api_client.ts b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/api_client.ts new file mode 100644 index 0000000000000..58cd7b17a1fb5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/api_client.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 type { GetInstalledIntegrationsResponse } from '../../../../common/detection_engine/fleet_integrations'; +import { GET_INSTALLED_INTEGRATIONS_URL } from '../../../../common/detection_engine/fleet_integrations'; +import { KibanaServices } from '../../../common/lib/kibana'; + +import type { + FetchInstalledIntegrationsArgs, + IFleetIntegrationsApiClient, +} from './api_client_interface'; + +export const fleetIntegrationsApi: IFleetIntegrationsApiClient = { + fetchInstalledIntegrations: ( + args: FetchInstalledIntegrationsArgs + ): Promise => { + const { packages, signal } = args; + + return http().fetch(GET_INSTALLED_INTEGRATIONS_URL, { + method: 'GET', + query: { + packages: packages?.sort()?.join(','), + }, + signal, + }); + }, +}; + +const http = () => KibanaServices.get().http; diff --git a/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/api_client_interface.ts b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/api_client_interface.ts new file mode 100644 index 0000000000000..4776b6e5528af --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/api_client_interface.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 type { GetInstalledIntegrationsResponse } from '../../../../common/detection_engine/fleet_integrations'; + +export interface IFleetIntegrationsApiClient { + /** + * Fetch all installed integrations. + * @throws An error if response is not OK + */ + fetchInstalledIntegrations( + args: FetchInstalledIntegrationsArgs + ): Promise; +} + +export interface FetchInstalledIntegrationsArgs { + /** + * Array of Fleet packages to filter for. + */ + packages?: string[]; + + /** + * Optional signal for cancelling the request. + */ + signal?: AbortSignal; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/index.ts b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/index.ts new file mode 100644 index 0000000000000..f20ead0b41939 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export * from './api_client_interface'; +export * from './api_client'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/index.ts b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/index.ts new file mode 100644 index 0000000000000..473b51dc47c28 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './api'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.test.ts similarity index 97% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.test.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.test.ts index 2ab0c7ae0b5b2..af6a82af1a9d5 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.test.ts @@ -6,12 +6,12 @@ */ import type { List } from '@kbn/securitysolution-io-ts-list-types'; -import type { CreateRulesSchema } from '../../../../../../common/detection_engine/schemas/request'; -import type { Rule } from '../../../../containers/detection_engine/rules'; +import type { RuleCreateProps } from '../../../../../common/detection_engine/rule_schema'; +import type { Rule } from '../../../rule_management/logic'; import { getListMock, getEndpointListMock, -} from '../../../../../../common/detection_engine/schemas/types/lists.mock'; +} from '../../../../../common/detection_engine/schemas/types/lists.mock'; import type { DefineStepRuleJson, ScheduleStepRuleJson, @@ -21,7 +21,7 @@ import type { ActionsStepRule, ScheduleStepRule, DefineStepRule, -} from '../types'; +} from '../../../../detections/pages/detection_engine/rules/types'; import { getTimeTypeValue, formatDefineStepData, @@ -38,8 +38,8 @@ import { mockScheduleStepRule, mockAboutStepRule, mockActionsStepRule, -} from '../all/__mocks__/mock'; -import { getThreatMock } from '../../../../../../common/detection_engine/schemas/types/threat.mock'; +} from '../../../rule_management_ui/components/rules_table/__mocks__/mock'; +import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; import type { Threat, Threats } from '@kbn/securitysolution-io-ts-alerting-types'; describe('helpers', () => { @@ -958,7 +958,7 @@ describe('helpers', () => { saved_id: '', }, }; - const result = formatRule( + const result = formatRule( mockDefineStepRuleWithoutSavedId, mockAbout, mockSchedule, @@ -969,14 +969,9 @@ describe('helpers', () => { }); test('returns rule without id if ruleId does not exist', () => { - const result = formatRule( - mockDefine, - mockAbout, - mockSchedule, - mockActions - ); + const result = formatRule(mockDefine, mockAbout, mockSchedule, mockActions); - expect(result).not.toHaveProperty('id'); + expect(result).not.toHaveProperty('id'); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts similarity index 96% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts index 9beeb17d3a1bb..6686239e053f9 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts @@ -23,12 +23,12 @@ import type { Type, } from '@kbn/securitysolution-io-ts-alerting-types'; import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; -import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../common/constants'; -import { assertUnreachable } from '../../../../../../common/utility_types'; +import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../common/constants'; +import { assertUnreachable } from '../../../../../common/utility_types'; import { transformAlertToRuleAction, transformAlertToRuleResponseAction, -} from '../../../../../../common/detection_engine/transform_actions'; +} from '../../../../../common/detection_engine/transform_actions'; import type { AboutStepRule, @@ -41,10 +41,10 @@ import type { ActionsStepRuleJson, RuleStepsFormData, RuleStep, -} from '../types'; -import { DataSourceType } from '../types'; -import type { CreateRulesSchema } from '../../../../../../common/detection_engine/schemas/request'; -import { stepActionsDefaultValue } from '../../../../components/rules/step_rule_actions'; +} from '../../../../detections/pages/detection_engine/rules/types'; +import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; +import type { RuleCreateProps } from '../../../../../common/detection_engine/rule_schema'; +import { stepActionsDefaultValue } from '../../../../detections/components/rules/step_rule_actions'; export const getTimeTypeValue = (time: string): { unit: Unit; value: number } => { const timeObj: { unit: Unit; value: number } = { @@ -568,7 +568,7 @@ export const formatActionsStepData = (actionsStepData: ActionsStepRule): Actions // Used to format form data in rule edit and // create flows so "T" here would likely -// either be CreateRulesSchema or Rule +// either be RuleCreateProps or Rule export const formatRule = ( defineStepData: DefineStepRule, aboutStepData: AboutStepRule, @@ -593,14 +593,14 @@ export const formatPreviewRule = ({ aboutRuleData: AboutStepRule; scheduleRuleData: ScheduleStepRule; exceptionsList?: List[]; -}): CreateRulesSchema => { +}): RuleCreateProps => { const aboutStepData = { ...aboutRuleData, name: 'Preview Rule', description: 'Preview Rule', }; return { - ...formatRule( + ...formatRule( defineRuleData, aboutStepData, scheduleRuleData, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx similarity index 88% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx index 0a4914274d2e6..a5dbc91d1709b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx @@ -18,32 +18,32 @@ import React, { useCallback, useRef, useState, useMemo, useEffect } from 'react' import styled from 'styled-components'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; -import { isThreatMatchRule } from '../../../../../../common/detection_engine/utils'; -import { useCreateRule } from '../../../../containers/detection_engine/rules'; -import type { CreateRulesSchema } from '../../../../../../common/detection_engine/schemas/request'; -import { useListsConfig } from '../../../../containers/detection_engine/lists/use_lists_config'; +import { isThreatMatchRule } from '../../../../../common/detection_engine/utils'; +import { useCreateRule } from '../../../rule_management/logic'; +import type { RuleCreateProps } from '../../../../../common/detection_engine/rule_schema'; +import { useListsConfig } from '../../../../detections/containers/detection_engine/lists/use_lists_config'; +import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; import { getDetectionEngineUrl, getRuleDetailsUrl, getRulesUrl, -} from '../../../../../common/components/link_to/redirect_to_detection_engine'; -import { SecuritySolutionPageWrapper } from '../../../../../common/components/page_wrapper'; -import { displaySuccessToast, useStateToaster } from '../../../../../common/components/toasters'; -import { SpyRoute } from '../../../../../common/utils/route/spy_routes'; -import { useUserData } from '../../../../components/user_info'; -import { AccordionTitle } from '../../../../components/rules/accordion_title'; -import { StepDefineRule } from '../../../../components/rules/step_define_rule'; -import { StepAboutRule } from '../../../../components/rules/step_about_rule'; -import { StepScheduleRule } from '../../../../components/rules/step_schedule_rule'; -import { StepRuleActions } from '../../../../components/rules/step_rule_actions'; -import * as RuleI18n from '../translations'; +} from '../../../../common/components/link_to/redirect_to_detection_engine'; +import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; +import { displaySuccessToast, useStateToaster } from '../../../../common/components/toasters'; +import { SpyRoute } from '../../../../common/utils/route/spy_routes'; +import { useUserData } from '../../../../detections/components/user_info'; +import { AccordionTitle } from '../../../../detections/components/rules/accordion_title'; +import { StepDefineRule } from '../../../../detections/components/rules/step_define_rule'; +import { StepAboutRule } from '../../../../detections/components/rules/step_about_rule'; +import { StepScheduleRule } from '../../../../detections/components/rules/step_schedule_rule'; +import { StepRuleActions } from '../../../../detections/components/rules/step_rule_actions'; +import * as RuleI18n from '../../../../detections/pages/detection_engine/rules/translations'; import { redirectToDetections, getActionMessageParams, - userHasPermissions, MaxWidthEuiFlexItem, -} from '../helpers'; +} from '../../../../detections/pages/detection_engine/rules/helpers'; import type { AboutStepRule, DefineStepRule, @@ -51,26 +51,26 @@ import type { RuleStepsFormData, RuleStepsFormHooks, RuleStepsData, -} from '../types'; -import { RuleStep } from '../types'; +} from '../../../../detections/pages/detection_engine/rules/types'; +import { RuleStep } from '../../../../detections/pages/detection_engine/rules/types'; import { formatRule, stepIsValid } from './helpers'; import * as i18n from './translations'; -import { SecurityPageName } from '../../../../../app/types'; +import { SecurityPageName } from '../../../../app/types'; import { getStepScheduleDefaultValue, ruleStepsOrder, stepAboutDefaultValue, stepDefineDefaultValue, -} from '../utils'; +} from '../../../../detections/pages/detection_engine/rules/utils'; import { APP_UI_ID, DEFAULT_INDEX_KEY, DEFAULT_INDICATOR_SOURCE_PATH, DEFAULT_THREAT_INDEX_KEY, -} from '../../../../../../common/constants'; -import { useKibana, useUiSetting$ } from '../../../../../common/lib/kibana'; -import { HeaderPage } from '../../../../../common/components/header_page'; -import { PreviewFlyout } from '../preview'; +} from '../../../../../common/constants'; +import { useKibana, useUiSetting$ } from '../../../../common/lib/kibana'; +import { HeaderPage } from '../../../../common/components/header_page'; +import { PreviewFlyout } from '../../../../detections/pages/detection_engine/rules/preview'; const formHookNoop = async (): Promise => undefined; @@ -163,9 +163,8 @@ const CreateRulePageComponent: React.FC = () => { [RuleStep.scheduleRule]: false, [RuleStep.ruleActions]: false, }); - const [{ isLoading, ruleId }, setRule] = useCreateRule(); + const { mutateAsync: createRule, isLoading } = useCreateRule(); const ruleType = stepsData.current[RuleStep.defineRule].data?.ruleType; - const ruleName = stepsData.current[RuleStep.aboutRule].data?.name; const actionMessageParams = useMemo(() => getActionMessageParams(ruleType), [ruleType]); const [dataViewOptions, setDataViewOptions] = useState<{ [x: string]: DataViewListItem }>({}); const [isPreviewDisabled, setIsPreviewDisabled] = useState(false); @@ -286,19 +285,25 @@ const CreateRulePageComponent: React.FC = () => { stepIsValid(scheduleStep) && stepIsValid(actionsStep) ) { - setRule( - formatRule( + const createdRule = await createRule( + formatRule( defineStep.data, aboutStep.data, scheduleStep.data, actionsStep.data ) ); + + displaySuccessToast(i18n.SUCCESSFULLY_CREATED_RULES(createdRule.name), dispatchToaster); + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.rules, + path: getRuleDetailsUrl(createdRule.id), + }); } } } }, - [goToStep, setRule, updateCurrentDataState] + [updateCurrentDataState, goToStep, createRule, dispatchToaster, navigateToApp] ); const getAccordionType = useCallback( @@ -342,15 +347,6 @@ const CreateRulePageComponent: React.FC = () => { /> ); - if (ruleName && ruleId) { - displaySuccessToast(i18n.SUCCESSFULLY_CREATED_RULES(ruleName), dispatchToaster); - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.rules, - path: getRuleDetailsUrl(ruleId), - }); - return null; - } - if ( redirectToDetections( isSignalIndexExists, @@ -364,7 +360,7 @@ const CreateRulePageComponent: React.FC = () => { path: getDetectionEngineUrl(), }); return null; - } else if (!userHasPermissions(canUserCRUD)) { + } else if (!hasUserCRUDPermission(canUserCRUD)) { navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.rules, path: getRulesUrl(), diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/translations.ts diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx similarity index 86% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx index 23d96c93aea2a..78b58f95c91a0 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx @@ -21,22 +21,23 @@ import { useParams } from 'react-router-dom'; import { noop } from 'lodash'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; -import type { UpdateRulesSchema } from '../../../../../../common/detection_engine/schemas/request'; -import { useRule, useUpdateRule } from '../../../../containers/detection_engine/rules'; -import { useListsConfig } from '../../../../containers/detection_engine/lists/use_lists_config'; -import { SecuritySolutionPageWrapper } from '../../../../../common/components/page_wrapper'; +import type { RuleUpdateProps } from '../../../../../common/detection_engine/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'; +import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; import { getRuleDetailsUrl, getDetectionEngineUrl, -} from '../../../../../common/components/link_to/redirect_to_detection_engine'; -import { displaySuccessToast, useStateToaster } from '../../../../../common/components/toasters'; -import { SpyRoute } from '../../../../../common/utils/route/spy_routes'; -import { useUserData } from '../../../../components/user_info'; -import { StepPanel } from '../../../../components/rules/step_panel'; -import { StepAboutRule } from '../../../../components/rules/step_about_rule'; -import { StepDefineRule } from '../../../../components/rules/step_define_rule'; -import { StepScheduleRule } from '../../../../components/rules/step_schedule_rule'; -import { StepRuleActions } from '../../../../components/rules/step_rule_actions'; +} from '../../../../common/components/link_to/redirect_to_detection_engine'; +import { displaySuccessToast, useStateToaster } from '../../../../common/components/toasters'; +import { SpyRoute } from '../../../../common/utils/route/spy_routes'; +import { useUserData } from '../../../../detections/components/user_info'; +import { StepPanel } from '../../../../detections/components/rules/step_panel'; +import { StepAboutRule } from '../../../../detections/components/rules/step_about_rule'; +import { StepDefineRule } from '../../../../detections/components/rules/step_define_rule'; +import { StepScheduleRule } from '../../../../detections/components/rules/step_schedule_rule'; +import { StepRuleActions } from '../../../../detections/components/rules/step_rule_actions'; import { formatRule, stepIsValid, @@ -44,15 +45,14 @@ import { isAboutStep, isScheduleStep, isActionsStep, -} from '../create/helpers'; +} from '../rule_creation/helpers'; import { getStepsData, redirectToDetections, getActionMessageParams, - userHasPermissions, MaxWidthEuiFlexItem, -} from '../helpers'; -import * as ruleI18n from '../translations'; +} from '../../../../detections/pages/detection_engine/rules/helpers'; +import * as ruleI18n from '../../../../detections/pages/detection_engine/rules/translations'; import type { ActionsStepRule, AboutStepRule, @@ -61,22 +61,22 @@ import type { RuleStepsFormHooks, RuleStepsFormData, RuleStepsData, -} from '../types'; -import { RuleStep } from '../types'; +} from '../../../../detections/pages/detection_engine/rules/types'; +import { RuleStep } from '../../../../detections/pages/detection_engine/rules/types'; import * as i18n from './translations'; -import { SecurityPageName } from '../../../../../app/types'; -import { ruleStepsOrder } from '../utils'; -import { useKibana, useUiSetting$ } from '../../../../../common/lib/kibana'; +import { SecurityPageName } from '../../../../app/types'; +import { ruleStepsOrder } from '../../../../detections/pages/detection_engine/rules/utils'; +import { useKibana, useUiSetting$ } from '../../../../common/lib/kibana'; import { APP_UI_ID, DEFAULT_INDEX_KEY, DEFAULT_THREAT_INDEX_KEY, -} from '../../../../../../common/constants'; -import { HeaderPage } from '../../../../../common/components/header_page'; -import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; -import { SINGLE_RULE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; -import { PreviewFlyout } from '../preview'; -import { useGetSavedQuery } from '../use_get_saved_query'; +} from '../../../../../common/constants'; +import { HeaderPage } from '../../../../common/components/header_page'; +import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; +import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions'; +import { PreviewFlyout } from '../../../../detections/pages/detection_engine/rules/preview'; +import { useGetSavedQuery } from '../../../../detections/pages/detection_engine/rules/use_get_saved_query'; const formHookNoop = async (): Promise => undefined; @@ -96,8 +96,8 @@ const EditRulePageComponent: FC = () => { const { data: dataServices } = useKibana().services; const { navigateToApp } = useKibana().services.application; - const { detailName: ruleId } = useParams<{ detailName: string | undefined }>(); - const [ruleLoading, rule] = useRule(ruleId); + const { detailName: ruleId } = useParams<{ detailName: string }>(); + const { data: rule, isLoading: ruleLoading } = useRule(ruleId); const loading = ruleLoading || userInfoLoading || listsConfigLoading; const { isSavedQueryLoading, savedQueryBar, savedQuery } = useGetSavedQuery(rule?.saved_id, { @@ -126,7 +126,7 @@ const EditRulePageComponent: FC = () => { const stepData = stepsData.current[step]; return stepData.data != null && !stepIsValid(stepData); }); - const [{ isLoading, isSaved }, setRule] = useUpdateRule(); + const { mutateAsync: updateRule, isLoading } = useUpdateRule(); const [dataViewOptions, setDataViewOptions] = useState<{ [x: string]: DataViewListItem }>({}); const [isPreviewDisabled, setIsPreviewDisabled] = useState(false); const [isRulePreviewVisible, setIsRulePreviewVisible] = useState(false); @@ -358,8 +358,8 @@ const EditRulePageComponent: FC = () => { stepIsValid(actions) ) { startTransaction({ name: SINGLE_RULE_ACTIONS.SAVE }); - setRule({ - ...formatRule( + await updateRule({ + ...formatRule( define.data, about.data, schedule.data, @@ -369,17 +369,25 @@ const EditRulePageComponent: FC = () => { ...(ruleId ? { id: ruleId } : {}), ...(rule != null ? { max_signals: rule.max_signals } : {}), }); + + displaySuccessToast(i18n.SUCCESSFULLY_SAVED_RULE(rule?.name ?? ''), dispatchToaster); + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.rules, + path: getRuleDetailsUrl(ruleId ?? ''), + }); } }, [ aboutStep, actionsStep, activeStep, defineStep, + dispatchToaster, + navigateToApp, rule, ruleId, scheduleStep, - setRule, setStepData, + updateRule, startTransaction, ]); @@ -432,15 +440,6 @@ const EditRulePageComponent: FC = () => { } }, [rule]); - if (isSaved) { - displaySuccessToast(i18n.SUCCESSFULLY_SAVED_RULE(rule?.name ?? ''), dispatchToaster); - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.rules, - path: getRuleDetailsUrl(ruleId ?? ''), - }); - return null; - } - if ( redirectToDetections( isSignalIndexExists, @@ -454,7 +453,7 @@ const EditRulePageComponent: FC = () => { path: getDetectionEngineUrl(), }); return null; - } else if (!userHasPermissions(canUserCRUD)) { + } else if (!hasUserCRUDPermission(canUserCRUD)) { navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.rules, path: getRuleDetailsUrl(ruleId ?? ''), diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/translations.ts diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/__mocks__/rule_details_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/__mocks__/rule_details_context.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/__mocks__/rule_details_context.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/__mocks__/rule_details_context.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/__snapshots__/execution_log_search_bar.test.tsx.snap diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_columns.tsx similarity index 89% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_columns.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_columns.tsx index 9d5fd1a974dac..610277ddcd076 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_columns.tsx @@ -14,13 +14,13 @@ import { FormattedMessage } from '@kbn/i18n-react'; import type { RuleExecutionResult, RuleExecutionStatus, -} from '../../../../../../../common/detection_engine/rule_monitoring'; +} from '../../../../../../common/detection_engine/rule_monitoring'; -import { getEmptyValue } from '../../../../../../common/components/empty_value'; -import { FormattedDate } from '../../../../../../common/components/formatted_date'; -import { ExecutionStatusIndicator } from '../../../../../../detection_engine/rule_monitoring'; -import { PopoverTooltip } from '../../all/popover_tooltip'; -import { TableHeaderTooltipCell } from '../../all/table_header_tooltip_cell'; +import { getEmptyValue } from '../../../../../common/components/empty_value'; +import { FormattedDate } from '../../../../../common/components/formatted_date'; +import { ExecutionStatusIndicator } from '../../../../rule_monitoring'; +import { PopoverTooltip } from '../../../../rule_management_ui/components/rules_table/popover_tooltip'; +import { TableHeaderTooltipCell } from '../../../../rule_management_ui/components/rules_table/table_header_tooltip_cell'; import { RuleDurationFormat } from './rule_duration_format'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_search_bar.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_search_bar.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.test.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_search_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_search_bar.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.tsx index 39a4c3ee159de..98c61183ab861 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_search_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_search_bar.tsx @@ -9,8 +9,8 @@ import React, { useCallback } from 'react'; import { replace } from 'lodash'; import { EuiFieldSearch, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { RuleExecutionStatus } from '../../../../../../../common/detection_engine/rule_monitoring'; -import { ExecutionStatusFilter } from '../../../../../../detection_engine/rule_monitoring'; +import { RuleExecutionStatus } from '../../../../../../common/detection_engine/rule_monitoring'; +import { ExecutionStatusFilter } from '../../../../rule_monitoring'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_table.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx similarity index 76% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_table.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx index 52f85b228ab36..e8cc02990289e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_table.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx @@ -9,19 +9,17 @@ import React from 'react'; import { noop } from 'lodash/fp'; import { render, screen } from '@testing-library/react'; -import { TestProviders } from '../../../../../../common/mock'; +import { TestProviders } from '../../../../../common/mock'; import { useRuleDetailsContextMock } from '../__mocks__/rule_details_context'; -import { getRuleExecutionResultsResponseMock } from '../../../../../../../common/detection_engine/rule_monitoring/mocks'; +import { getRuleExecutionResultsResponseMock } from '../../../../../../common/detection_engine/rule_monitoring/mocks'; -import { useExecutionResults } from '../../../../../../detection_engine/rule_monitoring'; -import { useSourcererDataView } from '../../../../../../common/containers/sourcerer'; +import { useExecutionResults } from '../../../../rule_monitoring'; +import { useSourcererDataView } from '../../../../../common/containers/sourcerer'; import { useRuleDetailsContext } from '../rule_details_context'; import { ExecutionLogTable } from './execution_log_table'; -jest.mock('../../../../../../common/containers/sourcerer'); -jest.mock( - '../../../../../../detection_engine/rule_monitoring/components/execution_results_table/use_execution_results' -); +jest.mock('../../../../../common/containers/sourcerer'); +jest.mock('../../../../rule_monitoring/components/execution_results_table/use_execution_results'); jest.mock('../rule_details_context'); const mockUseSourcererDataView = useSourcererDataView as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx similarity index 92% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_table.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx index 11b8e15194d07..072d3b6f58174 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/execution_log_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx @@ -27,41 +27,38 @@ import { buildFilter, FILTERS } from '@kbn/es-query'; import { MAX_EXECUTION_EVENTS_DISPLAYED } from '@kbn/securitysolution-rules'; import { mountReactNode } from '@kbn/core-mount-utils-browser-internal'; -import { InputsModelId } from '../../../../../../common/store/inputs/constants'; +import { InputsModelId } from '../../../../../common/store/inputs/constants'; import { RuleDetailTabs } from '..'; -import { RULE_DETAILS_EXECUTION_LOG_TABLE_SHOW_METRIC_COLUMNS_STORAGE_KEY } from '../../../../../../../common/constants'; +import { RULE_DETAILS_EXECUTION_LOG_TABLE_SHOW_METRIC_COLUMNS_STORAGE_KEY } from '../../../../../../common/constants'; import type { RuleExecutionResult, RuleExecutionStatus, -} from '../../../../../../../common/detection_engine/rule_monitoring'; +} from '../../../../../../common/detection_engine/rule_monitoring'; -import { HeaderSection } from '../../../../../../common/components/header_section'; +import { HeaderSection } from '../../../../../common/components/header_section'; import { UtilityBar, UtilityBarGroup, UtilityBarSection, UtilityBarText, -} from '../../../../../../common/components/utility_bar'; -import { useSourcererDataView } from '../../../../../../common/containers/sourcerer'; -import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; -import { useDeepEqualSelector } from '../../../../../../common/hooks/use_selector'; -import { useKibana } from '../../../../../../common/lib/kibana'; -import { inputsSelectors } from '../../../../../../common/store'; +} from '../../../../../common/components/utility_bar'; +import { useSourcererDataView } from '../../../../../common/containers/sourcerer'; +import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; +import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; +import { useKibana } from '../../../../../common/lib/kibana'; +import { inputsSelectors } from '../../../../../common/store'; import { setAbsoluteRangeDatePicker, setFilterQuery, setRelativeRangeDatePicker, -} from '../../../../../../common/store/inputs/actions'; +} from '../../../../../common/store/inputs/actions'; import type { AbsoluteTimeRange, RelativeTimeRange, -} from '../../../../../../common/store/inputs/model'; -import { - isAbsoluteTimeRange, - isRelativeTimeRange, -} from '../../../../../../common/store/inputs/model'; -import { SourcererScopeName } from '../../../../../../common/store/sourcerer/model'; -import { useExecutionResults } from '../../../../../../detection_engine/rule_monitoring'; +} from '../../../../../common/store/inputs/model'; +import { isAbsoluteTimeRange, isRelativeTimeRange } from '../../../../../common/store/inputs/model'; +import { SourcererScopeName } from '../../../../../common/store/sourcerer/model'; +import { useExecutionResults } from '../../../../rule_monitoring'; import { useRuleDetailsContext } from '../rule_details_context'; import * as i18n from './translations'; import { EXECUTION_LOG_COLUMNS, GET_EXECUTION_LOG_METRICS_COLUMNS } from './execution_log_columns'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/rule_duration_format.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/rule_duration_format.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/rule_duration_format.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/rule_duration_format.test.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/rule_duration_format.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/rule_duration_format.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/rule_duration_format.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/rule_duration_format.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/execution_log_table/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/translations.ts diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.test.tsx similarity index 84% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.test.tsx index 8130abd7efe3d..2cd73c6293a17 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.test.tsx @@ -8,64 +8,57 @@ import React from 'react'; import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; +import { tGridReducer } from '@kbn/timelines-plugin/public'; -import '../../../../../common/mock/match_media'; +import '../../../../common/mock/match_media'; import { createSecuritySolutionStorageMock, kibanaObservable, mockGlobalState, TestProviders, SUB_PLUGINS_REDUCER, -} from '../../../../../common/mock'; +} from '../../../../common/mock'; import { RuleDetailsPage } from '.'; -import type { State } from '../../../../../common/store'; -import { createStore } from '../../../../../common/store'; -import { useUserData } from '../../../../components/user_info'; -import { useRuleWithFallback } from '../../../../containers/detection_engine/rules/use_rule_with_fallback'; +import type { State } from '../../../../common/store'; +import { createStore } from '../../../../common/store'; +import { useUserData } from '../../../../detections/components/user_info'; +import { useRuleWithFallback } from '../../../rule_management/logic/use_rule_with_fallback'; -import { useSourcererDataView } from '../../../../../common/containers/sourcerer'; +import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { useParams } from 'react-router-dom'; -import { mockHistory, Router } from '../../../../../common/mock/router'; +import { mockHistory, Router } from '../../../../common/mock/router'; -import { fillEmptySeverityMappings } from '../helpers'; -import { tGridReducer } from '@kbn/timelines-plugin/public'; +import { fillEmptySeverityMappings } from '../../../../detections/pages/detection_engine/rules/helpers'; // Test will fail because we will to need to mock some core services to make the test work // For now let's forget about SiemSearchBar and QueryBar -jest.mock('../../../../../common/components/search_bar', () => ({ +jest.mock('../../../../common/components/search_bar', () => ({ SiemSearchBar: () => null, })); -jest.mock('../helpers', () => { - const original = jest.requireActual('../helpers'); +jest.mock('../../../../detections/pages/detection_engine/rules/helpers', () => { + const original = jest.requireActual( + '../../../../detections/pages/detection_engine/rules/helpers' + ); return { ...original, fillEmptySeverityMappings: jest.fn().mockReturnValue([]), }; }); -jest.mock('../../../../../common/components/query_bar', () => ({ +jest.mock('../../../../common/components/query_bar', () => ({ QueryBar: () => null, })); -jest.mock('../../../../containers/detection_engine/lists/use_lists_config'); -jest.mock('../../../../../common/components/link_to'); -jest.mock('../../../../components/user_info'); -jest.mock('../../../../containers/detection_engine/rules', () => { - const original = jest.requireActual('../../../../containers/detection_engine/rules'); - return { - ...original, - useRuleStatus: jest.fn(), - }; -}); -jest.mock('../../../../containers/detection_engine/rules/use_rule_with_fallback', () => { - const original = jest.requireActual( - '../../../../containers/detection_engine/rules/use_rule_with_fallback' - ); +jest.mock('../../../../detections/containers/detection_engine/lists/use_lists_config'); +jest.mock('../../../../common/components/link_to'); +jest.mock('../../../../detections/components/user_info'); +jest.mock('../../../rule_management/logic/use_rule_with_fallback', () => { + const original = jest.requireActual('../../../rule_management/logic/use_rule_with_fallback'); return { ...original, useRuleWithFallback: jest.fn(), }; }); -jest.mock('../../../../../common/containers/sourcerer', () => { - const actual = jest.requireActual('../../../../../common/containers/sourcerer'); +jest.mock('../../../../common/containers/sourcerer', () => { + const actual = jest.requireActual('../../../../common/containers/sourcerer'); return { ...actual, useSourcererDataView: jest @@ -73,7 +66,7 @@ jest.mock('../../../../../common/containers/sourcerer', () => { .mockReturnValue({ indexPattern: ['fakeindex'], loading: false }), }; }); -jest.mock('../../../../../common/containers/use_global_time', () => ({ +jest.mock('../../../../common/containers/use_global_time', () => ({ useGlobalTime: jest.fn().mockReturnValue({ from: '2020-07-07T08:20:18.966Z', isInitializing: false, @@ -94,8 +87,8 @@ jest.mock('react-router-dom', () => { const mockRedirectLegacyUrl = jest.fn(); const mockGetLegacyUrlConflict = jest.fn(); -jest.mock('../../../../../common/lib/kibana', () => { - const originalModule = jest.requireActual('../../../../../common/lib/kibana'); +jest.mock('../../../../common/lib/kibana', () => { + const originalModule = jest.requireActual('../../../../common/lib/kibana'); return { ...originalModule, useKibana: () => ({ diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx similarity index 82% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index 97c302d7038c5..5e8c5137f47c5 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -27,111 +27,111 @@ import type { ConnectedProps } from 'react-redux'; import { connect, useDispatch } from 'react-redux'; import styled from 'styled-components'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; - import type { Dispatch } from 'redux'; import { isTab } from '@kbn/timelines-plugin/public'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; -import { tableDefaults } from '../../../../../common/store/data_table/defaults'; -import { dataTableActions, dataTableSelectors } from '../../../../../common/store/data_table'; -import { SecuritySolutionTabNavigation } from '../../../../../common/components/navigation'; -import { InputsModelId } from '../../../../../common/store/inputs/constants'; + +import { isMlRule } from '../../../../../common/machine_learning/helpers'; +import { SecuritySolutionTabNavigation } from '../../../../common/components/navigation'; +import { InputsModelId } from '../../../../common/store/inputs/constants'; import { useDeepEqualSelector, useShallowEqualSelector, -} from '../../../../../common/hooks/use_selector'; -import { useKibana, useUiSetting$ } from '../../../../../common/lib/kibana'; -import { TableId } from '../../../../../../common/types/timeline'; -import type { UpdateDateRange } from '../../../../../common/components/charts/common'; -import { FiltersGlobal } from '../../../../../common/components/filters_global'; -import { FormattedDate } from '../../../../../common/components/formatted_date'; +} from '../../../../common/hooks/use_selector'; +import { useKibana, useUiSetting$ } from '../../../../common/lib/kibana'; +import { TableId } from '../../../../../common/types/timeline'; +import type { UpdateDateRange } from '../../../../common/components/charts/common'; +import { FiltersGlobal } from '../../../../common/components/filters_global'; +import { FormattedDate } from '../../../../common/components/formatted_date'; +import { tableDefaults } from '../../../../common/store/data_table/defaults'; +import { dataTableActions, dataTableSelectors } from '../../../../common/store/data_table'; import { - getEditRuleUrl, getRulesUrl, getDetectionEngineUrl, getRuleDetailsTabUrl, -} 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 '../../../../containers/detection_engine/rules'; -import { useListsConfig } from '../../../../containers/detection_engine/lists/use_lists_config'; -import { SpyRoute } from '../../../../../common/utils/route/spy_routes'; -import { StepAboutRuleToggleDetails } from '../../../../components/rules/step_about_rule_details'; -import { AlertsHistogramPanel } from '../../../../components/alerts_kpis/alerts_histogram_panel'; -import { AlertsTable } from '../../../../components/alerts_table'; -import { useUserData } from '../../../../components/user_info'; -import { StepDefineRule } from '../../../../components/rules/step_define_rule'; -import { StepScheduleRule } from '../../../../components/rules/step_schedule_rule'; +} 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'; +import { AlertsHistogramPanel } from '../../../../detections/components/alerts_kpis/alerts_histogram_panel'; +import { AlertsTable } from '../../../../detections/components/alerts_table'; +import { useUserData } from '../../../../detections/components/user_info'; +import { StepDefineRule } from '../../../../detections/components/rules/step_define_rule'; +import { StepScheduleRule } from '../../../../detections/components/rules/step_schedule_rule'; import { buildAlertsFilter, buildAlertStatusFilter, buildShowBuildingBlockFilter, buildThreatMatchFilter, -} from '../../../../components/alerts_table/default_config'; -import { RuleSwitch } from '../../../../components/rules/rule_switch'; -import { StepPanel } from '../../../../components/rules/step_panel'; -import { getStepsData, redirectToDetections, userHasPermissions } from '../helpers'; -import { useGlobalTime } from '../../../../../common/containers/use_global_time'; -import { inputsSelectors } from '../../../../../common/store/inputs'; -import { setAbsoluteRangeDatePicker } from '../../../../../common/store/inputs/actions'; -import { RuleActionsOverflow } from '../../../../components/rules/rule_actions_overflow'; -import { useMlCapabilities } from '../../../../../common/components/ml/hooks/use_ml_capabilities'; -import { hasMlAdminPermissions } from '../../../../../../common/machine_learning/has_ml_admin_permissions'; -import { hasMlLicense } from '../../../../../../common/machine_learning/has_ml_license'; -import { SecurityPageName } from '../../../../../app/types'; -import { LinkButton } from '../../../../../common/components/links'; -import { useFormatUrl } from '../../../../../common/components/link_to'; +} from '../../../../detections/components/alerts_table/default_config'; +import { RuleSwitch } from '../../../../detections/components/rules/rule_switch'; +import { StepPanel } from '../../../../detections/components/rules/step_panel'; +import { + getStepsData, + redirectToDetections, +} from '../../../../detections/pages/detection_engine/rules/helpers'; +import { useGlobalTime } from '../../../../common/containers/use_global_time'; +import { inputsSelectors } from '../../../../common/store/inputs'; +import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions'; +import { RuleActionsOverflow } from '../../../../detections/components/rules/rule_actions_overflow'; +import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; +import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; +import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; +import { SecurityPageName } from '../../../../app/types'; import { APP_UI_ID, DEFAULT_INDEX_KEY, DEFAULT_THREAT_INDEX_KEY, -} from '../../../../../../common/constants'; -import { useGlobalFullScreen } from '../../../../../common/containers/use_full_screen'; -import { Display } from '../../../../../hosts/pages/display'; +} from '../../../../../common/constants'; +import { useGlobalFullScreen } from '../../../../common/containers/use_full_screen'; +import { Display } from '../../../../hosts/pages/display'; import { focusUtilityBarAction, onTimelineTabKeyPressed, resetKeyboardFocus, showGlobalFilters, -} from '../../../../../timelines/components/timeline/helpers'; -import { useSourcererDataView } from '../../../../../common/containers/sourcerer'; -import { SourcererScopeName } from '../../../../../common/store/sourcerer/model'; +} from '../../../../timelines/components/timeline/helpers'; +import { useSourcererDataView } from '../../../../common/containers/sourcerer'; +import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { - getToolTipContent, + explainLackOfPermission, canEditRuleWithActions, isBoolean, -} from '../../../../../common/utils/privileges'; + hasUserCRUDPermission, +} from '../../../../common/utils/privileges'; import { RuleStatus, RuleStatusFailedCallOut, ruleStatusI18n, -} from '../../../../components/rules/rule_execution_status'; -import { - ExecutionEventsTable, - useRuleExecutionSettings, -} from '../../../../../detection_engine/rule_monitoring'; +} from '../../../../detections/components/rules/rule_execution_status'; +import { ExecutionEventsTable, useRuleExecutionSettings } from '../../../rule_monitoring'; import { ExecutionLogTable } from './execution_log_table/execution_log_table'; -import * as detectionI18n from '../../translations'; -import * as ruleI18n from '../translations'; +import * as detectionI18n from '../../../../detections/pages/detection_engine/translations'; +import * as ruleI18n from '../../../../detections/pages/detection_engine/rules/translations'; import { RuleDetailsContextProvider } from './rule_details_context'; -import { useGetSavedQuery } from '../use_get_saved_query'; +import { useGetSavedQuery } from '../../../../detections/pages/detection_engine/rules/use_get_saved_query'; import * as i18n from './translations'; -import { NeedAdminForUpdateRulesCallOut } from '../../../../components/callouts/need_admin_for_update_callout'; -import { MissingPrivilegesCallOut } from '../../../../components/callouts/missing_privileges_callout'; -import { useRuleWithFallback } from '../../../../containers/detection_engine/rules/use_rule_with_fallback'; -import type { BadgeOptions } from '../../../../../common/components/header_page/types'; -import type { AlertsStackByField } from '../../../../components/alerts_kpis/common/types'; -import type { Status } from '../../../../../../common/detection_engine/schemas/common/schemas'; +import { NeedAdminForUpdateRulesCallOut } from '../../../../detections/components/callouts/need_admin_for_update_callout'; +import { MissingPrivilegesCallOut } from '../../../../detections/components/callouts/missing_privileges_callout'; +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/detection_engine/schemas/common/schemas'; import { AlertsTableFilterGroup, FILTER_OPEN, -} from '../../../../components/alerts_table/alerts_filter_group'; -import { useSignalHelpers } from '../../../../../common/containers/sourcerer/use_signal_helpers'; -import { HeaderPage } from '../../../../../common/components/header_page'; -import { ExceptionsViewer } from '../../../../../detection_engine/rule_exceptions/components/all_exception_items_table'; -import type { NavTab } from '../../../../../common/components/navigation/types'; +} from '../../../../detections/components/alerts_table/alerts_filter_group'; +import { useSignalHelpers } from '../../../../common/containers/sourcerer/use_signal_helpers'; +import { HeaderPage } from '../../../../common/components/header_page'; +import { ExceptionsViewer } from '../../../rule_exceptions/components/all_exception_items_table'; +import type { NavTab } from '../../../../common/components/navigation/types'; +import { EditRuleSettingButtonLink } from '../../../../detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. @@ -299,7 +299,6 @@ const RuleDetailsPageComponent: React.FC = ({ const [showBuildingBlockAlerts, setShowBuildingBlockAlerts] = useState(false); const [showOnlyThreatIndicatorAlerts, setShowOnlyThreatIndicatorAlerts] = useState(false); const mlCapabilities = useMlCapabilities(); - const { formatUrl } = useFormatUrl(SecurityPageName.rules); const { globalFullScreen } = useGlobalFullScreen(); const [filterGroup, setFilterGroup] = useState(FILTER_OPEN); const [dataViewOptions, setDataViewOptions] = useState<{ [x: string]: DataViewListItem }>({}); @@ -584,45 +583,6 @@ const RuleDetailsPageComponent: React.FC = ({ setRule((currentRule) => (currentRule ? { ...currentRule, enabled } : currentRule)); }, []); - const goToEditRule = useCallback( - (ev) => { - ev.preventDefault(); - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.rules, - path: getEditRuleUrl(ruleId ?? ''), - }); - }, - [navigateToApp, ruleId] - ); - - const editRule = useMemo(() => { - if (!hasActionsPrivileges) { - return ( - - - {ruleI18n.EDIT_RULE_SETTINGS} - - - ); - } - return ( - - {ruleI18n.EDIT_RULE_SETTINGS} - - ); - }, [isExistingRule, canUserCRUD, formatUrl, goToEditRule, hasActionsPrivileges, ruleId]); - const onShowBuildingBlockAlertsChangedCallback = useCallback( (newShowBuildingBlockAlerts: boolean) => { setShowBuildingBlockAlerts(newShowBuildingBlockAlerts); @@ -719,7 +679,12 @@ const RuleDetailsPageComponent: React.FC = ({ = ({ isDisabled={ !isExistingRule || !canEditRuleWithActions(rule, hasActionsPrivileges) || - !userHasPermissions(canUserCRUD) || + !hasUserCRUDPermission(canUserCRUD) || (!hasMlPermissions && !rule?.enabled) } enabled={isExistingRule && (rule?.enabled ?? false)} @@ -740,11 +705,26 @@ const RuleDetailsPageComponent: React.FC = ({ - {editRule} + + + = ({ = ({ > ({ ...jest.requireActual('@kbn/securitysolution-hook-utils'), useAsync: jest.fn(), })); -jest.mock('../../../../detections/containers/detection_engine/rules/use_rule_async'); +jest.mock('../../../rule_management/logic/use_rule'); jest.mock('@kbn/lists-plugin/public'); +jest.mock('../../../rule_management/logic/use_find_rules'); const mockGetExceptionBuilderComponentLazy = getExceptionBuilderComponentLazy as jest.Mock< ReturnType >; -const mockUseAsync = useAsync as jest.Mock>; -const mockUseAddOrUpdateException = useAddOrUpdateException as jest.Mock< - ReturnType +const mockUseAddOrUpdateException = useCreateOrUpdateException as jest.Mock< + ReturnType >; -const mockUseFetchOrCreateRuleExceptionList = useFetchOrCreateRuleExceptionList as jest.Mock< - ReturnType +const mockFetchIndexPatterns = useFetchIndexPatterns as jest.Mock< + ReturnType >; const mockUseSignalIndex = useSignalIndex as jest.Mock>>; const mockUseFetchIndex = useFetchIndex as jest.Mock; -const mockUseRuleAsync = useRuleAsync as jest.Mock; +const mockUseFindRules = useFindRules as jest.Mock; +const mockUseFindExceptionListReferences = useFindExceptionListReferences as jest.Mock; + +const alertDataMock: AlertData = { + '@timestamp': '1234567890', + _id: 'test-id', + file: { path: 'test/path' }, +}; describe('When the add exception modal is opened', () => { - const ruleName = 'test rule'; let defaultEndpointItems: jest.SpyInstance< ReturnType >; beforeEach(() => { mockGetExceptionBuilderComponentLazy.mockReturnValue( - + ); defaultEndpointItems = jest.spyOn(helpers, 'defaultEndpointExceptionItems'); - mockUseAsync.mockImplementation(() => ({ - start: jest.fn(), - loading: false, - error: {}, - result: true, + mockUseAddOrUpdateException.mockImplementation(() => [false, jest.fn()]); + mockFetchIndexPatterns.mockImplementation(() => ({ + isLoading: false, + indexPatterns: stubIndexPattern, })); - mockUseAddOrUpdateException.mockImplementation(() => [{ isLoading: false }, jest.fn()]); - mockUseFetchOrCreateRuleExceptionList.mockImplementation(() => [ - false, - getExceptionListSchemaMock(), - ]); mockUseSignalIndex.mockImplementation(() => ({ loading: false, signalIndexName: 'mock-siem-signals-index', @@ -92,9 +96,48 @@ describe('When the add exception modal is opened', () => { indexPatterns: stubIndexPattern, }, ]); - mockUseRuleAsync.mockImplementation(() => ({ - rule: getRulesSchemaMock(), + mockUseFindRules.mockImplementation(() => ({ + data: { + rules: [ + { + ...getRulesSchemaMock(), + exceptions_list: [], + } as Rule, + ], + total: 1, + }, + isFetched: true, })); + mockUseFindExceptionListReferences.mockImplementation(() => [ + false, + false, + { + my_list_id: { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my_list_id', + namespace_type: 'single', + type: ExceptionListTypeEnum.DETECTION, + name: 'My exception list', + referenced_rules: [ + { + id: '345', + name: 'My rule', + rule_id: 'my_rule_id', + exception_lists: [ + { + id: '123', + list_id: 'my_list_id', + namespace_type: 'single', + type: ExceptionListTypeEnum.DETECTION, + }, + ], + }, + ], + }, + }, + jest.fn(), + ]); }); afterEach(() => { @@ -106,87 +149,705 @@ describe('When the add exception modal is opened', () => { let wrapper: ReactWrapper; beforeEach(() => { // Mocks one of the hooks as loading - mockUseFetchIndex.mockImplementation(() => [ - true, - { - indexPatterns: stubIndexPattern, - }, - ]); + mockFetchIndexPatterns.mockImplementation(() => ({ + isLoading: true, + indexPatterns: { fields: [], title: 'foo' }, + })); + wrapper = mount( ); }); + it('should show the loading spinner', () => { expect(wrapper.find('[data-test-subj="loadingAddExceptionFlyout"]').exists()).toBeTruthy(); }); }); - describe('when there is no alert data passed to an endpoint list exception', () => { + describe('exception list type of "endpoint"', () => { + describe('common functionality to test regardless of alert input', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) + ); + }); + + it('displays proper flyout and button text', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutTitle"]').at(1).text()).toEqual( + i18n.ADD_ENDPOINT_EXCEPTION + ); + expect(wrapper.find('[data-test-subj="addExceptionConfirmButton"]').at(1).text()).toEqual( + i18n.ADD_ENDPOINT_EXCEPTION + ); + }); + + it('should render item name input', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutNameInput"]').exists()).toBeTruthy(); + }); + + it('should render the exception builder', () => { + expect(wrapper.find('[data-test-subj="alertExceptionBuilder"]').exists()).toBeTruthy(); + }); + + it('does NOT render options to add exception to a rule or shared list', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemAddToRuleOrListSection"]').exists() + ).toBeFalsy(); + }); + + it('should contain the endpoint specific documentation text', () => { + expect(wrapper.find('[data-test-subj="addExceptionEndpointText"]').exists()).toBeTruthy(); + }); + + it('should NOT display the eql sequence callout', () => { + expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).not.toBeTruthy(); + }); + }); + + describe('alert data is passed in', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) + ); + }); + + it('should prepopulate endpoint items', () => { + expect(defaultEndpointItems).toHaveBeenCalled(); + }); + + it('should render the close single alert checkbox', () => { + expect( + wrapper.find('[data-test-subj="closeAlertOnAddExceptionCheckbox"]').exists() + ).toBeTruthy(); + }); + + it('should have the bulk close alerts checkbox disabled', () => { + expect( + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() + ).toBeDisabled(); + }); + + it('should NOT render the os selection dropdown', () => { + expect(wrapper.find('[data-test-subj="osSelectionDropdown"]').exists()).toBeFalsy(); + }); + }); + + describe('bulk closeable alert data is passed in', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + mockUseFetchIndex.mockImplementation(() => [ + false, + { + indexPatterns: createStubIndexPattern({ + spec: { + id: '1234', + title: 'filebeat-*', + fields: { + 'event.code': { + name: 'event.code', + type: 'string', + aggregatable: true, + searchable: true, + }, + 'file.path.caseless': { + name: 'file.path.caseless', + type: 'string', + aggregatable: true, + searchable: true, + }, + subject_name: { + name: 'subject_name', + type: 'string', + aggregatable: true, + searchable: true, + }, + trusted: { + name: 'trusted', + type: 'string', + aggregatable: true, + searchable: true, + }, + 'file.hash.sha256': { + name: 'file.hash.sha256', + type: 'string', + aggregatable: true, + searchable: true, + }, + }, + }, + }), + }, + ]); + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ + exceptionItems: [ + { + ...getExceptionListItemSchemaMock(), + entries: [{ field: 'file.hash.sha256', operator: 'included', type: 'match' }], + }, + ], + }) + ); + }); + + it('should prepopulate endpoint items', () => { + expect(defaultEndpointItems).toHaveBeenCalled(); + }); + + it('should render the close single alert checkbox', () => { + expect( + wrapper.find('[data-test-subj="closeAlertOnAddExceptionCheckbox"]').exists() + ).toBeTruthy(); + }); + + it('should have the bulk close checkbox enabled', () => { + expect( + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() + ).not.toBeDisabled(); + }); + + describe('when a "is in list" entry is added', () => { + it('should have the bulk close checkbox disabled', async () => { + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + + await waitFor(() => + callProps.onChange({ + exceptionItems: [ + ...callProps.exceptionListItems, + { + ...getExceptionListItemSchemaMock(), + entries: [ + { field: 'event.code', operator: 'included', type: 'list' }, + ] as EntriesArray, + }, + ], + }) + ); + + expect( + wrapper + .find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]') + .getDOMNode() + ).toBeDisabled(); + }); + }); + }); + + describe('alert data NOT passed in', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) + ); + }); + + it('should NOT render the close single alert checkbox', () => { + expect( + wrapper.find('[data-test-subj="closeAlertOnAddExceptionCheckbox"]').exists() + ).toBeFalsy(); + }); + + it('should render the os selection dropdown', () => { + expect(wrapper.find('[data-test-subj="osSelectionDropdown"]').exists()).toBeTruthy(); + }); + }); + }); + + describe('exception list type is NOT "endpoint" ("rule_default" or "detection")', () => { + describe('common features to test regardless of alert input', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [getExceptionListItemSchemaMock()] }) + ); + }); + + it('displays proper flyout and button text', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutTitle"]').at(1).text()).toEqual( + i18n.CREATE_RULE_EXCEPTION + ); + expect(wrapper.find('[data-test-subj="addExceptionConfirmButton"]').at(1).text()).toEqual( + i18n.CREATE_RULE_EXCEPTION + ); + }); + + it('should NOT prepopulate items', () => { + expect(defaultEndpointItems).not.toHaveBeenCalled(); + }); + + // button is disabled until there are exceptions, a name, and selection made on + // add to rule or lists section + it('has the add exception button disabled', () => { + expect( + wrapper.find('button[data-test-subj="addExceptionConfirmButton"]').getDOMNode() + ).toBeDisabled(); + }); + + it('should render item name input', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutNameInput"]').exists()).toBeTruthy(); + }); + + it('should NOT render the os selection dropdown', () => { + expect(wrapper.find('[data-test-subj="osSelectionDropdown"]').exists()).toBeFalsy(); + }); + + it('should render the exception builder', () => { + expect(wrapper.find('[data-test-subj="alertExceptionBuilder"]').exists()).toBeTruthy(); + }); + + it('renders options to add exception to a rule or shared list and has "add to rule" selected by default', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemAddToRuleOrListSection"]').exists() + ).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="addToRuleOptionsRadio"] input').getDOMNode() + ).toBeChecked(); + }); + + it('should NOT contain the endpoint specific documentation text', () => { + expect(wrapper.find('[data-test-subj="addExceptionEndpointText"]').exists()).toBeFalsy(); + }); + + it('should NOT display the eql sequence callout', () => { + expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).not.toBeTruthy(); + }); + }); + + describe('alert data is passed in', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [getExceptionListItemSchemaMock()] }) + ); + }); + + it('should render the close single alert checkbox', () => { + expect( + wrapper.find('[data-test-subj="closeAlertOnAddExceptionCheckbox"]').exists() + ).toBeTruthy(); + expect( + wrapper.find('input[data-test-subj="closeAlertOnAddExceptionCheckbox"]').getDOMNode() + ).not.toBeDisabled(); + }); + + it('should have the bulk close checkbox disabled', () => { + expect( + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() + ).toBeDisabled(); + }); + }); + + describe('bulk closeable alert data is passed in', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + mockUseFetchIndex.mockImplementation(() => [ + false, + { + indexPatterns: createStubIndexPattern({ + spec: { + id: '1234', + title: 'filebeat-*', + fields: { + 'event.code': { + name: 'event.code', + type: 'string', + aggregatable: true, + searchable: true, + }, + 'file.path.caseless': { + name: 'file.path.caseless', + type: 'string', + aggregatable: true, + searchable: true, + }, + subject_name: { + name: 'subject_name', + type: 'string', + aggregatable: true, + searchable: true, + }, + trusted: { + name: 'trusted', + type: 'string', + aggregatable: true, + searchable: true, + }, + 'file.hash.sha256': { + name: 'file.hash.sha256', + type: 'string', + aggregatable: true, + searchable: true, + }, + }, + }, + }), + }, + ]); + wrapper = mount( + + + + ); + + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ + exceptionItems: [ + { + ...getExceptionListItemSchemaMock(), + entries: [{ field: 'file.hash.sha256', operator: 'included', type: 'match' }], + }, + ], + }) + ); + }); + + it('should render the close single alert checkbox', () => { + expect( + wrapper.find('[data-test-subj="closeAlertOnAddExceptionCheckbox"]').exists() + ).toBeTruthy(); + expect( + wrapper.find('input[data-test-subj="closeAlertOnAddExceptionCheckbox"]').getDOMNode() + ).not.toBeDisabled(); + }); + + it('should have the bulk close checkbox enabled', () => { + expect( + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() + ).not.toBeDisabled(); + }); + + describe('when a "is in list" entry is added', () => { + it('should have the bulk close checkbox disabled', async () => { + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + + await waitFor(() => + callProps.onChange({ + exceptionItems: [ + ...callProps.exceptionListItems, + { + ...getExceptionListItemSchemaMock(), + entries: [ + { field: 'event.code', operator: 'included', type: 'list' }, + ] as EntriesArray, + }, + ], + }) + ); + + expect( + wrapper + .find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]') + .getDOMNode() + ).toBeDisabled(); + }); + }); + }); + + describe('alert data NOT passed in', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) + ); + }); + + it('should NOT render the close single alert checkbox', () => { + expect( + wrapper.find('[data-test-subj="closeAlertOnAddExceptionCheckbox"]').exists() + ).toBeFalsy(); + }); + + it('should have the bulk close checkbox disabled', () => { + expect( + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() + ).toBeDisabled(); + }); + }); + }); + + /* Say for example, from the lists management or lists details page */ + describe('when no rules are passed in', () => { let wrapper: ReactWrapper; beforeEach(async () => { wrapper = mount( ); const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; - await waitFor(() => callProps.onChange({ exceptionItems: [] })); - }); - it('has the add exception button disabled', () => { - expect( - wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode() - ).toBeDisabled(); + await waitFor(() => + callProps.onChange({ exceptionItems: [getExceptionListItemSchemaMock()] }) + ); }); - it('should render the exception builder', () => { - expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy(); + + it('allows large value lists', () => { + expect(wrapper.find('ExceptionsConditions').prop('allowLargeValueLists')).toBeTruthy(); }); - it('should not render the close on add exception checkbox', () => { + + it('defaults to selecting add to rule option, displaying rules selection table', () => { + expect(wrapper.find('[data-test-subj="addExceptionToRulesTable"]').exists()).toBeTruthy(); expect( - wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists() - ).toBeFalsy(); - }); - it('should contain the endpoint specific documentation text', () => { - expect(wrapper.find('[data-test-subj="add-exception-endpoint-text"]').exists()).toBeTruthy(); - }); - it('should render the os selection dropdown', () => { - expect(wrapper.find('[data-test-subj="os-selection-dropdown"]').exists()).toBeTruthy(); + wrapper.find('[data-test-subj="selectRulesToAddToOptionRadio"] input').getDOMNode() + ).toHaveAttribute('checked'); }); }); - describe('when there is alert data passed to an endpoint list exception', () => { + /* Say for example, from the rule details page, exceptions tab, or from an alert */ + describe('when a single rule is passed in', () => { let wrapper: ReactWrapper; beforeEach(async () => { - const alertDataMock: AlertData = { - '@timestamp': '1234567890', - _id: 'test-id', - file: { path: 'test/path' }, - }; wrapper = mount( ); @@ -195,119 +856,304 @@ describe('When the add exception modal is opened', () => { callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) ); }); - it('has the add exception button enabled', () => { - expect( - wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); + it('does not allow large value list selection for query rule', () => { + const shallowWrapper = shallow( + + ); + + expect(shallowWrapper.find('ExceptionsConditions').prop('allowLargeValueLists')).toBeTruthy(); }); - it('should render the exception builder', () => { - expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy(); + + it('does not allow large value list selection if EQL rule', () => { + const shallowWrapper = shallow( + + ); + + expect(shallowWrapper.find('ExceptionsConditions').prop('allowLargeValueLists')).toBeFalsy(); }); - it('should prepopulate endpoint items', () => { - expect(defaultEndpointItems).toHaveBeenCalled(); + + it('does not allow large value list selection if threshold rule', () => { + const shallowWrapper = shallow( + + ); + + expect(shallowWrapper.find('ExceptionsConditions').prop('allowLargeValueLists')).toBeFalsy(); }); - it('should render the close on add exception checkbox', () => { + + it('does not allow large value list selection if new trems rule', () => { + const shallowWrapper = shallow( + + ); + + expect(shallowWrapper.find('ExceptionsConditions').prop('allowLargeValueLists')).toBeFalsy(); + }); + + it('defaults to selecting add to rule radio option', () => { expect( - wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists() + wrapper.find('[data-test-subj="exceptionItemAddToRuleOrListSection"]').exists() ).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="addToRuleOptionsRadio"] input').getDOMNode() + ).toBeChecked(); }); - it('should have the bulk close checkbox disabled', () => { + + it('disables add to shared lists option if rule has no shared exception lists attached already', () => { expect( - wrapper - .find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]') - .getDOMNode() + wrapper.find('[data-test-subj="addToListsRadioOption"] input').getDOMNode() ).toBeDisabled(); }); - it('should contain the endpoint specific documentation text', () => { - expect(wrapper.find('[data-test-subj="add-exception-endpoint-text"]').exists()).toBeTruthy(); - }); - it('should not display the eql sequence callout', () => { - expect(wrapper.find('[data-test-subj="eql-sequence-callout"]').exists()).not.toBeTruthy(); - }); - it('should not render the os selection dropdown', () => { - expect(wrapper.find('[data-test-subj="os-selection-dropdown"]').exists()).toBeFalsy(); + + it('enables add to shared lists option if rule has shared list', () => { + wrapper = mount( + + + + ); + + expect( + wrapper.find('[data-test-subj="addToListsRadioOption"] input').getDOMNode() + ).toBeEnabled(); }); }); - describe('when there is alert data passed to a detection list exception', () => { + /* Say for example, add exception item from rules bulk action */ + describe('when multiple rules are passed in - bulk action', () => { let wrapper: ReactWrapper; beforeEach(async () => { - const alertDataMock: AlertData = { - '@timestamp': '1234567890', - _id: 'test-id', - file: { path: 'test/path' }, - }; wrapper = mount( ); const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; await waitFor(() => - callProps.onChange({ exceptionItems: [getExceptionListItemSchemaMock()] }) + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) ); }); - it('has the add exception button enabled', () => { - expect( - wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); - }); - it('should render the exception builder', () => { - expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy(); - }); - it('should not prepopulate endpoint items', () => { - expect(defaultEndpointItems).not.toHaveBeenCalled(); + + it('allows large value lists', () => { + const shallowWrapper = shallow( + + ); + + expect(shallowWrapper.find('ExceptionsConditions').prop('allowLargeValueLists')).toBeTruthy(); }); - it('should render the close on add exception checkbox', () => { + + it('defaults to selecting add to rules radio option', () => { expect( - wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists() + wrapper.find('[data-test-subj="exceptionItemAddToRuleOrListSection"]').exists() ).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="addToRulesOptionsRadio"] input').getDOMNode() + ).toBeChecked(); }); - it('should have the bulk close checkbox disabled', () => { + + it('disables add to shared lists option if rules have no shared lists in common', () => { expect( - wrapper - .find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]') - .getDOMNode() + wrapper.find('[data-test-subj="addToListsRadioOption"] input').getDOMNode() ).toBeDisabled(); }); - it('should not display the eql sequence callout', () => { - expect(wrapper.find('[data-test-subj="eql-sequence-callout"]').exists()).not.toBeTruthy(); + + it('enables add to shared lists option if rules have at least one shared list in common', () => { + wrapper = mount( + + + + ); + + expect( + wrapper.find('[data-test-subj="addToListsRadioOption"] input').getDOMNode() + ).toBeEnabled(); }); }); describe('when there is an exception being created on a sequence eql rule type', () => { let wrapper: ReactWrapper; beforeEach(async () => { - mockUseRuleAsync.mockImplementation(() => ({ - rule: { - ...getRulesEqlSchemaMock(), - query: - 'sequence [process where process.name = "test.exe"] [process where process.name = "explorer.exe"]', - }, - })); - const alertDataMock: AlertData = { - '@timestamp': '1234567890', - _id: 'test-id', - file: { path: 'test/path' }, - }; wrapper = mount( ); @@ -316,177 +1162,58 @@ describe('When the add exception modal is opened', () => { callProps.onChange({ exceptionItems: [getExceptionListItemSchemaMock()] }) ); }); - it('has the add exception button enabled', () => { - expect( - wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); - }); + it('should render the exception builder', () => { - expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="alertExceptionBuilder"]').exists()).toBeTruthy(); }); + it('should not prepopulate endpoint items', () => { expect(defaultEndpointItems).not.toHaveBeenCalled(); }); - it('should render the close on add exception checkbox', () => { + + it('should render the close single alert checkbox', () => { expect( - wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists() + wrapper.find('[data-test-subj="closeAlertOnAddExceptionCheckbox"]').exists() ).toBeTruthy(); }); + it('should have the bulk close checkbox disabled', () => { expect( - wrapper - .find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]') - .getDOMNode() + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() ).toBeDisabled(); }); + it('should display the eql sequence callout', () => { - expect(wrapper.find('[data-test-subj="eql-sequence-callout"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).toBeTruthy(); }); }); - describe('when there is bulk-closeable alert data passed to an endpoint list exception', () => { - let wrapper: ReactWrapper; - - beforeEach(async () => { - mockUseFetchIndex.mockImplementation(() => [ - false, - { - indexPatterns: createStubIndexPattern({ - spec: { - id: '1234', - title: 'filebeat-*', - fields: { - 'event.code': { - name: 'event.code', - type: 'string', - aggregatable: true, - searchable: true, - }, - 'file.path.caseless': { - name: 'file.path.caseless', - type: 'string', - aggregatable: true, - searchable: true, - }, - subject_name: { - name: 'subject_name', - type: 'string', - aggregatable: true, - searchable: true, - }, - trusted: { - name: 'trusted', - type: 'string', - aggregatable: true, - searchable: true, - }, - 'file.hash.sha256': { - name: 'file.hash.sha256', - type: 'string', - aggregatable: true, - searchable: true, - }, - }, - }, - }), - }, - ]); - - const alertDataMock: AlertData = { - '@timestamp': '1234567890', - _id: 'test-id', - file: { path: 'test/path' }, - }; - wrapper = mount( + describe('error states', () => { + test('when there are exception builder errors submit button is disabled', async () => { + const wrapper = mount( ); - const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; - await waitFor(() => { - return callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }); - }); - }); - it('has the add exception button enabled', async () => { + await waitFor(() => callProps.onChange({ exceptionItems: [], errorExists: true })); expect( - wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); - }); - it('should render the exception builder', () => { - expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy(); - }); - it('should prepopulate endpoint items', () => { - expect(defaultEndpointItems).toHaveBeenCalled(); - }); - it('should render the close on add exception checkbox', () => { - expect( - wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists() - ).toBeTruthy(); - }); - it('should contain the endpoint specific documentation text', () => { - expect(wrapper.find('[data-test-subj="add-exception-endpoint-text"]').exists()).toBeTruthy(); - }); - it('should have the bulk close checkbox enabled', () => { - expect( - wrapper - .find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]') - .getDOMNode() - ).not.toBeDisabled(); - }); - describe('when a "is in list" entry is added', () => { - it('should have the bulk close checkbox disabled', async () => { - const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; - - await waitFor(() => - callProps.onChange({ - exceptionItems: [ - ...callProps.exceptionListItems, - { - ...getExceptionListItemSchemaMock(), - entries: [ - { field: 'event.code', operator: 'included', type: 'list' }, - ] as EntriesArray, - }, - ], - }) - ); - - expect( - wrapper - .find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]') - .getDOMNode() - ).toBeDisabled(); - }); + wrapper.find('button[data-test-subj="addExceptionConfirmButton"]').getDOMNode() + ).toBeDisabled(); }); }); - - test('when there are exception builder errors submit button is disabled', async () => { - const wrapper = mount( - - - - ); - const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; - await waitFor(() => callProps.onChange({ exceptionItems: [], errorExists: true })); - expect( - wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode() - ).toBeDisabled(); - }); }); 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 c7b7050f23ffe..413973faff766 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 @@ -5,13 +5,10 @@ * 2.0. */ -// Component being re-implemented in 8.5 - -/* eslint complexity: ["error", 35]*/ - -import React, { memo, useEffect, useState, useCallback, useMemo } from 'react'; +import React, { memo, useEffect, useCallback, useMemo, useReducer } from 'react'; import styled, { css } from 'styled-components'; -import type { EuiComboBoxOptionOption } from '@elastic/eui'; +import { isEmpty } from 'lodash/fp'; + import { EuiFlyout, EuiFlyoutHeader, @@ -21,62 +18,53 @@ import { EuiButton, EuiButtonEmpty, EuiHorizontalRule, - EuiCheckbox, EuiSpacer, - EuiFormRow, - EuiText, - EuiCallOut, - EuiComboBox, EuiFlexGroup, + EuiLoadingContent, + EuiCallOut, + EuiText, } from '@elastic/eui'; -import type { - CreateExceptionListItemSchema, - ExceptionListItemSchema, - ExceptionListType, - OsTypeArray, -} from '@kbn/securitysolution-io-ts-list-types'; + +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; +import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import type { OsTypeArray, ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; import type { ExceptionsBuilderExceptionItem, ExceptionsBuilderReturnExceptionItem, } from '@kbn/securitysolution-list-utils'; -import { getExceptionBuilderComponentLazy } from '@kbn/lists-plugin/public'; -import type { DataViewBase } from '@kbn/es-query'; -import { useRuleIndices } from '../../../../detections/containers/detection_engine/rules/use_rule_indices'; -import { hasEqlSequenceQuery, isEqlRule } from '../../../../../common/detection_engine/utils'; + import type { Status } from '../../../../../common/detection_engine/schemas/common/schemas'; -import * as i18nCommon from '../../../../common/translations'; import * as i18n from './translations'; -import * as sharedI18n from '../../utils/translations'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { useKibana } from '../../../../common/lib/kibana'; -import { Loader } from '../../../../common/components/loader'; -import { useAddOrUpdateException } from '../../logic/use_add_exception'; -import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index'; -import { useRuleAsync } from '../../../../detections/containers/detection_engine/rules/use_rule_async'; -import { useFetchOrCreateRuleExceptionList } from '../../logic/use_fetch_or_create_rule_exception_list'; import { ExceptionItemComments } from '../item_comments'; import { - enrichNewExceptionItemsWithComments, - enrichExceptionItemsWithOS, - lowercaseHashValues, defaultEndpointExceptionItems, - entryHasListType, - entryHasNonEcsType, retrieveAlertOsTypes, filterIndexPatterns, } from '../../utils/helpers'; -import type { ErrorInfo } from '../error_callout'; -import { ErrorCallout } from '../error_callout'; import type { AlertData } from '../../utils/types'; -import { useFetchIndex } from '../../../../common/containers/source'; +import { initialState, createExceptionItemsReducer } from './reducer'; +import { ExceptionsFlyoutMeta } from '../flyout_components/item_meta_form'; +import { ExceptionsConditions } from '../flyout_components/item_conditions'; +import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data'; +import type { Rule } from '../../../rule_management/logic/types'; +import { ExceptionItemsFlyoutAlertsActions } from '../flyout_components/alerts_actions'; +import { ExceptionsAddToRulesOrLists } from '../flyout_components/add_exception_to_rule_or_list'; +import { useAddNewExceptionItems } from './use_add_new_exceptions'; +import { entrichNewExceptionItems } from '../flyout_components/utils'; +import { useCloseAlertsFromExceptions } from '../../logic/use_close_alerts'; import { ruleTypesThatAllowLargeValueLists } from '../../utils/constants'; +const SectionHeader = styled(EuiTitle)` + ${() => css` + font-weight: ${({ theme }) => theme.eui.euiFontWeightSemiBold}; + `} +`; + export interface AddExceptionFlyoutProps { - ruleName: string; - ruleId: string; - exceptionListType: ExceptionListType; - ruleIndices: string[]; - dataViewId?: string; + rules: Rule[] | null; + isBulkAction: boolean; + showAlertCloseOptions: boolean; + isEndpointItem: boolean; alertData?: AlertData; /** * The components that use this may or may not define `alertData` @@ -86,40 +74,22 @@ export interface AddExceptionFlyoutProps { */ isAlertDataLoading?: boolean; alertStatus?: Status; - onCancel: () => void; - onConfirm: (didCloseAlert: boolean, didBulkCloseAlert: boolean) => void; - onRuleChange?: () => void; + onCancel: (didRuleChange: boolean) => void; + onConfirm: (didRuleChange: boolean, didCloseAlert: boolean, didBulkCloseAlert: boolean) => void; } -const FlyoutHeader = styled(EuiFlyoutHeader)` - ${({ theme }) => css` - border-bottom: 1px solid ${theme.eui.euiColorLightShade}; - `} -`; - -const FlyoutSubtitle = styled.div` - ${({ theme }) => css` - color: ${theme.eui.euiColorMediumShade}; - `} -`; - -const FlyoutBodySection = styled.section` - ${({ theme }) => css` - padding: ${theme.eui.euiSizeS} ${theme.eui.euiSizeL}; - +const FlyoutBodySection = styled(EuiFlyoutBody)` + ${() => css` &.builder-section { overflow-y: scroll; } `} `; -const FlyoutCheckboxesSection = styled(EuiFlyoutBody)` - overflow-y: inherit; - height: auto; - - .euiFlyoutBody__overflowContent { - padding-top: 0; - } +const FlyoutHeader = styled(EuiFlyoutHeader)` + ${({ theme }) => css` + border-bottom: 1px solid ${theme.eui.euiColorLightShade}; + `} `; const FlyoutFooterGroup = styled(EuiFlexGroup)` @@ -129,487 +99,430 @@ const FlyoutFooterGroup = styled(EuiFlexGroup)` `; export const AddExceptionFlyout = memo(function AddExceptionFlyout({ - ruleName, - ruleId, - ruleIndices, - dataViewId, - exceptionListType, + rules, + isBulkAction, + isEndpointItem, alertData, + showAlertCloseOptions, isAlertDataLoading, + alertStatus, onCancel, onConfirm, - onRuleChange, - alertStatus, }: AddExceptionFlyoutProps) { - const { http, unifiedSearch, data } = useKibana().services; - const [errorsExist, setErrorExists] = useState(false); - const [comment, setComment] = useState(''); - const { rule: maybeRule, loading: isRuleLoading } = useRuleAsync(ruleId); - const [shouldCloseAlert, setShouldCloseAlert] = useState(false); - const [shouldBulkCloseAlert, setShouldBulkCloseAlert] = useState(false); - const [shouldDisableBulkClose, setShouldDisableBulkClose] = useState(false); - const [exceptionItemsToAdd, setExceptionItemsToAdd] = useState< - ExceptionsBuilderReturnExceptionItem[] - >([]); - const [fetchOrCreateListError, setFetchOrCreateListError] = useState(null); - const { addError, addSuccess, addWarning } = useAppToasts(); - const { loading: isSignalIndexLoading, signalIndexName } = useSignalIndex(); - const memoSignalIndexName = useMemo( - () => (signalIndexName !== null ? [signalIndexName] : []), - [signalIndexName] - ); - const [isSignalIndexPatternLoading, { indexPatterns: signalIndexPatterns }] = - useFetchIndex(memoSignalIndexName); + const { isLoading, indexPatterns } = useFetchIndexPatterns(rules); + const [isSubmitting, submitNewExceptionItems] = useAddNewExceptionItems(); + const [isClosingAlerts, closeAlerts] = useCloseAlertsFromExceptions(); + + const allowLargeValueLists = useMemo((): boolean => { + if (rules != null && rules.length === 1) { + // We'll only block this when we know what rule we're dealing with. + // When dealing with numerous rules that can be a mix of those that do and + // don't work with large value lists we'll need to communicate that to the + // user but not block. + return ruleTypesThatAllowLargeValueLists.includes(rules[0].type); + } else { + return true; + } + }, [rules]); - const { mlJobLoading, ruleIndices: memoRuleIndices } = useRuleIndices( - maybeRule?.machine_learning_job_id, - ruleIndices - ); - const hasDataViewId = dataViewId || maybeRule?.data_view_id || null; - const [dataViewIndexPatterns, setDataViewIndexPatterns] = useState(null); - - useEffect(() => { - const fetchSingleDataView = async () => { - if (hasDataViewId) { - const dv = await data.dataViews.get(hasDataViewId); - setDataViewIndexPatterns(dv); - } - }; + const [ + { + exceptionItemMeta: { name: exceptionItemName }, + listType, + selectedOs, + initialItems, + exceptionItems, + disableBulkClose, + bulkCloseAlerts, + closeSingleAlert, + bulkCloseIndex, + addExceptionToRadioSelection, + selectedRulesToAddTo, + exceptionListsToAddTo, + newComment, + itemConditionValidationErrorExists, + errorSubmitting, + }, + dispatch, + ] = useReducer(createExceptionItemsReducer(), { + ...initialState, + addExceptionToRadioSelection: isBulkAction + ? 'add_to_rules' + : rules != null && rules.length === 1 + ? 'add_to_rule' + : 'select_rules_to_add_to', + listType: isEndpointItem ? ExceptionListTypeEnum.ENDPOINT : ExceptionListTypeEnum.RULE_DEFAULT, + selectedRulesToAddTo: rules != null ? rules : [], + }); - fetchSingleDataView(); - }, [hasDataViewId, data.dataViews, setDataViewIndexPatterns]); + const hasAlertData = useMemo((): boolean => { + return alertData != null; + }, [alertData]); - const [isIndexPatternLoading, { indexPatterns: indexIndexPatterns }] = useFetchIndex( - hasDataViewId ? [] : memoRuleIndices + /** + * Reducer action dispatchers + * */ + const setInitialExceptionItems = useCallback( + (items: ExceptionsBuilderExceptionItem[]): void => { + dispatch({ + type: 'setInitialExceptionItems', + items, + }); + }, + [dispatch] ); - const indexPattern = useMemo( - (): DataViewBase | null => (hasDataViewId ? dataViewIndexPatterns : indexIndexPatterns), - [hasDataViewId, dataViewIndexPatterns, indexIndexPatterns] + const setExceptionItemsToAdd = useCallback( + (items: ExceptionsBuilderReturnExceptionItem[]): void => { + dispatch({ + type: 'setExceptionItems', + items, + }); + }, + [dispatch] ); - const handleBuilderOnChange = useCallback( - ({ - exceptionItems, - errorExists, - }: { - exceptionItems: ExceptionsBuilderReturnExceptionItem[]; - errorExists: boolean; - }) => { - setExceptionItemsToAdd(exceptionItems); - setErrorExists(errorExists); + const setRadioOption = useCallback( + (option: string): void => { + dispatch({ + type: 'setListOrRuleRadioOption', + option, + }); }, - [setExceptionItemsToAdd] + [dispatch] ); - const handleRuleChange = useCallback( - (ruleChanged: boolean): void => { - if (ruleChanged && onRuleChange) { - onRuleChange(); - } + const setSelectedRules = useCallback( + (rulesSelectedToAdd: Rule[]): void => { + dispatch({ + type: 'setSelectedRulesToAddTo', + rules: rulesSelectedToAdd, + }); }, - [onRuleChange] + [dispatch] ); - const handleDissasociationSuccess = useCallback( - (id: string): void => { - handleRuleChange(true); - addSuccess(sharedI18n.DISSASOCIATE_LIST_SUCCESS(id)); - onCancel(); + const setListsToAddExceptionTo = useCallback( + (lists: ExceptionListSchema[]): void => { + dispatch({ + type: 'setAddExceptionToLists', + listsToAddTo: lists, + }); }, - [handleRuleChange, addSuccess, onCancel] + [dispatch] ); - const handleDissasociationError = useCallback( - (error: Error): void => { - addError(error, { title: sharedI18n.DISSASOCIATE_EXCEPTION_LIST_ERROR }); - onCancel(); + const setExceptionItemMeta = useCallback( + (value: [string, string]): void => { + dispatch({ + type: 'setExceptionItemMeta', + value, + }); }, - [addError, onCancel] + [dispatch] ); - const onError = useCallback( - (error: Error): void => { - addError(error, { title: i18n.ADD_EXCEPTION_ERROR }); - onCancel(); + const setConditionsValidationError = useCallback( + (errorExists: boolean): void => { + dispatch({ + type: 'setConditionValidationErrorExists', + errorExists, + }); }, - [addError, onCancel] + [dispatch] ); - const onSuccess = useCallback( - (updated: number, conflicts: number): void => { - handleRuleChange(true); - addSuccess(i18n.ADD_EXCEPTION_SUCCESS); - onConfirm(shouldCloseAlert, shouldBulkCloseAlert); - if (conflicts > 0) { - addWarning({ - title: i18nCommon.UPDATE_ALERT_STATUS_FAILED(conflicts), - text: i18nCommon.UPDATE_ALERT_STATUS_FAILED_DETAILED(updated, conflicts), - }); - } + const setSelectedOs = useCallback( + (os: OsTypeArray | undefined): void => { + dispatch({ + type: 'setSelectedOsOptions', + selectedOs: os, + }); }, - [addSuccess, addWarning, onConfirm, shouldBulkCloseAlert, shouldCloseAlert, handleRuleChange] + [dispatch] ); - const [{ isLoading: addExceptionIsLoading }, addOrUpdateExceptionItems] = useAddOrUpdateException( - { - http, - onSuccess, - onError, - } + const setComment = useCallback( + (comment: string): void => { + dispatch({ + type: 'setComment', + comment, + }); + }, + [dispatch] ); - const handleFetchOrCreateExceptionListError = useCallback( - (error: Error, statusCode: number | null, message: string | null): void => { - setFetchOrCreateListError({ - reason: error.message, - code: statusCode, - details: message, - listListId: null, + const setBulkCloseIndex = useCallback( + (index: string[] | undefined): void => { + dispatch({ + type: 'setBulkCloseIndex', + bulkCloseIndex: index, }); }, - [setFetchOrCreateListError] + [dispatch] ); - const [isLoadingExceptionList, ruleExceptionList] = useFetchOrCreateRuleExceptionList({ - http, - ruleId, - exceptionListType, - onError: handleFetchOrCreateExceptionListError, - onSuccess: handleRuleChange, - }); - - const initialExceptionItems = useMemo((): ExceptionsBuilderExceptionItem[] => { - if (exceptionListType === 'endpoint' && alertData != null && ruleExceptionList) { - return defaultEndpointExceptionItems(ruleExceptionList.list_id, ruleName, alertData); - } else { - return []; - } - }, [exceptionListType, ruleExceptionList, ruleName, alertData]); - - useEffect((): void => { - if (isSignalIndexPatternLoading === false && isSignalIndexLoading === false) { - setShouldDisableBulkClose( - entryHasListType(exceptionItemsToAdd) || - entryHasNonEcsType(exceptionItemsToAdd, signalIndexPatterns) || - exceptionItemsToAdd.every((item) => item.entries.length === 0) - ); - } - }, [ - setShouldDisableBulkClose, - exceptionItemsToAdd, - isSignalIndexPatternLoading, - isSignalIndexLoading, - signalIndexPatterns, - ]); - - useEffect((): void => { - if (shouldDisableBulkClose === true) { - setShouldBulkCloseAlert(false); - } - }, [shouldDisableBulkClose]); - - const onCommentChange = useCallback( - (value: string): void => { - setComment(value); + const setCloseSingleAlert = useCallback( + (close: boolean): void => { + dispatch({ + type: 'setCloseSingleAlert', + close, + }); }, - [setComment] + [dispatch] ); - const onCloseAlertCheckboxChange = useCallback( - (event: React.ChangeEvent): void => { - setShouldCloseAlert(event.currentTarget.checked); + const setBulkCloseAlerts = useCallback( + (bulkClose: boolean): void => { + dispatch({ + type: 'setBulkCloseAlerts', + bulkClose, + }); }, - [setShouldCloseAlert] + [dispatch] ); - const onBulkCloseAlertCheckboxChange = useCallback( - (event: React.ChangeEvent): void => { - setShouldBulkCloseAlert(event.currentTarget.checked); + const setDisableBulkCloseAlerts = useCallback( + (disableBulkCloseAlerts: boolean): void => { + dispatch({ + type: 'setDisableBulkCloseAlerts', + disableBulkCloseAlerts, + }); }, - [setShouldBulkCloseAlert] + [dispatch] ); - const hasAlertData = useMemo((): boolean => { - return alertData !== undefined; - }, [alertData]); + const setErrorSubmitting = useCallback( + (err: Error | null): void => { + dispatch({ + type: 'setErrorSubmitting', + err, + }); + }, + [dispatch] + ); - const [selectedOs, setSelectedOs] = useState(); + useEffect((): void => { + if (listType === ExceptionListTypeEnum.ENDPOINT && alertData != null) { + setInitialExceptionItems( + defaultEndpointExceptionItems(ENDPOINT_LIST_ID, exceptionItemName, alertData) + ); + } + }, [listType, exceptionItemName, alertData, setInitialExceptionItems]); const osTypesSelection = useMemo((): OsTypeArray => { return hasAlertData ? retrieveAlertOsTypes(alertData) : selectedOs ? [...selectedOs] : []; }, [hasAlertData, alertData, selectedOs]); - const enrichExceptionItems = useCallback((): ExceptionsBuilderReturnExceptionItem[] => { - let enriched: ExceptionsBuilderReturnExceptionItem[] = []; - enriched = - comment !== '' - ? enrichNewExceptionItemsWithComments(exceptionItemsToAdd, [{ comment }]) - : exceptionItemsToAdd; - if (exceptionListType === 'endpoint') { - const osTypes = osTypesSelection; - enriched = lowercaseHashValues(enrichExceptionItemsWithOS(enriched, osTypes)); - } - return enriched; - }, [comment, exceptionItemsToAdd, exceptionListType, osTypesSelection]); - - const onAddExceptionConfirm = useCallback((): void => { - if (addOrUpdateExceptionItems != null) { - const alertIdToClose = shouldCloseAlert && alertData ? alertData._id : undefined; - const bulkCloseIndex = - shouldBulkCloseAlert && signalIndexName != null ? [signalIndexName] : undefined; - addOrUpdateExceptionItems( - maybeRule?.rule_id ?? '', - // This is being rewritten in https://github.com/elastic/kibana/pull/140643 - // As of now, flyout cannot yet create item of type CreateRuleExceptionListItemSchema - enrichExceptionItems() as Array, - alertIdToClose, - bulkCloseIndex - ); + const handleOnSubmit = useCallback(async (): Promise => { + if (submitNewExceptionItems == null) return; + + try { + const ruleDefaultOptions = ['add_to_rule', 'add_to_rules', 'select_rules_to_add_to']; + const addToRules = ruleDefaultOptions.includes(addExceptionToRadioSelection); + const addToSharedLists = addExceptionToRadioSelection === 'add_to_lists'; + + const items = entrichNewExceptionItems({ + itemName: exceptionItemName, + commentToAdd: newComment, + addToRules, + addToSharedLists, + sharedLists: exceptionListsToAddTo, + listType, + selectedOs: osTypesSelection, + items: exceptionItems, + }); + + const addedItems = await submitNewExceptionItems({ + itemsToAdd: items, + selectedRulesToAddTo, + listType, + addToRules: addToRules && !isEmpty(selectedRulesToAddTo), + addToSharedLists: addToSharedLists && !isEmpty(exceptionListsToAddTo), + sharedLists: exceptionListsToAddTo, + }); + + const alertIdToClose = closeSingleAlert && alertData ? alertData._id : undefined; + const ruleStaticIds = addToRules + ? selectedRulesToAddTo.map(({ rule_id: ruleId }) => ruleId) + : (rules ?? []).map(({ rule_id: ruleId }) => ruleId); + + if (closeAlerts != null && !isEmpty(ruleStaticIds) && (bulkCloseAlerts || closeSingleAlert)) { + await closeAlerts(ruleStaticIds, addedItems, alertIdToClose, bulkCloseIndex); + } + + // Rule only would have been updated if we had to create a rule default list + // to attach to it, all shared lists would already be referenced on the rule + onConfirm(true, closeSingleAlert, bulkCloseAlerts); + } catch (e) { + setErrorSubmitting(e); } }, [ - addOrUpdateExceptionItems, - maybeRule, - enrichExceptionItems, - shouldCloseAlert, - shouldBulkCloseAlert, + submitNewExceptionItems, + addExceptionToRadioSelection, + exceptionItemName, + newComment, + exceptionListsToAddTo, + listType, + osTypesSelection, + exceptionItems, + selectedRulesToAddTo, + closeSingleAlert, alertData, - signalIndexName, + rules, + closeAlerts, + bulkCloseAlerts, + onConfirm, + bulkCloseIndex, + setErrorSubmitting, ]); const isSubmitButtonDisabled = useMemo( (): boolean => - fetchOrCreateListError != null || - exceptionItemsToAdd.every((item) => item.entries.length === 0) || - errorsExist, - [fetchOrCreateListError, exceptionItemsToAdd, errorsExist] - ); - - const addExceptionMessage = - exceptionListType === 'endpoint' ? i18n.ADD_ENDPOINT_EXCEPTION : i18n.ADD_EXCEPTION; - - const isRuleEQLSequenceStatement = useMemo((): boolean => { - if (maybeRule != null) { - return isEqlRule(maybeRule.type) && hasEqlSequenceQuery(maybeRule.query); - } - return false; - }, [maybeRule]); - - const OsOptions: Array> = useMemo((): Array< - EuiComboBoxOptionOption - > => { - return [ - { - label: sharedI18n.OPERATING_SYSTEM_WINDOWS, - value: ['windows'], - }, - { - label: sharedI18n.OPERATING_SYSTEM_MAC, - value: ['macos'], - }, - { - label: sharedI18n.OPERATING_SYSTEM_LINUX, - value: ['linux'], - }, - { - label: sharedI18n.OPERATING_SYSTEM_WINDOWS_AND_MAC, - value: ['windows', 'macos'], - }, - ]; - }, []); - - const handleOSSelectionChange = useCallback( - (selectedOptions): void => { - setSelectedOs(selectedOptions[0].value); - }, - [setSelectedOs] + isSubmitting || + isClosingAlerts || + errorSubmitting != null || + exceptionItemName.trim() === '' || + exceptionItems.every((item) => item.entries.length === 0) || + itemConditionValidationErrorExists || + (addExceptionToRadioSelection === 'add_to_lists' && isEmpty(exceptionListsToAddTo)), + [ + isSubmitting, + isClosingAlerts, + errorSubmitting, + exceptionItemName, + exceptionItems, + itemConditionValidationErrorExists, + addExceptionToRadioSelection, + exceptionListsToAddTo, + ] ); - const selectedOStoOptions = useMemo((): Array> => { - return OsOptions.filter((option) => { - return selectedOs === option.value; - }); - }, [selectedOs, OsOptions]); - - const singleSelectionOptions = useMemo(() => { - return { asPlainText: true }; - }, []); + const handleDismissError = useCallback((): void => { + setErrorSubmitting(null); + }, [setErrorSubmitting]); - const hasOsSelection = useMemo(() => { - return exceptionListType === 'endpoint' && !hasAlertData; - }, [exceptionListType, hasAlertData]); + const handleCloseFlyout = useCallback((): void => { + onCancel(false); + }, [onCancel]); - const isExceptionBuilderFormDisabled = useMemo(() => { - return hasOsSelection && selectedOs === undefined; - }, [hasOsSelection, selectedOs]); - - const allowLargeValueLists = useMemo( - () => (maybeRule != null ? ruleTypesThatAllowLargeValueLists.includes(maybeRule.type) : false), - [maybeRule] - ); + const addExceptionMessage = useMemo(() => { + return listType === ExceptionListTypeEnum.ENDPOINT + ? i18n.ADD_ENDPOINT_EXCEPTION + : i18n.CREATE_RULE_EXCEPTION; + }, [listType]); return ( -

    {addExceptionMessage}

    +

    {addExceptionMessage}

    - - - {ruleName} -
    - {fetchOrCreateListError != null && ( - - } + {!isLoading && ( + + {errorSubmitting != null && ( + <> + + {i18n.SUBMIT_ERROR_DISMISS_MESSAGE} + + + {i18n.SUBMIT_ERROR_DISMISS_BUTTON} + + + + + )} + - - )} - {fetchOrCreateListError == null && - (isLoadingExceptionList || - isIndexPatternLoading || - isSignalIndexLoading || - isAlertDataLoading || - isSignalIndexPatternLoading) && ( - - )} - {fetchOrCreateListError == null && - indexPattern != null && - !isSignalIndexLoading && - !isSignalIndexPatternLoading && - !isLoadingExceptionList && - !isIndexPatternLoading && - !isRuleLoading && - !mlJobLoading && - !isAlertDataLoading && - ruleExceptionList && ( - <> - - {isRuleEQLSequenceStatement && ( - <> - - - - )} - {i18n.EXCEPTION_BUILDER_INFO} - - {exceptionListType === 'endpoint' && !hasAlertData && ( - <> - - - - - - )} - {getExceptionBuilderComponentLazy({ - allowLargeValueLists, - httpService: http, - autocompleteService: unifiedSearch.autocomplete, - exceptionListItems: initialExceptionItems, - listType: exceptionListType, - osTypes: osTypesSelection, - listId: ruleExceptionList.list_id, - listNamespaceType: ruleExceptionList.namespace_type, - listTypeSpecificIndexPatternFilter: filterIndexPatterns, - ruleName, - indexPatterns: indexPattern, - isOrDisabled: isExceptionBuilderFormDisabled, - isAndDisabled: isExceptionBuilderFormDisabled, - isNestedDisabled: isExceptionBuilderFormDisabled, - dataTestSubj: 'alert-exception-builder', - idAria: 'alert-exception-builder', - onChange: handleBuilderOnChange, - isDisabled: isExceptionBuilderFormDisabled, - })} - - - - + + + {listType !== ExceptionListTypeEnum.ENDPOINT && ( + <> + + + + )} + + +

    {i18n.COMMENTS_SECTION_TITLE(0)}

    + + } + newCommentValue={newComment} + newCommentOnChange={setComment} + /> + {showAlertCloseOptions && ( + <> + + -
    - - - {alertData != null && alertStatus !== 'closed' && ( - - - - )} - - - - {exceptionListType === 'endpoint' && ( - <> - - - {i18n.ENDPOINT_QUARANTINE_TEXT} - - - )} - - - )} - {fetchOrCreateListError == null && ( - - - - {i18n.CANCEL} - - - - {addExceptionMessage} - - - + + )} + )} + + + + {i18n.CANCEL} + + + + {addExceptionMessage} + + +
    ); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts new file mode 100644 index 0000000000000..c36c842930b0f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts @@ -0,0 +1,250 @@ +/* + * 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 { ExceptionListSchema, OsTypeArray } from '@kbn/securitysolution-io-ts-list-types'; +import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import type { + ExceptionsBuilderExceptionItem, + ExceptionsBuilderReturnExceptionItem, +} from '@kbn/securitysolution-list-utils'; + +import type { Rule } from '../../../rule_management/logic/types'; + +export interface State { + exceptionItemMeta: { name: string }; + listType: ExceptionListTypeEnum; + initialItems: ExceptionsBuilderExceptionItem[]; + exceptionItems: ExceptionsBuilderReturnExceptionItem[]; + newComment: string; + addExceptionToRadioSelection: string; + itemConditionValidationErrorExists: boolean; + closeSingleAlert: boolean; + bulkCloseAlerts: boolean; + disableBulkClose: boolean; + bulkCloseIndex: string[] | undefined; + selectedOs: OsTypeArray | undefined; + exceptionListsToAddTo: ExceptionListSchema[]; + selectedRulesToAddTo: Rule[]; + errorSubmitting: Error | null; +} + +export const initialState: State = { + initialItems: [], + exceptionItems: [], + exceptionItemMeta: { name: '' }, + newComment: '', + itemConditionValidationErrorExists: false, + closeSingleAlert: false, + bulkCloseAlerts: false, + disableBulkClose: false, + bulkCloseIndex: undefined, + selectedOs: undefined, + exceptionListsToAddTo: [], + addExceptionToRadioSelection: 'add_to_rule', + selectedRulesToAddTo: [], + listType: ExceptionListTypeEnum.RULE_DEFAULT, + errorSubmitting: null, +}; + +export type Action = + | { + type: 'setExceptionItemMeta'; + value: [string, string]; + } + | { + type: 'setInitialExceptionItems'; + items: ExceptionsBuilderExceptionItem[]; + } + | { + type: 'setExceptionItems'; + items: ExceptionsBuilderReturnExceptionItem[]; + } + | { + type: 'setConditionValidationErrorExists'; + errorExists: boolean; + } + | { + type: 'setComment'; + comment: string; + } + | { + type: 'setCloseSingleAlert'; + close: boolean; + } + | { + type: 'setBulkCloseAlerts'; + bulkClose: boolean; + } + | { + type: 'setDisableBulkCloseAlerts'; + disableBulkCloseAlerts: boolean; + } + | { + type: 'setBulkCloseIndex'; + bulkCloseIndex: string[] | undefined; + } + | { + type: 'setSelectedOsOptions'; + selectedOs: OsTypeArray | undefined; + } + | { + type: 'setAddExceptionToLists'; + listsToAddTo: ExceptionListSchema[]; + } + | { + type: 'setListOrRuleRadioOption'; + option: string; + } + | { + type: 'setSelectedRulesToAddTo'; + rules: Rule[]; + } + | { + type: 'setListType'; + listType: ExceptionListTypeEnum; + } + | { + type: 'setErrorSubmitting'; + err: Error | null; + }; + +export const createExceptionItemsReducer = + () => + (state: State, action: Action): State => { + switch (action.type) { + case 'setExceptionItemMeta': { + const { value } = action; + + return { + ...state, + exceptionItemMeta: { + ...state.exceptionItemMeta, + [value[0]]: value[1], + }, + }; + } + case 'setInitialExceptionItems': { + const { items } = action; + + return { + ...state, + initialItems: items, + }; + } + case 'setExceptionItems': { + const { items } = action; + + return { + ...state, + exceptionItems: items, + }; + } + case 'setConditionValidationErrorExists': { + const { errorExists } = action; + + return { + ...state, + itemConditionValidationErrorExists: errorExists, + }; + } + case 'setComment': { + const { comment } = action; + + return { + ...state, + newComment: comment, + }; + } + case 'setCloseSingleAlert': { + const { close } = action; + + return { + ...state, + closeSingleAlert: close, + }; + } + case 'setBulkCloseAlerts': { + const { bulkClose } = action; + + return { + ...state, + bulkCloseAlerts: bulkClose, + }; + } + case 'setBulkCloseIndex': { + const { bulkCloseIndex } = action; + + return { + ...state, + bulkCloseIndex, + }; + } + case 'setSelectedOsOptions': { + const { selectedOs } = action; + + return { + ...state, + selectedOs, + }; + } + case 'setAddExceptionToLists': { + const { listsToAddTo } = action; + + return { + ...state, + exceptionListsToAddTo: listsToAddTo, + }; + } + case 'setListOrRuleRadioOption': { + const { option } = action; + + return { + ...state, + addExceptionToRadioSelection: option, + listType: + option === 'add_to_lists' + ? ExceptionListTypeEnum.DETECTION + : ExceptionListTypeEnum.RULE_DEFAULT, + selectedRulesToAddTo: option === 'add_to_lists' ? [] : state.selectedRulesToAddTo, + }; + } + case 'setSelectedRulesToAddTo': { + const { rules } = action; + + return { + ...state, + selectedRulesToAddTo: rules, + }; + } + case 'setListType': { + const { listType } = action; + + return { + ...state, + listType, + }; + } + case 'setDisableBulkCloseAlerts': { + const { disableBulkCloseAlerts } = action; + + return { + ...state, + disableBulkClose: disableBulkCloseAlerts, + }; + } + case 'setErrorSubmitting': { + const { err } = action; + + return { + ...state, + errorSubmitting: err, + }; + } + default: + return state; + } + }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts index fe0b316648214..eea7f90d07e5c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts @@ -7,79 +7,79 @@ import { i18n } from '@kbn/i18n'; -export const CANCEL = i18n.translate('xpack.securitySolution.exceptions.addException.cancel', { +export const CANCEL = i18n.translate('xpack.securitySolution.ruleExceptions.addException.cancel', { defaultMessage: 'Cancel', }); -export const ADD_EXCEPTION = i18n.translate( - 'xpack.securitySolution.exceptions.addException.addException', +export const CREATE_RULE_EXCEPTION = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addException.createRuleExceptionLabel', { - defaultMessage: 'Add Rule Exception', + defaultMessage: 'Add rule exception', } ); export const ADD_ENDPOINT_EXCEPTION = i18n.translate( - 'xpack.securitySolution.exceptions.addException.addEndpointException', + 'xpack.securitySolution.ruleExceptions.addException.addEndpointException', { defaultMessage: 'Add Endpoint Exception', } ); -export const ADD_EXCEPTION_ERROR = i18n.translate( - 'xpack.securitySolution.exceptions.addException.error', +export const SUBMIT_ERROR_TITLE = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addException.submitError.title', { - defaultMessage: 'Failed to add exception', + defaultMessage: 'An error occured submitting exception', } ); -export const ADD_EXCEPTION_SUCCESS = i18n.translate( - 'xpack.securitySolution.exceptions.addException.success', +export const SUBMIT_ERROR_DISMISS_BUTTON = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addException.submitError.dismissButton', { - defaultMessage: 'Successfully added exception', + defaultMessage: 'Dismiss', } ); -export const ENDPOINT_QUARANTINE_TEXT = i18n.translate( - 'xpack.securitySolution.exceptions.addException.endpointQuarantineText', +export const SUBMIT_ERROR_DISMISS_MESSAGE = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addException.submitError.message', { - defaultMessage: - 'On all Endpoint hosts, quarantined files that match the exception are automatically restored to their original locations. This exception applies to all rules using Endpoint exceptions.', + defaultMessage: 'View toast for error details.', } ); -export const BULK_CLOSE_LABEL = i18n.translate( - 'xpack.securitySolution.exceptions.addException.bulkCloseLabel', +export const ADD_EXCEPTION_SUCCESS = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addException.success', { - defaultMessage: 'Close all alerts that match this exception and were generated by this rule', + defaultMessage: 'Rule exception added to shared exception list', } ); -export const BULK_CLOSE_LABEL_DISABLED = i18n.translate( - 'xpack.securitySolution.exceptions.addException.bulkCloseLabel.disabled', - { - defaultMessage: - 'Close all alerts that match this exception and were generated by this rule (Lists and non-ECS fields are not supported)', - } -); +export const ADD_EXCEPTION_SUCCESS_DETAILS = (listNames: string) => + i18n.translate( + 'xpack.securitySolution.ruleExceptions.addExceptionFlyout.closeAlerts.successDetails', + { + values: { listNames }, + defaultMessage: 'Rule exception has been added to shared lists: {listNames}.', + } + ); -export const EXCEPTION_BUILDER_INFO = i18n.translate( - 'xpack.securitySolution.exceptions.addException.infoLabel', +export const ADD_RULE_EXCEPTION_SUCCESS_TITLE = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessTitle', { - defaultMessage: "Alerts are generated when the rule's conditions are met, except when:", + defaultMessage: 'Rule exception added', } ); -export const ADD_EXCEPTION_SEQUENCE_WARNING = i18n.translate( - 'xpack.securitySolution.exceptions.addException.sequenceWarning', - { - defaultMessage: - "This rule's query contains an EQL sequence statement. The exception created will apply to all events in the sequence.", - } -); +export const ADD_RULE_EXCEPTION_SUCCESS_TEXT = (ruleName: string) => + i18n.translate( + 'xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessText', + { + values: { ruleName }, + defaultMessage: 'Exception has been added to rules - {ruleName}.', + } + ); -export const OPERATING_SYSTEM_PLACEHOLDER = i18n.translate( - 'xpack.securitySolution.exceptions.addException.operatingSystemPlaceHolder', - { - defaultMessage: 'Select an operating system', - } -); +export const COMMENTS_SECTION_TITLE = (comments: number) => + i18n.translate('xpack.securitySolution.ruleExceptions.addExceptionFlyout.commentsTitle', { + values: { comments }, + defaultMessage: 'Add comments ({comments})', + }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/use_add_new_exceptions.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/use_add_new_exceptions.ts new file mode 100644 index 0000000000000..7aa686ed43cdf --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/use_add_new_exceptions.ts @@ -0,0 +1,148 @@ +/* + * 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 { useEffect, useRef, useCallback, useState } from 'react'; +import type { + CreateExceptionListItemSchema, + CreateRuleExceptionListItemSchema, + ExceptionListItemSchema, + ExceptionListSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { + createExceptionListItemSchema, + exceptionListItemSchema, + ExceptionListTypeEnum, + createRuleExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import type { ExceptionsBuilderReturnExceptionItem } from '@kbn/securitysolution-list-utils'; + +import * as i18n from './translations'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import type { Rule } from '../../../rule_management/logic/types'; +import { useCreateOrUpdateException } from '../../logic/use_create_update_exception'; +import { useAddRuleDefaultException } from '../../logic/use_add_rule_exception'; + +export interface AddNewExceptionItemHookProps { + itemsToAdd: ExceptionsBuilderReturnExceptionItem[]; + listType: ExceptionListTypeEnum; + selectedRulesToAddTo: Rule[]; + addToSharedLists: boolean; + addToRules: boolean; + sharedLists: ExceptionListSchema[]; +} + +export type AddNewExceptionItemHookFuncProps = ( + arg: AddNewExceptionItemHookProps +) => Promise; + +export type ReturnUseAddNewExceptionItems = [boolean, AddNewExceptionItemHookFuncProps | null]; + +/** + * Hook for adding new exception items from flyout + * + */ +export const useAddNewExceptionItems = (): ReturnUseAddNewExceptionItems => { + const { addSuccess, addError, addWarning } = useAppToasts(); + const [isAddRuleExceptionLoading, addRuleExceptions] = useAddRuleDefaultException(); + const [isAddingExceptions, addSharedExceptions] = useCreateOrUpdateException(); + + const [isLoading, setIsLoading] = useState(false); + const addNewExceptionsRef = useRef(null); + + const areRuleDefaultItems = useCallback( + ( + items: ExceptionsBuilderReturnExceptionItem[] + ): items is CreateRuleExceptionListItemSchema[] => { + return items.every((item) => createRuleExceptionListItemSchema.is(item)); + }, + [] + ); + + const areSharedListItems = useCallback( + ( + items: ExceptionsBuilderReturnExceptionItem[] + ): items is Array => { + return items.every( + (item) => exceptionListItemSchema.is(item) || createExceptionListItemSchema.is(item) + ); + }, + [] + ); + + useEffect(() => { + const abortCtrl = new AbortController(); + + const addNewExceptions = async ({ + itemsToAdd, + listType, + selectedRulesToAddTo, + addToRules, + addToSharedLists, + sharedLists, + }: AddNewExceptionItemHookProps): Promise => { + try { + let result: ExceptionListItemSchema[] = []; + setIsLoading(true); + + if ( + addToRules && + addRuleExceptions != null && + listType !== ExceptionListTypeEnum.ENDPOINT && + areRuleDefaultItems(itemsToAdd) + ) { + result = await addRuleExceptions(itemsToAdd, selectedRulesToAddTo); + + const ruleNames = selectedRulesToAddTo.map(({ name }) => name).join(', '); + + addSuccess({ + title: i18n.ADD_RULE_EXCEPTION_SUCCESS_TITLE, + text: i18n.ADD_RULE_EXCEPTION_SUCCESS_TEXT(ruleNames), + }); + } else if ( + (listType === ExceptionListTypeEnum.ENDPOINT || addToSharedLists) && + addSharedExceptions != null && + areSharedListItems(itemsToAdd) + ) { + result = await addSharedExceptions(itemsToAdd); + + const sharedListNames = sharedLists.map(({ name }) => name); + + addSuccess({ + title: i18n.ADD_EXCEPTION_SUCCESS, + text: i18n.ADD_EXCEPTION_SUCCESS_DETAILS(sharedListNames.join(',')), + }); + } + + setIsLoading(false); + + return result; + } catch (e) { + setIsLoading(false); + addError(e, { title: i18n.SUBMIT_ERROR_TITLE }); + throw e; + } + }; + + addNewExceptionsRef.current = addNewExceptions; + return (): void => { + abortCtrl.abort(); + }; + }, [ + addSuccess, + addError, + addWarning, + addRuleExceptions, + addSharedExceptions, + areRuleDefaultItems, + areSharedListItems, + ]); + + return [ + isLoading || isAddingExceptions || isAddRuleExceptionLoading, + addNewExceptionsRef.current, + ]; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/all_items.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/all_items.test.tsx index 0df9fad55a14d..2caf7d352a733 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/all_items.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/all_items.test.tsx @@ -10,7 +10,6 @@ import { ThemeProvider } from 'styled-components'; import { mount } from 'enzyme'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionsViewerItems } from './all_items'; import { getMockTheme } from '../../../../common/lib/kibana/kibana_react.mock'; @@ -31,7 +30,7 @@ describe('ExceptionsViewerItems', () => { { ); expect( - wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty-detection"]').exists() + wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty"]').exists() ).toBeTruthy(); expect(wrapper.find('[data-test-subj="exceptionsContainer"]').exists()).toBeFalsy(); }); @@ -55,7 +54,7 @@ describe('ExceptionsViewerItems', () => { { void; @@ -42,7 +39,7 @@ interface ExceptionItemsViewerProps { const ExceptionItemsViewerComponent: React.FC = ({ isReadOnly, exceptions, - listType, + isEndpoint, disableActions, ruleReferences, viewerState, @@ -55,7 +52,7 @@ const ExceptionItemsViewerComponent: React.FC = ({ {viewerState != null && viewerState !== 'deleting' ? ( @@ -68,8 +65,8 @@ const ExceptionItemsViewerComponent: React.FC = ({ { const wrapper = mount( @@ -33,7 +31,7 @@ describe('ExeptionItemsViewerEmptyPrompts', () => { const wrapper = mount( @@ -44,11 +42,11 @@ describe('ExeptionItemsViewerEmptyPrompts', () => { ).toBeTruthy(); }); - it('it renders no endpoint items screen when "currentState" is "empty" and "listType" is "endpoint"', () => { + it('it renders no endpoint items screen when "currentState" is "empty" and "isEndpoint" is "true"', () => { const wrapper = mount( @@ -61,15 +59,15 @@ describe('ExeptionItemsViewerEmptyPrompts', () => { i18n.EXCEPTION_EMPTY_PROMPT_ENDPOINT_BUTTON ); expect( - wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty-endpoint"]').exists() + wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty"]').exists() ).toBeTruthy(); }); - it('it renders no exception items screen when "currentState" is "empty" and "listType" is "detection"', () => { + it('it renders no exception items screen when "currentState" is "empty" and "isEndpoint" is "false"', () => { const wrapper = mount( @@ -82,7 +80,7 @@ describe('ExeptionItemsViewerEmptyPrompts', () => { i18n.EXCEPTION_EMPTY_PROMPT_BUTTON ); expect( - wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty-detection"]').exists() + wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty"]').exists() ).toBeTruthy(); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/empty_viewer_state.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/empty_viewer_state.tsx index 2be1860f138d3..b00bf7dd75134 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/empty_viewer_state.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/empty_viewer_state.tsx @@ -15,21 +15,20 @@ import { EuiPanel, } from '@elastic/eui'; -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import * as i18n from './translations'; import type { ViewerState } from './reducer'; import illustration from '../../../../common/images/illustration_product_no_results_magnifying_glass.svg'; interface ExeptionItemsViewerEmptyPromptsComponentProps { isReadOnly: boolean; - listType: ExceptionListTypeEnum; + isEndpoint: boolean; currentState: ViewerState; onCreateExceptionListItem: () => void; } const ExeptionItemsViewerEmptyPromptsComponent = ({ isReadOnly, - listType, + isEndpoint, currentState, onCreateExceptionListItem, }: ExeptionItemsViewerEmptyPromptsComponentProps): JSX.Element => { @@ -60,7 +59,7 @@ const ExeptionItemsViewerEmptyPromptsComponent = ({ } body={

    - {listType === ExceptionListTypeEnum.ENDPOINT + {isEndpoint ? i18n.EXCEPTION_EMPTY_ENDPOINT_PROMPT_BODY : i18n.EXCEPTION_EMPTY_PROMPT_BODY}

    @@ -74,12 +73,12 @@ const ExeptionItemsViewerEmptyPromptsComponent = ({ isDisabled={isReadOnly} fill > - {listType === ExceptionListTypeEnum.ENDPOINT + {isEndpoint ? i18n.EXCEPTION_EMPTY_PROMPT_ENDPOINT_BUTTON : i18n.EXCEPTION_EMPTY_PROMPT_BUTTON} , ]} - data-test-subj={`exceptionItemViewerEmptyPrompts-empty-${listType}`} + data-test-subj="exceptionItemViewerEmptyPrompts-empty" /> ); case 'empty_search': @@ -100,7 +99,13 @@ const ExeptionItemsViewerEmptyPromptsComponent = ({ ); } - }, [currentState, euiTheme.colors.darkestShade, isReadOnly, listType, onCreateExceptionListItem]); + }, [ + currentState, + euiTheme.colors.darkestShade, + isReadOnly, + isEndpoint, + onCreateExceptionListItem, + ]); return ( { }, }); - (useFindExceptionListReferences as jest.Mock).mockReturnValue([false, null]); + (useFindExceptionListReferences as jest.Mock).mockReturnValue([ + false, + false, + { + list_id: { + _version: 'WzEzNjMzLDFd', + created_at: '2022-09-26T19:41:43.338Z', + created_by: 'elastic', + description: + 'Exception list containing exceptions for rule with id: 178c2e10-3dd3-11ed-81d7-37f31b5b97f6', + id: '3fa2c8a0-3dd3-11ed-81d7-37f31b5b97f6', + immutable: false, + list_id: 'list_id', + name: 'Exceptions for rule - My really good rule', + namespace_type: 'single', + os_types: [], + tags: ['default_rule_exception_list'], + tie_breaker_id: '83395c3e-76a0-466e-ba58-2f5a4b8b5444', + type: 'rule_default', + updated_at: '2022-09-26T19:41:43.342Z', + updated_by: 'elastic', + version: 1, + referenced_rules: [ + { + name: 'My really good rule', + id: '178c2e10-3dd3-11ed-81d7-37f31b5b97f6', + rule_id: 'cc604877-838b-438d-866b-8bce5237aa07', + exception_lists: [ + { + id: '3fa2c8a0-3dd3-11ed-81d7-37f31b5b97f6', + list_id: 'list_id', + type: 'rule_default', + namespace_type: 'single', + }, + ], + }, + ], + }, + }, + jest.fn(), + ]); }); it('it renders loading screen when "currentState" is "loading"', () => { @@ -108,7 +148,7 @@ describe('ExceptionsViewer', () => { }, ], }} - listType={ExceptionListTypeEnum.DETECTION} + listTypes={[ExceptionListTypeEnum.DETECTION]} isViewReadOnly={false} /> @@ -146,7 +186,7 @@ describe('ExceptionsViewer', () => { }, ], }} - listType={ExceptionListTypeEnum.DETECTION} + listTypes={[ExceptionListTypeEnum.DETECTION]} isViewReadOnly={false} /> @@ -157,7 +197,7 @@ describe('ExceptionsViewer', () => { ).toBeTruthy(); }); - it('it renders no endpoint items screen when "currentState" is "empty" and "listType" is "endpoint"', () => { + it('it renders no endpoint items screen when "currentState" is "empty" and "listTypes" includes only "endpoint"', () => { (useReducer as jest.Mock).mockReturnValue([ { exceptions: [], @@ -184,7 +224,7 @@ describe('ExceptionsViewer', () => { }, ], }} - listType={ExceptionListTypeEnum.ENDPOINT} + listTypes={[ExceptionListTypeEnum.ENDPOINT]} isViewReadOnly={false} /> @@ -197,11 +237,11 @@ describe('ExceptionsViewer', () => { i18n.EXCEPTION_EMPTY_PROMPT_ENDPOINT_BUTTON ); expect( - wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty-endpoint"]').exists() + wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty"]').exists() ).toBeTruthy(); }); - it('it renders no exception items screen when "currentState" is "empty" and "listType" is "detection"', () => { + it('it renders no exception items screen when "currentState" is "empty" and "listTypes" includes "detection"', () => { (useReducer as jest.Mock).mockReturnValue([ { exceptions: [], @@ -228,7 +268,7 @@ describe('ExceptionsViewer', () => { }, ], }} - listType={ExceptionListTypeEnum.DETECTION} + listTypes={[ExceptionListTypeEnum.DETECTION]} isViewReadOnly={false} /> @@ -241,7 +281,7 @@ describe('ExceptionsViewer', () => { i18n.EXCEPTION_EMPTY_PROMPT_BUTTON ); expect( - wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty-detection"]').exists() + wrapper.find('[data-test-subj="exceptionItemViewerEmptyPrompts-empty"]').exists() ).toBeTruthy(); }); @@ -271,7 +311,7 @@ describe('ExceptionsViewer', () => { }, ], }} - listType={ExceptionListTypeEnum.DETECTION} + listTypes={[ExceptionListTypeEnum.DETECTION]} isViewReadOnly={false} /> ); @@ -305,7 +345,7 @@ describe('ExceptionsViewer', () => { }, ], }} - listType={ExceptionListTypeEnum.DETECTION} + listTypes={[ExceptionListTypeEnum.DETECTION]} isViewReadOnly={false} /> ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.tsx index 97de081738ffd..f0c71819d4bce 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.tsx @@ -6,22 +6,24 @@ */ import React, { useCallback, useMemo, useEffect, useReducer } from 'react'; +import styled from 'styled-components'; + import { EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; +import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import type { ExceptionListItemSchema, UseExceptionListItemsSuccess, Pagination, + ExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { transformInput } from '@kbn/securitysolution-list-hooks'; import { deleteExceptionListItemById, fetchExceptionListsItemsByListIds, } from '@kbn/securitysolution-list-api'; -import styled from 'styled-components'; -import { DEFAULT_INDEX_PATTERN } from '../../../../../common/constants'; + import { useUserData } from '../../../../detections/components/user_info'; import { useKibana, useToasts } from '../../../../common/lib/kibana'; import { ExceptionsViewerSearchBar } from './search_bar'; @@ -36,7 +38,7 @@ import { EditExceptionFlyout } from '../edit_exception_flyout'; import { AddExceptionFlyout } from '../add_exception_flyout'; import * as i18n from './translations'; import { useFindExceptionListReferences } from '../../logic/use_find_references'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../rule_management/logic/types'; const StyledText = styled(EuiText)` font-style: italic; @@ -74,7 +76,7 @@ export interface GetExceptionItemProps { interface ExceptionsViewerProps { rule: Rule | null; - listType: ExceptionListTypeEnum; + listTypes: ExceptionListTypeEnum[]; /* Used for when displaying exceptions for a rule that has since been deleted, forcing read only view */ isViewReadOnly: boolean; onRuleChange?: () => void; @@ -82,7 +84,7 @@ interface ExceptionsViewerProps { const ExceptionsViewerComponent = ({ rule, - listType, + listTypes, isViewReadOnly, onRuleChange, }: ExceptionsViewerProps): JSX.Element => { @@ -92,9 +94,24 @@ const ExceptionsViewerComponent = ({ const exceptionListsToQuery = useMemo( () => rule != null && rule.exceptions_list != null - ? rule.exceptions_list.filter((list) => list.type === listType) + ? rule.exceptions_list.filter(({ type }) => + listTypes.includes(type as ExceptionListTypeEnum) + ) : [], - [listType, rule] + [listTypes, rule] + ); + const exceptionListsFormattedForReferenceQuery = useMemo( + () => + exceptionListsToQuery.map(({ id, list_id: listId, namespace_type: namespaceType }) => ({ + id, + listId, + namespaceType, + })), + [exceptionListsToQuery] + ); + const isEndpointSpecified = useMemo( + () => listTypes.length === 1 && listTypes[0] === ExceptionListTypeEnum.ENDPOINT, + [listTypes] ); // Reducer state @@ -166,13 +183,10 @@ const ExceptionsViewerComponent = ({ useFindExceptionListReferences(); useEffect(() => { - if (fetchReferences != null && exceptionListsToQuery.length) { - const listsToQuery = exceptionListsToQuery.map( - ({ id, list_id: listId, namespace_type: namespaceType }) => ({ id, listId, namespaceType }) - ); - fetchReferences(listsToQuery); + if (fetchReferences != null && exceptionListsFormattedForReferenceQuery.length) { + fetchReferences(exceptionListsFormattedForReferenceQuery); } - }, [exceptionListsToQuery, fetchReferences]); + }, [exceptionListsFormattedForReferenceQuery, fetchReferences]); useEffect(() => { if (isFetchReferencesError) { @@ -241,6 +255,7 @@ const ExceptionsViewerComponent = ({ async (options?: GetExceptionItemProps) => { try { const { pageIndex, itemsPerPage, total, data } = await handleFetchItems(options); + setViewerState(total > 0 ? null : 'empty'); setExceptions({ exceptions: data, @@ -306,15 +321,26 @@ const ExceptionsViewerComponent = ({ [setFlyoutType] ); - const handleCancelExceptionItemFlyout = useCallback((): void => { - setFlyoutType(null); - handleGetExceptionListItems(); - }, [setFlyoutType, handleGetExceptionListItems]); + const handleCancelExceptionItemFlyout = useCallback( + (didRuleChange: boolean): void => { + setFlyoutType(null); + if (didRuleChange && onRuleChange != null) { + onRuleChange(); + } + }, + [onRuleChange, setFlyoutType] + ); - const handleConfirmExceptionFlyout = useCallback((): void => { - setFlyoutType(null); - handleGetExceptionListItems(); - }, [setFlyoutType, handleGetExceptionListItems]); + const handleConfirmExceptionFlyout = useCallback( + (didRuleChange: boolean): void => { + setFlyoutType(null); + if (didRuleChange && onRuleChange != null) { + onRuleChange(); + } + handleGetExceptionListItems(); + }, + [setFlyoutType, handleGetExceptionListItems, onRuleChange] + ); const handleDeleteException = useCallback( async ({ id: itemId, name, namespaceType }: ExceptionListItemIdentifiers) => { @@ -360,49 +386,53 @@ const ExceptionsViewerComponent = ({ } }, [exceptionListsToQuery.length, handleGetExceptionListItems, setViewerState]); + const exceptionToEditList = useMemo( + (): ExceptionListSchema | null => + allReferences != null && exceptionToEdit != null + ? (allReferences[exceptionToEdit.list_id] as ExceptionListSchema) + : null, + [allReferences, exceptionToEdit] + ); + return ( <> - {currenFlyout === 'editException' && exceptionToEdit != null && rule != null && ( - - )} + {currenFlyout === 'editException' && + exceptionToEditList != null && + exceptionToEdit != null && + rule != null && ( + + )} {currenFlyout === 'addException' && rule != null && ( )} <> - {listType === ExceptionListTypeEnum.ENDPOINT - ? i18n.ENDPOINT_EXCEPTIONS_TAB_ABOUT - : i18n.EXCEPTIONS_TAB_ABOUT} + {isEndpointSpecified ? i18n.ENDPOINT_EXCEPTIONS_TAB_ABOUT : i18n.EXCEPTIONS_TAB_ABOUT} {!STATES_SEARCH_HIDDEN.includes(viewerState) && ( { it('it does not display add exception button if user is read only', () => { const wrapper = mount( { const wrapper = mount( { expect(wrapper.find('[data-test-subj="exceptionsHeaderAddExceptionBtn"]').at(0).text()).toEqual( 'Add rule exception' ); - expect(mockOnAddExceptionClick).toHaveBeenCalledWith('detection'); + expect(mockOnAddExceptionClick).toHaveBeenCalled(); }); it('it invokes "onAddExceptionClick" when user selects to add an endpoint exception item', () => { @@ -52,7 +50,7 @@ describe('ExceptionsViewerSearchBar', () => { const wrapper = mount( { expect(wrapper.find('[data-test-subj="exceptionsHeaderAddExceptionBtn"]').at(0).text()).toEqual( 'Add endpoint exception' ); - expect(mockOnAddExceptionClick).toHaveBeenCalledWith('endpoint'); + expect(mockOnAddExceptionClick).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/search_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/search_bar.tsx index ec85567baef42..36dac931265c2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/search_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/search_bar.tsx @@ -8,8 +8,6 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiSearchBar } from '@elastic/eui'; -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import * as sharedI18n from '../../utils/translations'; import * as i18n from './translations'; import type { GetExceptionItemProps } from '.'; @@ -47,10 +45,10 @@ interface ExceptionsViewerSearchBarProps { canAddException: boolean; // Exception list type used to determine what type of item is // being created when "onAddExceptionClick" is invoked - listType: ExceptionListTypeEnum; + isEndpoint: boolean; isSearching: boolean; onSearch: (arg: GetExceptionItemProps) => void; - onAddExceptionClick: (type: ExceptionListTypeEnum) => void; + onAddExceptionClick: () => void; } /** @@ -58,7 +56,7 @@ interface ExceptionsViewerSearchBarProps { */ const ExceptionsViewerSearchBarComponent = ({ canAddException, - listType, + isEndpoint, isSearching, onSearch, onAddExceptionClick, @@ -71,14 +69,12 @@ const ExceptionsViewerSearchBarComponent = ({ ); const handleAddException = useCallback(() => { - onAddExceptionClick(listType); - }, [onAddExceptionClick, listType]); + onAddExceptionClick(); + }, [onAddExceptionClick]); const addExceptionButtonText = useMemo(() => { - return listType === ExceptionListTypeEnum.ENDPOINT - ? sharedI18n.ADD_TO_ENDPOINT_LIST - : sharedI18n.ADD_TO_DETECTIONS_LIST; - }, [listType]); + return isEndpoint ? i18n.ADD_TO_ENDPOINT_LIST : i18n.ADD_TO_DETECTIONS_LIST; + }, [isEndpoint]); return ( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/translations.ts index 221143a1e0b64..6e50d5d28fe3e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/translations.ts @@ -8,63 +8,63 @@ import { i18n } from '@kbn/i18n'; export const EXCEPTION_NO_SEARCH_RESULTS_PROMPT_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.noSearchResultsPromptTitle', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.noSearchResultsPromptTitle', { defaultMessage: 'No results match your search criteria', } ); export const EXCEPTION_NO_SEARCH_RESULTS_PROMPT_BODY = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.noSearchResultsPromptBody', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.noSearchResultsPromptBody', { defaultMessage: 'Try modifying your search.', } ); export const EXCEPTION_EMPTY_PROMPT_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.addExceptionsEmptyPromptTitle', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.addExceptionsEmptyPromptTitle', { defaultMessage: 'Add exceptions to this rule', } ); export const EXCEPTION_EMPTY_PROMPT_BODY = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.emptyPromptBody', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.emptyPromptBody', { defaultMessage: 'There are no exceptions for this rule. Create your first rule exception.', } ); export const EXCEPTION_EMPTY_ENDPOINT_PROMPT_BODY = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.endpoint.emptyPromptBody', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.endpoint.emptyPromptBody', { defaultMessage: 'There are no endpoint exceptions. Create your first endpoint exception.', } ); export const EXCEPTION_EMPTY_PROMPT_BUTTON = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.emptyPromptButtonLabel', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.emptyPromptButtonLabel', { defaultMessage: 'Add rule exception', } ); export const EXCEPTION_EMPTY_PROMPT_ENDPOINT_BUTTON = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.endpoint.emptyPromptButtonLabel', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.endpoint.emptyPromptButtonLabel', { defaultMessage: 'Add endpoint exception', } ); export const EXCEPTION_ERROR_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.exceptionItemsFetchError', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionItemsFetchError', { defaultMessage: 'Unable to load exception items', } ); export const EXCEPTION_ERROR_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.exceptionItemsFetchErrorDescription', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionItemsFetchErrorDescription', { defaultMessage: 'There was an error loading the exception items. Contact your administrator for help.', @@ -72,48 +72,51 @@ export const EXCEPTION_ERROR_DESCRIPTION = i18n.translate( ); export const EXCEPTION_SEARCH_ERROR_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.exceptionItemSearchErrorTitle', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionItemSearchErrorTitle', { defaultMessage: 'Error searching', } ); export const EXCEPTION_SEARCH_ERROR_BODY = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.exceptionItemSearchErrorBody', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionItemSearchErrorBody', { defaultMessage: 'An error occurred searching for exception items. Please try again.', } ); export const EXCEPTION_DELETE_ERROR_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.exceptionDeleteErrorTitle', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionDeleteErrorTitle', { defaultMessage: 'Error deleting exception item', } ); export const EXCEPTION_ITEMS_PAGINATION_ARIA_LABEL = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.paginationAriaLabel', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.paginationAriaLabel', { defaultMessage: 'Exception item table pagination', } ); export const EXCEPTION_ITEM_DELETE_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.allItems.exceptionItemDeleteSuccessTitle', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionItemDeleteSuccessTitle', { defaultMessage: 'Exception deleted', } ); export const EXCEPTION_ITEM_DELETE_TEXT = (itemName: string) => - i18n.translate('xpack.securitySolution.exceptions.allItems.exceptionItemDeleteSuccessText', { - values: { itemName }, - defaultMessage: '"{itemName}" deleted successfully.', - }); + i18n.translate( + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionItemDeleteSuccessText', + { + values: { itemName }, + defaultMessage: '"{itemName}" deleted successfully.', + } + ); export const ENDPOINT_EXCEPTIONS_TAB_ABOUT = i18n.translate( - 'xpack.securitySolution.exceptions.allExceptionItems.exceptionEndpointDetailsDescription', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionEndpointDetailsDescription', { defaultMessage: 'Endpoint exceptions are added to both the detection rule and the Elastic Endpoint agent on your hosts.', @@ -121,15 +124,29 @@ export const ENDPOINT_EXCEPTIONS_TAB_ABOUT = i18n.translate( ); export const EXCEPTIONS_TAB_ABOUT = i18n.translate( - 'xpack.securitySolution.exceptions.allExceptionItems.exceptionDetectionDetailsDescription', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.exceptionDetectionDetailsDescription', { defaultMessage: 'Rule exceptions are added to the detection rule.', } ); export const SEARCH_PLACEHOLDER = i18n.translate( - 'xpack.securitySolution.exceptions.allExceptionItems.searchPlaceholder', + 'xpack.securitySolution.ruleExceptions.allExceptionItems.searchPlaceholder', { defaultMessage: 'Filter exceptions using simple query syntax, for example, name:"my list"', } ); + +export const ADD_TO_ENDPOINT_LIST = i18n.translate( + 'xpack.securitySolution.ruleExceptions.allExceptionItems.addToEndpointListLabel', + { + defaultMessage: 'Add endpoint exception', + } +); + +export const ADD_TO_DETECTIONS_LIST = i18n.translate( + 'xpack.securitySolution.ruleExceptions.allExceptionItems.addToDetectionsListLabel', + { + defaultMessage: 'Add rule exception', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/utility_bar.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/utility_bar.test.tsx index aa604dbfbf001..d9fe0218311c5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/utility_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/utility_bar.test.tsx @@ -6,14 +6,14 @@ */ import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { mount } from 'enzyme'; import { ExceptionsViewerUtility } from './utility_bar'; import { TestProviders } from '../../../../common/mock'; describe('ExceptionsViewerUtility', () => { it('it renders correct item counts', () => { - const wrapper = mountWithIntl( + const wrapper = mount( { }); it('it renders last updated message', () => { - const wrapper = mountWithIntl( + const wrapper = mount( >; const mockUseSignalIndex = useSignalIndex as jest.Mock>>; -const mockUseAddOrUpdateException = useAddOrUpdateException as jest.Mock< - ReturnType ->; const mockUseFetchIndex = useFetchIndex as jest.Mock; const mockUseCurrentUser = useCurrentUser as jest.Mock>>; -const mockUseRuleAsync = useRuleAsync as jest.Mock; +const mockFetchIndexPatterns = useFetchIndexPatterns as jest.Mock< + ReturnType +>; +const mockUseAddOrUpdateException = useCreateOrUpdateException as jest.Mock< + ReturnType +>; +const mockUseFindExceptionListReferences = useFindExceptionListReferences as jest.Mock; describe('When the edit exception modal is opened', () => { - const ruleName = 'test rule'; - beforeEach(() => { const emptyComp = ; mockGetExceptionBuilderComponentLazy.mockReturnValue(emptyComp); @@ -66,19 +76,42 @@ describe('When the edit exception modal is opened', () => { loading: false, signalIndexName: 'test-signal', }); - mockUseAddOrUpdateException.mockImplementation(() => [{ isLoading: false }, jest.fn()]); + mockUseAddOrUpdateException.mockImplementation(() => [false, jest.fn()]); mockUseFetchIndex.mockImplementation(() => [ false, { indexPatterns: createStubIndexPattern({ spec: { id: '1234', - title: 'logstash-*', + title: 'filebeat-*', fields: { - response: { - name: 'response', - type: 'number', - esTypes: ['integer'], + 'event.code': { + name: 'event.code', + type: 'string', + aggregatable: true, + searchable: true, + }, + 'file.path.caseless': { + name: 'file.path.caseless', + type: 'string', + aggregatable: true, + searchable: true, + }, + subject_name: { + name: 'subject_name', + type: 'string', + aggregatable: true, + searchable: true, + }, + trusted: { + name: 'trusted', + type: 'string', + aggregatable: true, + searchable: true, + }, + 'file.hash.sha256': { + name: 'file.hash.sha256', + type: 'string', aggregatable: true, searchable: true, }, @@ -88,9 +121,40 @@ describe('When the edit exception modal is opened', () => { }, ]); mockUseCurrentUser.mockReturnValue({ username: 'test-username' }); - mockUseRuleAsync.mockImplementation(() => ({ - rule: getRulesSchemaMock(), + mockFetchIndexPatterns.mockImplementation(() => ({ + isLoading: false, + indexPatterns: stubIndexPattern, })); + mockUseFindExceptionListReferences.mockImplementation(() => [ + false, + false, + { + my_list_id: { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my_list_id', + namespace_type: 'single', + type: ExceptionListTypeEnum.DETECTION, + name: 'My exception list', + referenced_rules: [ + { + id: '345', + name: 'My rule', + rule_id: 'my_rule_id', + exception_lists: [ + { + id: '1234', + list_id: 'my_list_id', + namespace_type: 'single', + type: ExceptionListTypeEnum.DETECTION, + }, + ], + }, + ], + }, + }, + jest.fn(), + ]); }); afterEach(() => { @@ -100,24 +164,22 @@ describe('When the edit exception modal is opened', () => { describe('when the modal is loading', () => { it('renders the loading spinner', async () => { - mockUseFetchIndex.mockImplementation(() => [ - true, - { - indexPatterns: stubIndexPattern, - }, - ]); + // Mocks one of the hooks as loading + mockFetchIndexPatterns.mockImplementation(() => ({ + isLoading: true, + indexPatterns: { fields: [], title: 'foo' }, + })); + const wrapper = mount( - + - + ); await waitFor(() => { expect(wrapper.find('[data-test-subj="loadingEditExceptionFlyout"]').exists()).toBeTruthy(); @@ -125,69 +187,198 @@ describe('When the edit exception modal is opened', () => { }); }); - describe('when an endpoint exception with exception data is passed', () => { - describe('when exception entry fields are included in the index pattern', () => { + describe('exception list type of "endpoint"', () => { + mockUseFindExceptionListReferences.mockImplementation(() => [ + false, + false, + { + endpoint_list: { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'endpoint_list', + namespace_type: 'agnostic', + type: ExceptionListTypeEnum.ENDPOINT, + name: 'My exception list', + referenced_rules: [ + { + id: '345', + name: 'My rule', + rule_id: 'my_rule_id', + exception_lists: [ + { + id: 'endpoint_list', + list_id: 'endpoint_list', + namespace_type: 'single', + type: ExceptionListTypeEnum.ENDPOINT, + }, + ], + }, + ], + }, + }, + jest.fn(), + ]); + + describe('common functionality to test', () => { + let wrapper: ReactWrapper; + beforeEach(async () => { + wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) + ); + }); + + it('displays proper flyout and button text', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutTitle"]').at(1).text()).toEqual( + i18n.EDIT_ENDPOINT_EXCEPTION_TITLE + ); + expect(wrapper.find('[data-test-subj="editExceptionConfirmButton"]').at(1).text()).toEqual( + i18n.EDIT_ENDPOINT_EXCEPTION_TITLE + ); + }); + + it('should render item name input', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutNameInput"]').exists()).toBeTruthy(); + }); + + it('should render OS info', () => { + expect(wrapper.find('[data-test-subj="exceptionItemSelectedOs"]').exists()).toBeTruthy(); + }); + + it('should render the exception builder', () => { + expect(wrapper.find('ExceptionsConditions').exists()).toBeTruthy(); + }); + + it('does NOT render section showing list or rule item assigned to', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemLinkedToListSection"]').exists() + ).toBeFalsy(); + expect( + wrapper.find('[data-test-subj="exceptionItemLinkedToRuleSection"]').exists() + ).toBeFalsy(); + }); + + it('should contain the endpoint specific documentation text', () => { + expect(wrapper.find('[data-test-subj="addExceptionEndpointText"]').exists()).toBeTruthy(); + }); + + it('should NOT display the eql sequence callout', () => { + expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).not.toBeTruthy(); + }); + }); + + describe('when exception entry fields and index allow user to bulk close', () => { let wrapper: ReactWrapper; beforeEach(async () => { const exceptionItemMock = { ...getExceptionListItemSchemaMock(), entries: [ - { field: 'response', operator: 'included', type: 'match', value: '3' }, + { field: 'file.hash.sha256', operator: 'included', type: 'match' }, ] as EntriesArray, }; wrapper = mount( ); const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; - await waitFor(() => { - callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }); - }); - }); - it('has the edit exception button enabled', () => { - expect( - wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) + ); }); + it('should have the bulk close checkbox enabled', () => { expect( - wrapper - .find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]') - .getDOMNode() + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() ).not.toBeDisabled(); }); - it('renders the exceptions builder', () => { - expect(wrapper.find('[data-test-subj="edit-exception-builder"]').exists()).toBeTruthy(); - }); - it('should contain the endpoint specific documentation text', () => { - expect( - wrapper.find('[data-test-subj="edit-exception-endpoint-text"]').exists() - ).toBeTruthy(); - }); }); - describe("when exception entry fields aren't included in the index pattern", () => { + describe('when entry has non ecs type', () => { let wrapper: ReactWrapper; beforeEach(async () => { wrapper = mount( ); @@ -196,182 +387,310 @@ describe('When the edit exception modal is opened', () => { callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }); }); }); - it('has the edit exception button enabled', () => { - expect( - wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); - }); + it('should have the bulk close checkbox disabled', () => { expect( - wrapper - .find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]') - .getDOMNode() + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() ).toBeDisabled(); }); - it('renders the exceptions builder', () => { - expect(wrapper.find('[data-test-subj="edit-exception-builder"]').exists()).toBeTruthy(); - }); - it('should contain the endpoint specific documentation text', () => { - expect( - wrapper.find('[data-test-subj="edit-exception-endpoint-text"]').exists() - ).toBeTruthy(); - }); }); }); - describe('when an exception assigned to a sequence eql rule type is passed', () => { + describe('exception list type of "detection"', () => { let wrapper: ReactWrapper; beforeEach(async () => { - (useRuleAsync as jest.Mock).mockImplementation(() => ({ - rule: { - ...getRulesEqlSchemaMock(), - query: - 'sequence [process where process.name = "test.exe"] [process where process.name = "explorer.exe"]', - }, - })); wrapper = mount( - + - + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) ); - const callProps = (getExceptionBuilderComponentLazy as jest.Mock).mock.calls[0][0]; - await waitFor(() => { - callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }); - }); }); - it('has the edit exception button enabled', () => { - expect( - wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); + + it('displays proper flyout and button text', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutTitle"]').at(1).text()).toEqual( + i18n.EDIT_EXCEPTION_TITLE + ); + expect(wrapper.find('[data-test-subj="editExceptionConfirmButton"]').at(1).text()).toEqual( + i18n.EDIT_EXCEPTION_TITLE + ); }); - it('renders the exceptions builder', () => { - expect(wrapper.find('[data-test-subj="edit-exception-builder"]').exists()).toBeTruthy(); + + it('should render item name input', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutNameInput"]').exists()).toBeTruthy(); }); - it('should not contain the endpoint specific documentation text', () => { - expect(wrapper.find('[data-test-subj="edit-exception-endpoint-text"]').exists()).toBeFalsy(); + + it('should not render OS info', () => { + expect(wrapper.find('[data-test-subj="exceptionItemSelectedOs"]').exists()).toBeFalsy(); }); - it('should have the bulk close checkbox disabled', () => { + + it('should render the exception builder', () => { + expect(wrapper.find('ExceptionsConditions').exists()).toBeTruthy(); + }); + + it('does render section showing list item is assigned to', () => { expect( - wrapper - .find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]') - .getDOMNode() - ).toBeDisabled(); + wrapper.find('[data-test-subj="exceptionItemLinkedToListSection"]').exists() + ).toBeTruthy(); }); - it('should display the eql sequence callout', () => { - expect(wrapper.find('[data-test-subj="eql-sequence-callout"]').exists()).toBeTruthy(); + + it('does NOT render section showing rule item is assigned to', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemLinkedToRuleSection"]').exists() + ).toBeFalsy(); + }); + + it('should NOT contain the endpoint specific documentation text', () => { + expect(wrapper.find('[data-test-subj="addExceptionEndpointText"]').exists()).toBeFalsy(); + }); + + it('should NOT display the eql sequence callout', () => { + expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).toBeFalsy(); }); }); - describe('when a detection exception with entries is passed', () => { + describe('exception list type of "rule_default"', () => { + mockUseFindExceptionListReferences.mockImplementation(() => [ + false, + false, + { + my_list_id: { + ...getExceptionListSchemaMock(), + id: '123', + list_id: 'my_list_id', + namespace_type: 'single', + type: ExceptionListTypeEnum.RULE_DEFAULT, + name: 'My exception list', + referenced_rules: [ + { + id: '345', + name: 'My rule', + rule_id: 'my_rule_id', + exception_lists: [ + { + id: '1234', + list_id: 'my_list_id', + namespace_type: 'single', + type: ExceptionListTypeEnum.RULE_DEFAULT, + }, + ], + }, + ], + }, + }, + jest.fn(), + ]); + let wrapper: ReactWrapper; beforeEach(async () => { wrapper = mount( - + - + ); const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; - await waitFor(() => { - callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }); - }); + await waitFor(() => + callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }) + ); }); - it('has the edit exception button enabled', () => { - expect( - wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode() - ).not.toBeDisabled(); + + it('displays proper flyout and button text', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutTitle"]').at(1).text()).toEqual( + i18n.EDIT_EXCEPTION_TITLE + ); + expect(wrapper.find('[data-test-subj="editExceptionConfirmButton"]').at(1).text()).toEqual( + i18n.EDIT_EXCEPTION_TITLE + ); }); - it('renders the exceptions builder', () => { - expect(wrapper.find('[data-test-subj="edit-exception-builder"]').exists()).toBeTruthy(); + + it('should render item name input', () => { + expect(wrapper.find('[data-test-subj="exceptionFlyoutNameInput"]').exists()).toBeTruthy(); }); - it('should not contain the endpoint specific documentation text', () => { - expect(wrapper.find('[data-test-subj="edit-exception-endpoint-text"]').exists()).toBeFalsy(); + + it('should not render OS info', () => { + expect(wrapper.find('[data-test-subj="exceptionItemSelectedOs"]').exists()).toBeFalsy(); }); - it('should have the bulk close checkbox disabled', () => { + + it('should render the exception builder', () => { + expect(wrapper.find('ExceptionsConditions').exists()).toBeTruthy(); + }); + + it('does NOT render section showing list item is assigned to', () => { expect( - wrapper - .find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]') - .getDOMNode() - ).toBeDisabled(); + wrapper.find('[data-test-subj="exceptionItemLinkedToListSection"]').exists() + ).toBeFalsy(); + }); + + it('does render section showing rule item is assigned to', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemLinkedToRuleSection"]').exists() + ).toBeTruthy(); }); - it('should not display the eql sequence callout', () => { - expect(wrapper.find('[data-test-subj="eql-sequence-callout"]').exists()).not.toBeTruthy(); + + it('should NOT contain the endpoint specific documentation text', () => { + expect(wrapper.find('[data-test-subj="addExceptionEndpointText"]').exists()).toBeFalsy(); + }); + + it('should NOT display the eql sequence callout', () => { + expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).toBeFalsy(); }); }); - describe('when an exception with no entries is passed', () => { + describe('when an exception assigned to a sequence eql rule type is passed', () => { let wrapper: ReactWrapper; beforeEach(async () => { - const exceptionItemMock = { ...getExceptionListItemSchemaMock(), entries: [] }; wrapper = mount( - + - + ); - const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + const callProps = (getExceptionBuilderComponentLazy as jest.Mock).mock.calls[0][0]; await waitFor(() => { callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }); }); }); - it('has the edit exception button disabled', () => { + + it('should have the bulk close checkbox disabled', () => { expect( - wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode() + wrapper.find('input[data-test-subj="bulkCloseAlertOnAddExceptionCheckbox"]').getDOMNode() ).toBeDisabled(); }); - it('renders the exceptions builder', () => { - expect(wrapper.find('[data-test-subj="edit-exception-builder"]').exists()).toBeTruthy(); + + it('should display the eql sequence callout', () => { + expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).toBeTruthy(); }); - it('should have the bulk close checkbox disabled', () => { + }); + + describe('error states', () => { + test('when there are exception builder errors has submit button disabled', async () => { + const wrapper = mount( + + + + ); + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => callProps.onChange({ exceptionItems: [], errorExists: true })); + expect( - wrapper - .find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]') - .getDOMNode() + wrapper.find('button[data-test-subj="editExceptionConfirmButton"]').getDOMNode() ).toBeDisabled(); }); }); - - test('when there are exception builder errors has the add exception button disabled', async () => { - const wrapper = mount( - - - - ); - const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; - await waitFor(() => callProps.onChange({ exceptionItems: [], errorExists: true })); - - expect( - wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode() - ).toBeDisabled(); - }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx index 85a59f06281f1..6b85b4bf7302f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx @@ -5,75 +5,65 @@ * 2.0. */ -// Component being re-implemented in 8.5 - -/* eslint-disable complexity */ - -import React, { memo, useState, useCallback, useEffect, useMemo } from 'react'; +import { isEmpty } from 'lodash/fp'; +import React, { useCallback, useEffect, useMemo, useReducer } from 'react'; import styled, { css } from 'styled-components'; import { EuiButton, EuiButtonEmpty, EuiHorizontalRule, - EuiCheckbox, EuiSpacer, - EuiFormRow, - EuiText, - EuiCallOut, EuiFlyoutHeader, EuiFlyoutBody, EuiFlexGroup, EuiTitle, EuiFlyout, EuiFlyoutFooter, + EuiLoadingContent, } from '@elastic/eui'; import type { - ExceptionListType, - OsTypeArray, - OsType, ExceptionListItemSchema, - CreateExceptionListItemSchema, + ExceptionListSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { + ExceptionListTypeEnum, + exceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { getExceptionBuilderComponentLazy } from '@kbn/lists-plugin/public'; -import type { DataViewBase } from '@kbn/es-query'; import type { ExceptionsBuilderReturnExceptionItem } from '@kbn/securitysolution-list-utils'; -import { useRuleIndices } from '../../../../detections/containers/detection_engine/rules/use_rule_indices'; -import { hasEqlSequenceQuery, isEqlRule } from '../../../../../common/detection_engine/utils'; -import { useFetchIndex } from '../../../../common/containers/source'; -import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index'; -import { useRuleAsync } from '../../../../detections/containers/detection_engine/rules/use_rule_async'; -import * as i18n from './translations'; -import * as sharedI18n from '../../utils/translations'; -import { useKibana } from '../../../../common/lib/kibana'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { useAddOrUpdateException } from '../../logic/use_add_exception'; -import { ExceptionItemComments } from '../item_comments'; import { - enrichExistingExceptionItemWithComments, - enrichExceptionItemsWithOS, - entryHasListType, - entryHasNonEcsType, - lowercaseHashValues, - filterIndexPatterns, -} from '../../utils/helpers'; -import { Loader } from '../../../../common/components/loader'; -import type { ErrorInfo } from '../error_callout'; -import { ErrorCallout } from '../error_callout'; -import { ruleTypesThatAllowLargeValueLists } from '../../utils/constants'; + isEqlRule, + isNewTermsRule, + isThresholdRule, +} from '../../../../../common/detection_engine/utils'; + +import type { Rule } from '../../../rule_management/logic/types'; +import { ExceptionsFlyoutMeta } from '../flyout_components/item_meta_form'; +import { ExceptionsLinkedToLists } from '../flyout_components/linked_to_list'; +import { ExceptionsLinkedToRule } from '../flyout_components/linked_to_rule'; +import { ExceptionItemsFlyoutAlertsActions } from '../flyout_components/alerts_actions'; +import { ExceptionsConditions } from '../flyout_components/item_conditions'; + +import { filterIndexPatterns } from '../../utils/helpers'; +import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data'; +import { useCloseAlertsFromExceptions } from '../../logic/use_close_alerts'; +import { useFindExceptionListReferences } from '../../logic/use_find_references'; +import { entrichExceptionItemsForUpdate } from '../flyout_components/utils'; +import { ExceptionItemComments } from '../item_comments'; +import { createExceptionItemsReducer } from './reducer'; +import { useEditExceptionItems } from './use_edit_exception'; + +import * as i18n from './translations'; interface EditExceptionFlyoutProps { - ruleName: string; - ruleId: string; - ruleIndices: string[]; - dataViewId?: string; - exceptionItem: ExceptionListItemSchema; - exceptionListType: ExceptionListType; - onCancel: () => void; - onConfirm: () => void; - onRuleChange?: () => void; + list: ExceptionListSchema; + itemToEdit: ExceptionListItemSchema; + showAlertCloseOptions: boolean; + rule?: Rule; + onCancel: (arg: boolean) => void; + onConfirm: (arg: boolean) => void; } const FlyoutHeader = styled(EuiFlyoutHeader)` @@ -82,412 +72,335 @@ const FlyoutHeader = styled(EuiFlyoutHeader)` `} `; -const FlyoutSubtitle = styled.div` - ${({ theme }) => css` - color: ${theme.eui.euiColorMediumShade}; +const FlyoutBodySection = styled(EuiFlyoutBody)` + ${() => css` + &.builder-section { + overflow-y: scroll; + } `} `; -const FlyoutBodySection = styled.section` +const FlyoutFooterGroup = styled(EuiFlexGroup)` ${({ theme }) => css` - padding: ${theme.eui.euiSizeS} ${theme.eui.euiSizeL}; + padding: ${theme.eui.euiSizeS}; `} `; -const FlyoutCheckboxesSection = styled.section` - overflow-y: inherit; - height: auto; - .euiFlyoutBody__overflowContent { - padding-top: 0; - } -`; - -const FlyoutFooterGroup = styled(EuiFlexGroup)` - ${({ theme }) => css` - padding: ${theme.eui.euiSizeS}; +const SectionHeader = styled(EuiTitle)` + ${() => css` + font-weight: ${({ theme }) => theme.eui.euiFontWeightSemiBold}; `} `; -export const EditExceptionFlyout = memo(function EditExceptionFlyout({ - ruleName, - ruleId, - ruleIndices, - dataViewId, - exceptionItem, - exceptionListType, +const EditExceptionFlyoutComponent: React.FC = ({ + list, + itemToEdit, + rule, + showAlertCloseOptions, onCancel, onConfirm, - onRuleChange, -}: EditExceptionFlyoutProps) { - const { http, unifiedSearch, data } = useKibana().services; - const [comment, setComment] = useState(''); - const [errorsExist, setErrorExists] = useState(false); - const { rule: maybeRule, loading: isRuleLoading } = useRuleAsync(ruleId); - const [updateError, setUpdateError] = useState(null); - const [hasVersionConflict, setHasVersionConflict] = useState(false); - const [shouldBulkCloseAlert, setShouldBulkCloseAlert] = useState(false); - const [shouldDisableBulkClose, setShouldDisableBulkClose] = useState(false); - const [exceptionItemsToAdd, setExceptionItemsToAdd] = useState< - ExceptionsBuilderReturnExceptionItem[] - >([]); - const { addError, addSuccess } = useAppToasts(); - const { loading: isSignalIndexLoading, signalIndexName } = useSignalIndex(); - const memoSignalIndexName = useMemo( - () => (signalIndexName !== null ? [signalIndexName] : []), - [signalIndexName] - ); - const [isSignalIndexPatternLoading, { indexPatterns: signalIndexPatterns }] = - useFetchIndex(memoSignalIndexName); +}): JSX.Element => { + const selectedOs = useMemo(() => itemToEdit.os_types, [itemToEdit]); + const rules = useMemo(() => (rule != null ? [rule] : null), [rule]); + const listType = useMemo((): ExceptionListTypeEnum => list.type as ExceptionListTypeEnum, [list]); - const { mlJobLoading, ruleIndices: memoRuleIndices } = useRuleIndices( - maybeRule?.machine_learning_job_id, - ruleIndices - ); + const { isLoading, indexPatterns } = useFetchIndexPatterns(rules); + const [isSubmitting, submitEditExceptionItems] = useEditExceptionItems(); + const [isClosingAlerts, closeAlerts] = useCloseAlertsFromExceptions(); - const hasDataViewId = dataViewId || maybeRule?.data_view_id || null; - const [dataViewIndexPatterns, setDataViewIndexPatterns] = useState(null); - - useEffect(() => { - const fetchSingleDataView = async () => { - if (hasDataViewId) { - const dv = await data.dataViews.get(hasDataViewId); - setDataViewIndexPatterns(dv); - } - }; - - fetchSingleDataView(); - }, [hasDataViewId, data.dataViews, setDataViewIndexPatterns]); + const [ + { + exceptionItems, + exceptionItemMeta: { name: exceptionItemName }, + newComment, + bulkCloseAlerts, + disableBulkClose, + bulkCloseIndex, + entryErrorExists, + }, + dispatch, + ] = useReducer(createExceptionItemsReducer(), { + exceptionItems: [itemToEdit], + exceptionItemMeta: { name: itemToEdit.name }, + newComment: '', + bulkCloseAlerts: false, + disableBulkClose: true, + bulkCloseIndex: undefined, + entryErrorExists: false, + }); + + const allowLargeValueLists = useMemo((): boolean => { + if (rule != null) { + // We'll only block this when we know what rule we're dealing with. + // When editing an item outside the context of a specific rule, + // we won't block but should communicate to the user that large value lists + // won't be applied to all rule types. + return !isEqlRule(rule.type) && !isThresholdRule(rule.type) && !isNewTermsRule(rule.type); + } else { + return true; + } + }, [rule]); - // Don't fetch indices if rule has data view id (currently rule can technically have - // both defined and in that case we'd be doing unnecessary work here if all we want is - // the data view fields) - const [isIndexPatternLoading, { indexPatterns: indexIndexPatterns }] = useFetchIndex( - hasDataViewId ? [] : memoRuleIndices - ); + const [isLoadingReferences, referenceFetchError, ruleReferences, fetchReferences] = + useFindExceptionListReferences(); - const indexPattern = useMemo( - (): DataViewBase | null => (hasDataViewId ? dataViewIndexPatterns : indexIndexPatterns), - [hasDataViewId, dataViewIndexPatterns, indexIndexPatterns] - ); - - const handleExceptionUpdateError = useCallback( - (error: Error, statusCode: number | null, message: string | null) => { - if (error.message.includes('Conflict')) { - setHasVersionConflict(true); - } else { - setUpdateError({ - reason: error.message, - code: statusCode, - details: message, - listListId: exceptionItem.list_id, - }); - } + useEffect(() => { + if (fetchReferences != null) { + fetchReferences([ + { + id: list.id, + listId: list.list_id, + namespaceType: list.namespace_type, + }, + ]); + } + }, [list, fetchReferences]); + + /** + * Reducer action dispatchers + * */ + const setExceptionItemsToAdd = useCallback( + (items: ExceptionsBuilderReturnExceptionItem[]): void => { + dispatch({ + type: 'setExceptionItems', + items, + }); }, - [setUpdateError, setHasVersionConflict, exceptionItem.list_id] + [dispatch] ); - const handleDissasociationSuccess = useCallback( - (id: string): void => { - addSuccess(sharedI18n.DISSASOCIATE_LIST_SUCCESS(id)); - - if (onRuleChange) { - onRuleChange(); - } - - onCancel(); + const setExceptionItemMeta = useCallback( + (value: [string, string]): void => { + dispatch({ + type: 'setExceptionItemMeta', + value, + }); }, - [addSuccess, onCancel, onRuleChange] + [dispatch] ); - const handleDissasociationError = useCallback( - (error: Error): void => { - addError(error, { title: sharedI18n.DISSASOCIATE_EXCEPTION_LIST_ERROR }); - onCancel(); + const setComment = useCallback( + (comment: string): void => { + dispatch({ + type: 'setComment', + comment, + }); }, - [addError, onCancel] + [dispatch] ); - const handleExceptionUpdateSuccess = useCallback((): void => { - addSuccess(i18n.EDIT_EXCEPTION_SUCCESS); - onConfirm(); - }, [addSuccess, onConfirm]); - - const [{ isLoading: addExceptionIsLoading }, addOrUpdateExceptionItems] = useAddOrUpdateException( - { - http, - onSuccess: handleExceptionUpdateSuccess, - onError: handleExceptionUpdateError, - } + const setBulkCloseAlerts = useCallback( + (bulkClose: boolean): void => { + dispatch({ + type: 'setBulkCloseAlerts', + bulkClose, + }); + }, + [dispatch] ); - useEffect(() => { - if (isSignalIndexPatternLoading === false && isSignalIndexLoading === false) { - setShouldDisableBulkClose( - entryHasListType(exceptionItemsToAdd) || - entryHasNonEcsType(exceptionItemsToAdd, signalIndexPatterns) || - exceptionItemsToAdd.every((item) => item.entries.length === 0) - ); - } - }, [ - setShouldDisableBulkClose, - exceptionItemsToAdd, - isSignalIndexPatternLoading, - isSignalIndexLoading, - signalIndexPatterns, - ]); - - useEffect(() => { - if (shouldDisableBulkClose === true) { - setShouldBulkCloseAlert(false); - } - }, [shouldDisableBulkClose]); - - const isSubmitButtonDisabled = useMemo( - () => - exceptionItemsToAdd.every((item) => item.entries.length === 0) || - hasVersionConflict || - errorsExist, - [exceptionItemsToAdd, hasVersionConflict, errorsExist] + const setDisableBulkCloseAlerts = useCallback( + (disableBulkCloseAlerts: boolean): void => { + dispatch({ + type: 'setDisableBulkCloseAlerts', + disableBulkCloseAlerts, + }); + }, + [dispatch] ); - const handleBuilderOnChange = useCallback( - ({ - exceptionItems, - errorExists, - }: { - exceptionItems: ExceptionsBuilderReturnExceptionItem[]; - errorExists: boolean; - }) => { - setExceptionItemsToAdd(exceptionItems); - setErrorExists(errorExists); + const setBulkCloseIndex = useCallback( + (index: string[] | undefined): void => { + dispatch({ + type: 'setBulkCloseIndex', + bulkCloseIndex: index, + }); }, - [setExceptionItemsToAdd] + [dispatch] ); - const onCommentChange = useCallback( - (value: string) => { - setComment(value); + const setConditionsValidationError = useCallback( + (errorExists: boolean): void => { + dispatch({ + type: 'setConditionValidationErrorExists', + errorExists, + }); }, - [setComment] + [dispatch] ); - const onBulkCloseAlertCheckboxChange = useCallback( - (event: React.ChangeEvent) => { - setShouldBulkCloseAlert(event.currentTarget.checked); + const handleCloseFlyout = useCallback((): void => { + onCancel(false); + }, [onCancel]); + + const areItemsReadyForUpdate = useCallback( + (items: ExceptionsBuilderReturnExceptionItem[]): items is ExceptionListItemSchema[] => { + return items.every((item) => exceptionListItemSchema.is(item)); }, - [setShouldBulkCloseAlert] + [] ); - const enrichExceptionItems = useCallback(() => { - const [exceptionItemToEdit] = exceptionItemsToAdd; - let enriched: ExceptionsBuilderReturnExceptionItem[] = [ - { - ...enrichExistingExceptionItemWithComments(exceptionItemToEdit, [ - ...exceptionItem.comments, - ...(comment.trim() !== '' ? [{ comment }] : []), - ]), - }, - ]; - if (exceptionListType === 'endpoint') { - enriched = lowercaseHashValues(enrichExceptionItemsWithOS(enriched, exceptionItem.os_types)); - } - return enriched; - }, [exceptionItemsToAdd, exceptionItem, comment, exceptionListType]); - - const onEditExceptionConfirm = useCallback(() => { - if (addOrUpdateExceptionItems !== null) { - const bulkCloseIndex = - shouldBulkCloseAlert && signalIndexName !== null ? [signalIndexName] : undefined; - addOrUpdateExceptionItems( - maybeRule?.rule_id ?? '', - // This is being rewritten in https://github.com/elastic/kibana/pull/140643 - // As of now, flyout cannot yet create item of type CreateRuleExceptionListItemSchema - enrichExceptionItems() as Array, - undefined, - bulkCloseIndex - ); + const handleSubmit = useCallback(async (): Promise => { + if (submitEditExceptionItems == null) return; + + try { + const items = entrichExceptionItemsForUpdate({ + itemName: exceptionItemName, + commentToAdd: newComment, + listType, + selectedOs: itemToEdit.os_types, + items: exceptionItems, + }); + + if (areItemsReadyForUpdate(items)) { + await submitEditExceptionItems({ + itemsToUpdate: items, + }); + + const ruleDefaultRule = rule != null ? [rule.rule_id] : []; + const referencedRules = + ruleReferences != null + ? ruleReferences[list.list_id].referenced_rules.map(({ rule_id: ruleId }) => ruleId) + : []; + const ruleIdsForBulkClose = + listType === ExceptionListTypeEnum.RULE_DEFAULT ? ruleDefaultRule : referencedRules; + + if (closeAlerts != null && !isEmpty(ruleIdsForBulkClose) && bulkCloseAlerts) { + await closeAlerts(ruleIdsForBulkClose, items, undefined, bulkCloseIndex); + } + + onConfirm(true); + } + } catch (e) { + onCancel(false); } }, [ - addOrUpdateExceptionItems, - maybeRule, - enrichExceptionItems, - shouldBulkCloseAlert, - signalIndexName, + submitEditExceptionItems, + exceptionItemName, + newComment, + listType, + itemToEdit.os_types, + exceptionItems, + areItemsReadyForUpdate, + rule, + ruleReferences, + list.list_id, + closeAlerts, + bulkCloseAlerts, + onConfirm, + bulkCloseIndex, + onCancel, ]); - const isRuleEQLSequenceStatement = useMemo((): boolean => { - if (maybeRule != null) { - return isEqlRule(maybeRule.type) && hasEqlSequenceQuery(maybeRule.query); - } - return false; - }, [maybeRule]); - - const osDisplay = (osTypes: OsTypeArray): string => { - const translateOS = (currentOs: OsType): string => { - return currentOs === 'linux' - ? sharedI18n.OPERATING_SYSTEM_LINUX - : currentOs === 'macos' - ? sharedI18n.OPERATING_SYSTEM_MAC - : sharedI18n.OPERATING_SYSTEM_WINDOWS; - }; - return osTypes - .reduce((osString, currentOs) => { - return `${translateOS(currentOs)}, ${osString}`; - }, '') - .slice(0, -2); - }; - - const allowLargeValueLists = useMemo( - () => (maybeRule != null ? ruleTypesThatAllowLargeValueLists.includes(maybeRule.type) : false), - [maybeRule] + const editExceptionMessage = useMemo( + () => + listType === ExceptionListTypeEnum.ENDPOINT + ? i18n.EDIT_ENDPOINT_EXCEPTION_TITLE + : i18n.EDIT_EXCEPTION_TITLE, + [listType] + ); + + const isSubmitButtonDisabled = useMemo( + () => + isSubmitting || + isClosingAlerts || + exceptionItems.every((item) => item.entries.length === 0) || + isLoading || + entryErrorExists, + [isLoading, entryErrorExists, exceptionItems, isSubmitting, isClosingAlerts] ); return ( - + -

    - {exceptionListType === 'endpoint' - ? i18n.EDIT_ENDPOINT_EXCEPTION_TITLE - : i18n.EDIT_EXCEPTION_TITLE} -

    +

    {editExceptionMessage}

    - -
    - {(addExceptionIsLoading || isIndexPatternLoading || isSignalIndexLoading) && ( - - )} - {!isSignalIndexLoading && - indexPattern != null && - !addExceptionIsLoading && - !isIndexPatternLoading && - !isRuleLoading && - !mlJobLoading && ( - - - {isRuleEQLSequenceStatement && ( - <> - - - - )} - {i18n.EXCEPTION_BUILDER_INFO} - - {exceptionListType === 'endpoint' && ( - <> - -
    -
    {sharedI18n.OPERATING_SYSTEM_LABEL}
    -
    {osDisplay(exceptionItem.os_types)}
    -
    -
    - - - )} - {getExceptionBuilderComponentLazy({ - allowLargeValueLists, - httpService: http, - autocompleteService: unifiedSearch.autocomplete, - exceptionListItems: [exceptionItem], - listType: exceptionListType, - listId: exceptionItem.list_id, - listNamespaceType: exceptionItem.namespace_type, - listTypeSpecificIndexPatternFilter: filterIndexPatterns, - ruleName, - isOrDisabled: true, - isAndDisabled: false, - osTypes: exceptionItem.os_types, - isNestedDisabled: false, - dataTestSubj: 'edit-exception-builder', - idAria: 'edit-exception-builder', - onChange: handleBuilderOnChange, - indexPatterns: indexPattern, - })} - - - - -
    + {isLoading && } + + + + + {listType === ExceptionListTypeEnum.DETECTION && ( + <> - - - - - {exceptionListType === 'endpoint' && ( - <> - - - {i18n.ENDPOINT_QUARANTINE_TEXT} - - - )} - -
    + + )} - - - {hasVersionConflict && ( + {listType === ExceptionListTypeEnum.RULE_DEFAULT && rule != null && ( <> - -

    {i18n.VERSION_CONFLICT_ERROR_DESCRIPTION}

    -
    - + + )} - {updateError != null && ( + + +

    {i18n.COMMENTS_SECTION_TITLE(itemToEdit.comments.length ?? 0)}

    + + } + exceptionItemComments={itemToEdit.comments} + newCommentValue={newComment} + newCommentOnChange={setComment} + /> + {showAlertCloseOptions && ( <> - + - )} - {updateError === null && ( - - - {i18n.CANCEL} - - - - {i18n.EDIT_EXCEPTION_SAVE_BUTTON} - - - )} + + + + + {i18n.CANCEL} + + + + {editExceptionMessage} + +
    ); -}); +}; + +export const EditExceptionFlyout = React.memo(EditExceptionFlyoutComponent); + +EditExceptionFlyout.displayName = 'EditExceptionFlyout'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts new file mode 100644 index 0000000000000..22fefe760e4aa --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts @@ -0,0 +1,116 @@ +/* + * 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 { ExceptionsBuilderReturnExceptionItem } from '@kbn/securitysolution-list-utils'; + +export interface State { + exceptionItems: ExceptionsBuilderReturnExceptionItem[]; + exceptionItemMeta: { name: string }; + newComment: string; + bulkCloseAlerts: boolean; + disableBulkClose: boolean; + bulkCloseIndex: string[] | undefined; + entryErrorExists: boolean; +} + +export type Action = + | { + type: 'setExceptionItemMeta'; + value: [string, string]; + } + | { + type: 'setComment'; + comment: string; + } + | { + type: 'setBulkCloseAlerts'; + bulkClose: boolean; + } + | { + type: 'setDisableBulkCloseAlerts'; + disableBulkCloseAlerts: boolean; + } + | { + type: 'setBulkCloseIndex'; + bulkCloseIndex: string[] | undefined; + } + | { + type: 'setExceptionItems'; + items: ExceptionsBuilderReturnExceptionItem[]; + } + | { + type: 'setConditionValidationErrorExists'; + errorExists: boolean; + }; + +export const createExceptionItemsReducer = + () => + (state: State, action: Action): State => { + switch (action.type) { + case 'setExceptionItemMeta': { + const { value } = action; + + return { + ...state, + exceptionItemMeta: { + ...state.exceptionItemMeta, + [value[0]]: value[1], + }, + }; + } + case 'setComment': { + const { comment } = action; + + return { + ...state, + newComment: comment, + }; + } + case 'setBulkCloseAlerts': { + const { bulkClose } = action; + + return { + ...state, + bulkCloseAlerts: bulkClose, + }; + } + case 'setDisableBulkCloseAlerts': { + const { disableBulkCloseAlerts } = action; + + return { + ...state, + disableBulkClose: disableBulkCloseAlerts, + }; + } + case 'setBulkCloseIndex': { + const { bulkCloseIndex } = action; + + return { + ...state, + bulkCloseIndex, + }; + } + case 'setExceptionItems': { + const { items } = action; + + return { + ...state, + exceptionItems: items, + }; + } + case 'setConditionValidationErrorExists': { + const { errorExists } = action; + + return { + ...state, + entryErrorExists: errorExists, + }; + } + default: + return state; + } + }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/translations.ts index 6a5fd6f44810c..9839fa5ddc9de 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/translations.ts @@ -7,87 +7,50 @@ import { i18n } from '@kbn/i18n'; -export const CANCEL = i18n.translate('xpack.securitySolution.exceptions.editException.cancel', { +export const CANCEL = i18n.translate('xpack.securitySolution.ruleExceptions.editException.cancel', { defaultMessage: 'Cancel', }); -export const EDIT_EXCEPTION_SAVE_BUTTON = i18n.translate( - 'xpack.securitySolution.exceptions.editException.editExceptionSaveButton', - { - defaultMessage: 'Save', - } -); - export const EDIT_EXCEPTION_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.editException.editExceptionTitle', + 'xpack.securitySolution.ruleExceptions.editException.editExceptionTitle', { - defaultMessage: 'Edit Rule Exception', + defaultMessage: 'Edit rule exception', } ); export const EDIT_ENDPOINT_EXCEPTION_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.editException.editEndpointExceptionTitle', - { - defaultMessage: 'Edit Endpoint Exception', - } -); - -export const EDIT_EXCEPTION_SUCCESS = i18n.translate( - 'xpack.securitySolution.exceptions.editException.success', - { - defaultMessage: 'Successfully updated exception', - } -); - -export const BULK_CLOSE_LABEL = i18n.translate( - 'xpack.securitySolution.exceptions.editException.bulkCloseLabel', - { - defaultMessage: 'Close all alerts that match this exception and were generated by this rule', - } -); - -export const BULK_CLOSE_LABEL_DISABLED = i18n.translate( - 'xpack.securitySolution.exceptions.editException.bulkCloseLabel.disabled', + 'xpack.securitySolution.ruleExceptions.editException.editEndpointExceptionTitle', { - defaultMessage: - 'Close all alerts that match this exception and were generated by this rule (Lists and non-ECS fields are not supported)', + defaultMessage: 'Edit endpoint exception', } ); -export const ENDPOINT_QUARANTINE_TEXT = i18n.translate( - 'xpack.securitySolution.exceptions.editException.endpointQuarantineText', +export const EDIT_RULE_EXCEPTION_SUCCESS_TITLE = i18n.translate( + 'xpack.securitySolution.ruleExceptions.editException.editRuleExceptionToastSuccessTitle', { - defaultMessage: - 'On all Endpoint hosts, quarantined files that match the exception are automatically restored to their original locations. This exception applies to all rules using Endpoint exceptions.', + defaultMessage: 'Rule exception updated', } ); -export const EXCEPTION_BUILDER_INFO = i18n.translate( - 'xpack.securitySolution.exceptions.editException.infoLabel', - { - defaultMessage: "Alerts are generated when the rule's conditions are met, except when:", - } -); +export const EDIT_RULE_EXCEPTION_SUCCESS_TEXT = (exceptionItemName: string, numItems: number) => + i18n.translate( + 'xpack.securitySolution.ruleExceptions.editException.editRuleExceptionToastSuccessText', + { + values: { exceptionItemName, numItems }, + defaultMessage: + '{numItems, plural, =1 {Exception} other {Exceptions}} - {exceptionItemName} - {numItems, plural, =1 {has} other {have}} been updated.', + } + ); -export const VERSION_CONFLICT_ERROR_TITLE = i18n.translate( - 'xpack.securitySolution.exceptions.editException.versionConflictTitle', +export const EDIT_RULE_EXCEPTION_ERROR_TITLE = i18n.translate( + 'xpack.securitySolution.ruleExceptions.editException.editRuleExceptionToastErrorTitle', { - defaultMessage: 'Sorry, there was an error', + defaultMessage: 'Error updating exception', } ); -export const VERSION_CONFLICT_ERROR_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.exceptions.editException.versionConflictDescription', - { - defaultMessage: - "It appears this exception was updated since you first selected to edit it. Try clicking 'Cancel' and editing the exception again.", - } -); - -export const EDIT_EXCEPTION_SEQUENCE_WARNING = i18n.translate( - 'xpack.securitySolution.exceptions.editException.sequenceWarning', - { - defaultMessage: - "This rule's query contains an EQL sequence statement. The exception modified will apply to all events in the sequence.", - } -); +export const COMMENTS_SECTION_TITLE = (comments: number) => + i18n.translate('xpack.securitySolution.ruleExceptions.editExceptionFlyout.commentsTitle', { + values: { comments }, + defaultMessage: 'Add comments ({comments})', + }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/use_edit_exception.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/use_edit_exception.tsx new file mode 100644 index 0000000000000..e5dd0dc4844dc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/use_edit_exception.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useRef, useState } from 'react'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import * as i18n from './translations'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { useCreateOrUpdateException } from '../../logic/use_create_update_exception'; + +export interface EditExceptionItemHookProps { + itemsToUpdate: ExceptionListItemSchema[]; +} + +export type EditExceptionItemHookFuncProps = (arg: EditExceptionItemHookProps) => Promise; + +export type ReturnUseEditExceptionItems = [boolean, EditExceptionItemHookFuncProps | null]; + +/** + * Hook for editing exception items from flyout + * + */ +export const useEditExceptionItems = (): ReturnUseEditExceptionItems => { + const { addSuccess, addError, addWarning } = useAppToasts(); + const [isAddingExceptions, updateExceptions] = useCreateOrUpdateException(); + + const [isLoading, setIsLoading] = useState(false); + const updateExceptionsRef = useRef(null); + + useEffect(() => { + let isSubscribed = true; + const abortCtrl = new AbortController(); + + const updateExceptionItem = async ({ itemsToUpdate }: EditExceptionItemHookProps) => { + if (updateExceptions == null) return; + + try { + setIsLoading(true); + + await updateExceptions(itemsToUpdate); + + addSuccess({ + title: i18n.EDIT_RULE_EXCEPTION_SUCCESS_TITLE, + text: i18n.EDIT_RULE_EXCEPTION_SUCCESS_TEXT( + itemsToUpdate.map(({ name }) => name).join(', '), + itemsToUpdate.length + ), + }); + + if (isSubscribed) { + setIsLoading(false); + } + } catch (e) { + if (isSubscribed) { + setIsLoading(false); + addError(e, { title: i18n.EDIT_RULE_EXCEPTION_ERROR_TITLE }); + throw new Error(e); + } + } + }; + + updateExceptionsRef.current = updateExceptionItem; + return (): void => { + isSubscribed = false; + abortCtrl.abort(); + }; + }, [addSuccess, addError, addWarning, updateExceptions]); + + return [isLoading || isAddingExceptions, updateExceptionsRef.current]; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.test.tsx index d67e62dcb52dc..782066527d13a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.test.tsx @@ -10,21 +10,19 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import { coreMock } from '@kbn/core/public/mocks'; import { getListMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; -import { useDissasociateExceptionList } from '../../../../detections/containers/detection_engine/rules/use_dissasociate_exception_list'; +import { useDisassociateExceptionList } from '../../../rule_management/logic/use_disassociate_exception_list'; import { ErrorCallout } from '.'; -import { savedRuleMock } from '../../../../detections/containers/detection_engine/rules/mock'; +import { savedRuleMock } from '../../../rule_management/logic/mock'; -jest.mock( - '../../../../detections/containers/detection_engine/rules/use_dissasociate_exception_list' -); +jest.mock('../../../rule_management/logic/use_disassociate_exception_list'); const mockKibanaHttpService = coreMock.createStart().http; describe('ErrorCallout', () => { - const mockDissasociate = jest.fn(); + const mockDisassociate = jest.fn(); beforeEach(() => { - (useDissasociateExceptionList as jest.Mock).mockReturnValue([false, mockDissasociate]); + (useDisassociateExceptionList as jest.Mock).mockReturnValue([false, mockDisassociate]); }); it('it renders error details', () => { @@ -104,7 +102,7 @@ describe('ErrorCallout', () => { expect(wrapper.find('[data-test-subj="errorCalloutMessage"]').at(0).text()).toEqual( 'Error fetching exception list' ); - expect(wrapper.find('[data-test-subj="errorCalloutDissasociateButton"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="errorCalloutDisassociateButton"]').exists()).toBeFalsy(); }); it('it renders specific missing exceptions list error', () => { @@ -133,10 +131,10 @@ describe('ErrorCallout', () => { expect(wrapper.find('[data-test-subj="errorCalloutMessage"]').at(0).text()).toEqual( 'The associated exception list (some_uuid) no longer exists. Please remove the missing exception list to add additional exceptions to the detection rule.' ); - expect(wrapper.find('[data-test-subj="errorCalloutDissasociateButton"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="errorCalloutDisassociateButton"]').exists()).toBeTruthy(); }); - it('it dissasociates list from rule when remove exception list clicked ', () => { + it('it disassociates list from rule when remove exception list clicked ', () => { const wrapper = mountWithIntl( { /> ); - wrapper.find('[data-test-subj="errorCalloutDissasociateButton"]').at(0).simulate('click'); + wrapper.find('[data-test-subj="errorCalloutDisassociateButton"]').at(0).simulate('click'); - expect(mockDissasociate).toHaveBeenCalledWith([]); + expect(mockDisassociate).toHaveBeenCalledWith([]); }); }); 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 84583ad5f3139..104481b6e111a 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 '../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../rule_management/logic/types'; import * as i18n from '../../utils/translations'; -import { useDissasociateExceptionList } from '../../../../detections/containers/detection_engine/rules/use_dissasociate_exception_list'; +import { useDisassociateExceptionList } from '../../../rule_management/logic/use_disassociate_exception_list'; export interface ErrorInfo { reason: string | null; @@ -54,7 +54,7 @@ const ErrorCalloutComponent = ({ onSuccess(listToDelete != null ? listToDelete.id : ''); }, [onSuccess, listToDelete]); - const [isDissasociatingList, handleDissasociateExceptionList] = useDissasociateExceptionList({ + const [isDisassociatingList, handleDisassociateExceptionList] = useDisassociateExceptionList({ http, ruleRuleId: rule != null ? rule.rule_id : '', onSuccess: handleOnSuccess, @@ -66,8 +66,8 @@ const ErrorCalloutComponent = ({ errorInfo.code === 404 && rule != null && listToDelete != null && - handleDissasociateExceptionList != null, - [errorInfo.code, listToDelete, handleDissasociateExceptionList, rule] + handleDisassociateExceptionList != null, + [errorInfo.code, listToDelete, handleDisassociateExceptionList, rule] ); useEffect((): void => { @@ -80,23 +80,23 @@ const ErrorCalloutComponent = ({ setErrorTitle(`${errorInfo.reason}${errorInfo.code != null ? ` (${errorInfo.code})` : ''}`); }, [errorInfo.reason, errorInfo.code, listToDelete, canDisplay404Actions]); - const handleDissasociateList = useCallback((): void => { + const handleDisassociateList = useCallback((): void => { // Yes, it's redundant, unfortunately typescript wasn't picking up - // that `handleDissasociateExceptionList` and `list` are checked in + // that `handleDisassociateExceptionList` and `list` are checked in // canDisplay404Actions if ( canDisplay404Actions && rule != null && listToDelete != null && - handleDissasociateExceptionList != null + handleDisassociateExceptionList != null ) { const exceptionLists = (rule.exceptions_list ?? []).filter( ({ id }) => id !== listToDelete.id ); - handleDissasociateExceptionList(exceptionLists); + handleDisassociateExceptionList(exceptionLists); } - }, [handleDissasociateExceptionList, listToDelete, canDisplay404Actions, rule]); + }, [handleDisassociateExceptionList, listToDelete, canDisplay404Actions, rule]); useEffect((): void => { if (errorInfo.code === 404 && rule != null && rule.exceptions_list != null) { @@ -144,16 +144,16 @@ const ErrorCalloutComponent = ({ {i18n.CANCEL} {canDisplay404Actions && ( {i18n.CLEAR_EXCEPTIONS_LABEL} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.test.tsx index f80372dc11283..1697a5d5b0bc7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.test.tsx @@ -8,13 +8,13 @@ import React from 'react'; import { mount } from 'enzyme'; -import { ExceptionItemCard } from '.'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; import { getCommentsArrayMock } from '@kbn/lists-plugin/common/schemas/types/comment.mock'; -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { TestProviders } from '../../../../common/mock'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; +import { TestProviders } from '../../../../common/mock'; +import { ExceptionItemCard } from '.'; + jest.mock('../../../../common/lib/kibana'); describe('ExceptionItemCard', () => { @@ -28,8 +28,8 @@ describe('ExceptionItemCard', () => { onDeleteException={jest.fn()} onEditException={jest.fn()} exceptionItem={exceptionItem} - listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={{ + isEndpoint={false} + listAndReferences={{ ...getExceptionListSchemaMock(), referenced_rules: [ { @@ -77,8 +77,8 @@ describe('ExceptionItemCard', () => { onEditException={jest.fn()} exceptionItem={exceptionItem} dataTestSubj="item" - listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={{ + isEndpoint={false} + listAndReferences={{ ...getExceptionListSchemaMock(), referenced_rules: [ { @@ -125,8 +125,8 @@ describe('ExceptionItemCard', () => { onEditException={jest.fn()} exceptionItem={exceptionItem} dataTestSubj="item" - listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={{ + isEndpoint={false} + listAndReferences={{ ...getExceptionListSchemaMock(), referenced_rules: [ { @@ -169,8 +169,8 @@ describe('ExceptionItemCard', () => { onEditException={mockOnEditException} exceptionItem={exceptionItem} dataTestSubj="item" - listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={{ + isEndpoint={false} + listAndReferences={{ ...getExceptionListSchemaMock(), referenced_rules: [ { @@ -203,6 +203,69 @@ describe('ExceptionItemCard', () => { .find('button[data-test-subj="exceptionItemCardHeader-actionButton"]') .at(0) .simulate('click'); + + expect( + wrapper.find('button[data-test-subj="exceptionItemCardHeader-actionItem-edit"]').text() + ).toEqual('Edit rule exception'); + + wrapper + .find('button[data-test-subj="exceptionItemCardHeader-actionItem-edit"]') + .simulate('click'); + + expect(mockOnEditException).toHaveBeenCalledWith(getExceptionListItemSchemaMock()); + }); + + it('it invokes "onEditException" when edit button clicked when "isEndpoint" is "true"', () => { + const mockOnEditException = jest.fn(); + const exceptionItem = getExceptionListItemSchemaMock(); + + const wrapper = mount( + + + + ); + + // click on popover + wrapper + .find('button[data-test-subj="exceptionItemCardHeader-actionButton"]') + .at(0) + .simulate('click'); + + expect( + wrapper.find('button[data-test-subj="exceptionItemCardHeader-actionItem-edit"]').text() + ).toEqual('Edit endpoint exception'); + wrapper .find('button[data-test-subj="exceptionItemCardHeader-actionItem-edit"]') .simulate('click'); @@ -222,8 +285,8 @@ describe('ExceptionItemCard', () => { onEditException={jest.fn()} exceptionItem={exceptionItem} dataTestSubj="item" - listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={{ + isEndpoint={false} + listAndReferences={{ ...getExceptionListSchemaMock(), referenced_rules: [ { @@ -256,6 +319,73 @@ describe('ExceptionItemCard', () => { .find('button[data-test-subj="exceptionItemCardHeader-actionButton"]') .at(0) .simulate('click'); + + expect( + wrapper.find('button[data-test-subj="exceptionItemCardHeader-actionItem-delete"]').text() + ).toEqual('Delete rule exception'); + + wrapper + .find('button[data-test-subj="exceptionItemCardHeader-actionItem-delete"]') + .simulate('click'); + + expect(mockOnDeleteException).toHaveBeenCalledWith({ + id: '1', + name: 'some name', + namespaceType: 'single', + }); + }); + + it('it invokes "onDeleteException" when delete button clicked when "isEndpoint" is "true"', () => { + const mockOnDeleteException = jest.fn(); + const exceptionItem = getExceptionListItemSchemaMock(); + + const wrapper = mount( + + + + ); + + // click on popover + wrapper + .find('button[data-test-subj="exceptionItemCardHeader-actionButton"]') + .at(0) + .simulate('click'); + + expect( + wrapper.find('button[data-test-subj="exceptionItemCardHeader-actionItem-delete"]').text() + ).toEqual('Delete endpoint exception'); + wrapper .find('button[data-test-subj="exceptionItemCardHeader-actionItem-delete"]') .simulate('click'); @@ -278,8 +408,8 @@ describe('ExceptionItemCard', () => { onEditException={jest.fn()} exceptionItem={exceptionItem} dataTestSubj="item" - listType={ExceptionListTypeEnum.DETECTION} - ruleReferences={{ + isEndpoint={false} + listAndReferences={{ ...getExceptionListSchemaMock(), referenced_rules: [ { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.tsx index 4bfa09e96486e..b841bac12f9d9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/index.tsx @@ -9,7 +9,6 @@ import type { EuiCommentProps } from '@elastic/eui'; import { EuiPanel, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useMemo, useCallback } from 'react'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { getFormattedComments } from '../../utils/helpers'; import type { ExceptionListItemIdentifiers } from '../../utils/types'; @@ -17,14 +16,14 @@ import * as i18n from './translations'; import { ExceptionItemCardHeader } from './header'; import { ExceptionItemCardConditions } from './conditions'; import { ExceptionItemCardMetaInfo } from './meta'; -import type { ExceptionListRuleReferencesSchema } from '../../../../../common/detection_engine/schemas/response'; +import type { ExceptionListRuleReferencesSchema } from '../../../../../common/detection_engine/rule_exceptions'; import { ExceptionItemCardComments } from './comments'; export interface ExceptionItemProps { exceptionItem: ExceptionListItemSchema; - listType: ExceptionListTypeEnum; + isEndpoint: boolean; disableActions: boolean; - ruleReferences: ExceptionListRuleReferencesSchema | null; + listAndReferences: ExceptionListRuleReferencesSchema | null; onDeleteException: (arg: ExceptionListItemIdentifiers) => void; onEditException: (item: ExceptionListItemSchema) => void; dataTestSubj: string; @@ -33,8 +32,8 @@ export interface ExceptionItemProps { const ExceptionItemCardComponent = ({ disableActions, exceptionItem, - listType, - ruleReferences, + isEndpoint, + listAndReferences, onDeleteException, onEditException, dataTestSubj, @@ -65,19 +64,17 @@ const ExceptionItemCardComponent = ({ { key: 'edit', icon: 'controlsHorizontal', - label: - listType === ExceptionListTypeEnum.ENDPOINT - ? i18n.ENDPOINT_EXCEPTION_ITEM_EDIT_BUTTON - : i18n.EXCEPTION_ITEM_EDIT_BUTTON, + label: isEndpoint + ? i18n.ENDPOINT_EXCEPTION_ITEM_EDIT_BUTTON + : i18n.EXCEPTION_ITEM_EDIT_BUTTON, onClick: handleEdit, }, { key: 'delete', icon: 'trash', - label: - listType === ExceptionListTypeEnum.ENDPOINT - ? i18n.ENDPOINT_EXCEPTION_ITEM_DELETE_BUTTON - : i18n.EXCEPTION_ITEM_DELETE_BUTTON, + label: isEndpoint + ? i18n.ENDPOINT_EXCEPTION_ITEM_DELETE_BUTTON + : i18n.EXCEPTION_ITEM_DELETE_BUTTON, onClick: handleDelete, }, ]} @@ -88,7 +85,7 @@ const ExceptionItemCardComponent = ({ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.test.tsx index 8892117f1616e..0a355a4567a8d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.test.tsx @@ -6,193 +6,233 @@ */ import React from 'react'; +import type { ReactWrapper } from 'enzyme'; import { mount } from 'enzyme'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; +import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionItemCardMetaInfo } from './meta'; import { TestProviders } from '../../../../common/mock'; describe('ExceptionItemCardMetaInfo', () => { - it('it renders item creation info', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find('[data-test-subj="exceptionItemMeta-createdBy-value1"]').at(0).text() - ).toEqual('Apr 20, 2020 @ 15:25:31.830'); - expect( - wrapper.find('[data-test-subj="exceptionItemMeta-createdBy-value2"]').at(0).text() - ).toEqual('some user'); - }); + describe('general functionality', () => { + let wrapper: ReactWrapper; + + beforeAll(() => { + wrapper = mount( + + + + ); + }); + + it('it renders item creation info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-createdBy-value1"]').at(0).text() + ).toEqual('Apr 20, 2020 @ 15:25:31.830'); + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-createdBy-value2"]').at(0).text() + ).toEqual('some user'); + }); + + it('it renders item update info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-updatedBy-value1"]').at(0).text() + ).toEqual('Apr 20, 2020 @ 15:25:31.830'); + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-updatedBy-value2"]').at(0).text() + ).toEqual('some user'); + }); + + it('it renders references info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-affectedRulesButton"]').at(0).text() + ).toEqual('Affects 1 rule'); + }); + + it('it renders affected shared list info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-affectedListsButton"]').at(0).text() + ).toEqual('Affects shared list'); + }); + + it('it renders references info when multiple references exist', () => { + wrapper = mount( + + + + ); - it('it renders item update info', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find('[data-test-subj="exceptionItemMeta-updatedBy-value1"]').at(0).text() - ).toEqual('Apr 20, 2020 @ 15:25:31.830'); - expect( - wrapper.find('[data-test-subj="exceptionItemMeta-updatedBy-value2"]').at(0).text() - ).toEqual('some user'); + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-affectedRulesButton"]').at(0).text() + ).toEqual('Affects 2 rules'); + }); }); - it('it renders references info', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find('[data-test-subj="exceptionItemMeta-affectedRulesButton"]').at(0).text() - ).toEqual('Affects 1 rule'); + describe('exception item for "rule_default" list', () => { + let wrapper: ReactWrapper; + + beforeAll(() => { + wrapper = mount( + + + + ); + }); + + it('it renders references info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-affectedRulesButton"]').at(0).text() + ).toEqual('Affects 1 rule'); + }); + + it('it does NOT render affected shared list info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-affectedListsButton"]').exists() + ).toBeFalsy(); + }); }); - it('it renders references info when multiple references exist', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find('[data-test-subj="exceptionItemMeta-affectedRulesButton"]').at(0).text() - ).toEqual('Affects 2 rules'); + describe('exception item for "endpoint" list', () => { + let wrapper: ReactWrapper; + + beforeAll(() => { + wrapper = mount( + + + + ); + }); + + it('it renders references info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-affectedRulesButton"]').at(0).text() + ).toEqual('Affects 1 rule'); + }); + + it('it renders affected shared list info', () => { + expect( + wrapper.find('[data-test-subj="exceptionItemMeta-affectedListsButton"]').at(0).text() + ).toEqual('Affects shared list'); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx index 453e1542bfce8..c025a2dc2a2cb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx @@ -19,14 +19,15 @@ import { EuiPopover, } from '@elastic/eui'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import styled from 'styled-components'; import * as i18n from './translations'; import { FormattedDate } from '../../../../common/components/formatted_date'; import { SecurityPageName } from '../../../../../common/constants'; -import type { ExceptionListRuleReferencesSchema } from '../../../../../common/detection_engine/schemas/response'; +import type { ExceptionListRuleReferencesSchema } from '../../../../../common/detection_engine/rule_exceptions'; import { SecuritySolutionLinkAnchor } from '../../../../common/components/links'; -import { RuleDetailTabs } from '../../../../detections/pages/detection_engine/rules/details'; +import { RuleDetailTabs } from '../../../rule_details_ui/pages/rule_details'; import { getRuleDetailsTabUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; const StyledFlexItem = styled(EuiFlexItem)` @@ -36,24 +37,27 @@ const StyledFlexItem = styled(EuiFlexItem)` export interface ExceptionItemCardMetaInfoProps { item: ExceptionListItemSchema; - references: ExceptionListRuleReferencesSchema | null; + listAndReferences: ExceptionListRuleReferencesSchema | null; dataTestSubj: string; } export const ExceptionItemCardMetaInfo = memo( - ({ item, references, dataTestSubj }) => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); + ({ item, listAndReferences, dataTestSubj }) => { + const [isListsPopoverOpen, setIsListsPopoverOpen] = useState(false); + const [isRulesPopoverOpen, setIsRulesPopoverOpen] = useState(false); - const onAffectedRulesClick = () => setIsPopoverOpen((isOpen) => !isOpen); - const onClosePopover = () => setIsPopoverOpen(false); + const onAffectedRulesClick = () => setIsRulesPopoverOpen((isOpen) => !isOpen); + const onAffectedListsClick = () => setIsListsPopoverOpen((isOpen) => !isOpen); + const onCloseRulesPopover = () => setIsRulesPopoverOpen(false); + const onClosListsPopover = () => setIsListsPopoverOpen(false); const itemActions = useMemo((): EuiContextMenuPanelProps['items'] => { - if (references == null) { + if (listAndReferences == null) { return []; } - return references.referenced_rules.map((reference) => ( + return listAndReferences.referenced_rules.map((reference) => ( @@ -61,13 +65,92 @@ export const ExceptionItemCardMetaInfo = memo( data-test-subj="ruleName" deepLinkId={SecurityPageName.rules} path={getRuleDetailsTabUrl(reference.id, RuleDetailTabs.alerts)} + external > {reference.name} )); - }, [references, dataTestSubj]); + }, [listAndReferences, dataTestSubj]); + + const rulesAffected = useMemo((): JSX.Element => { + if (listAndReferences == null) return <>; + + return ( + + + {i18n.AFFECTED_RULES(listAndReferences?.referenced_rules.length ?? 0)} + + } + panelPaddingSize="none" + isOpen={isRulesPopoverOpen} + closePopover={onCloseRulesPopover} + data-test-subj={`${dataTestSubj}-rulesPopover`} + id={'rulesPopover'} + > + + + + ); + }, [listAndReferences, dataTestSubj, isRulesPopoverOpen, itemActions]); + + const listsAffected = useMemo((): JSX.Element => { + if (listAndReferences == null) return <>; + + if (listAndReferences.type !== ExceptionListTypeEnum.RULE_DEFAULT) { + return ( + + + {i18n.AFFECTED_LIST} + + } + panelPaddingSize="none" + isOpen={isListsPopoverOpen} + closePopover={onClosListsPopover} + data-test-subj={`${dataTestSubj}-listsPopover`} + id={'listsPopover'} + > + + + + {listAndReferences.name} + + + , + ]} + /> + + + ); + } else { + return <>; + } + }, [listAndReferences, dataTestSubj, isListsPopoverOpen]); return ( ( dataTestSubj={`${dataTestSubj}-updatedBy`} /> - {references != null && ( - - - {i18n.AFFECTED_RULES(references?.referenced_rules.length ?? 0)} - - } - panelPaddingSize="none" - isOpen={isPopoverOpen} - closePopover={onClosePopover} - data-test-subj={`${dataTestSubj}-items`} - > - - - + {listAndReferences != null && ( + <> + {rulesAffected} + {listsAffected} + )} ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/translations.ts index ccdd5eebf3b8c..75d0b098c297e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/translations.ts @@ -8,174 +8,181 @@ import { i18n } from '@kbn/i18n'; export const EXCEPTION_ITEM_EDIT_BUTTON = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.editItemButton', + 'xpack.securitySolution.ruleExceptions.exceptionItem.editItemButton', { defaultMessage: 'Edit rule exception', } ); export const EXCEPTION_ITEM_DELETE_BUTTON = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.deleteItemButton', + 'xpack.securitySolution.ruleExceptions.exceptionItem.deleteItemButton', { defaultMessage: 'Delete rule exception', } ); export const ENDPOINT_EXCEPTION_ITEM_EDIT_BUTTON = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.endpoint.editItemButton', + 'xpack.securitySolution.ruleExceptions.exceptionItem.endpoint.editItemButton', { defaultMessage: 'Edit endpoint exception', } ); export const ENDPOINT_EXCEPTION_ITEM_DELETE_BUTTON = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.endpoint.deleteItemButton', + 'xpack.securitySolution.ruleExceptions.exceptionItem.endpoint.deleteItemButton', { defaultMessage: 'Delete endpoint exception', } ); export const EXCEPTION_ITEM_CREATED_LABEL = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.createdLabel', + 'xpack.securitySolution.ruleExceptions.exceptionItem.createdLabel', { defaultMessage: 'Created', } ); export const EXCEPTION_ITEM_UPDATED_LABEL = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.updatedLabel', + 'xpack.securitySolution.ruleExceptions.exceptionItem.updatedLabel', { defaultMessage: 'Updated', } ); export const EXCEPTION_ITEM_META_BY = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.metaDetailsBy', + 'xpack.securitySolution.ruleExceptions.exceptionItem.metaDetailsBy', { defaultMessage: 'by', } ); export const exceptionItemCommentsAccordion = (comments: number) => - i18n.translate('xpack.securitySolution.exceptions.exceptionItem.showCommentsLabel', { + i18n.translate('xpack.securitySolution.ruleExceptions.exceptionItem.showCommentsLabel', { values: { comments }, defaultMessage: 'Show {comments, plural, =1 {comment} other {comments}} ({comments})', }); export const CONDITION_OPERATOR_TYPE_MATCH = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.matchOperator', { defaultMessage: 'IS', } ); export const CONDITION_OPERATOR_TYPE_NOT_MATCH = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator.not', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.matchOperator.not', { defaultMessage: 'IS NOT', } ); export const CONDITION_OPERATOR_TYPE_WILDCARD_MATCHES = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardMatchesOperator', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.wildcardMatchesOperator', { defaultMessage: 'MATCHES', } ); export const CONDITION_OPERATOR_TYPE_WILDCARD_DOES_NOT_MATCH = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardDoesNotMatchOperator', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.wildcardDoesNotMatchOperator', { defaultMessage: 'DOES NOT MATCH', } ); export const CONDITION_OPERATOR_TYPE_NESTED = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.nestedOperator', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.nestedOperator', { defaultMessage: 'has', } ); export const CONDITION_OPERATOR_TYPE_MATCH_ANY = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.matchAnyOperator', { defaultMessage: 'is one of', } ); export const CONDITION_OPERATOR_TYPE_NOT_MATCH_ANY = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator.not', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.matchAnyOperator.not', { defaultMessage: 'is not one of', } ); export const CONDITION_OPERATOR_TYPE_EXISTS = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.existsOperator', { defaultMessage: 'exists', } ); export const CONDITION_OPERATOR_TYPE_DOES_NOT_EXIST = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator.not', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.existsOperator.not', { defaultMessage: 'does not exist', } ); export const CONDITION_OPERATOR_TYPE_LIST = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.listOperator', { defaultMessage: 'included in', } ); export const CONDITION_OPERATOR_TYPE_NOT_IN_LIST = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator.not', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.listOperator.not', { defaultMessage: 'is not included in', } ); export const CONDITION_AND = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.and', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.and', { defaultMessage: 'AND', } ); export const CONDITION_OS = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.os', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.os', { defaultMessage: 'OS', } ); export const OS_WINDOWS = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.windows', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.windows', { defaultMessage: 'Windows', } ); export const OS_LINUX = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.linux', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.linux', { defaultMessage: 'Linux', } ); export const OS_MAC = i18n.translate( - 'xpack.securitySolution.exceptions.exceptionItem.conditions.macos', + 'xpack.securitySolution.ruleExceptions.exceptionItem.conditions.macos', { defaultMessage: 'Mac', } ); export const AFFECTED_RULES = (numRules: number) => - i18n.translate('xpack.securitySolution.exceptions.exceptionItem.affectedRules', { + i18n.translate('xpack.securitySolution.ruleExceptions.exceptionItem.affectedRules', { values: { numRules }, defaultMessage: 'Affects {numRules} {numRules, plural, =1 {rule} other {rules}}', }); + +export const AFFECTED_LIST = i18n.translate( + 'xpack.securitySolution.ruleExceptions.exceptionItem.affectedList', + { + defaultMessage: 'Affects shared list', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.test.tsx index d9038b0c3fd04..6f81b8177b5f6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.test.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { getRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import { getRulesSchemaMock } from '../../../../../../common/detection_engine/rule_schema/mocks'; +import type { Rule } from '../../../../rule_management/logic/types'; import { ExceptionsAddToRulesOrLists } from '.'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.tsx index aa705891ecfe7..67e66cc8faa13 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_exception_to_rule_or_list/index.tsx @@ -12,7 +12,7 @@ import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import * as i18n from './translations'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../../rule_management/logic/types'; import { ExceptionsAddToRulesOptions } from '../add_to_rules_options'; import { ExceptionsAddToListsOptions } from '../add_to_lists_options'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_options/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_options/index.test.tsx index 4b55522a638e2..b8911e47d1eb6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_options/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_options/index.test.tsx @@ -11,7 +11,7 @@ import { shallow } from 'enzyme'; import { ExceptionsAddToListsOptions } from '.'; -jest.mock('../../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'); +jest.mock('../../../../rule_management/logic/use_find_rules'); describe('ExceptionsAddToListsOptions', () => { it('it displays radio option as disabled if there are no "sharedLists"', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_table/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_table/index.tsx index f8dc8e41a6df4..d99480ae565cb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_lists_table/index.tsx @@ -11,11 +11,11 @@ import { EuiText, EuiSpacer, EuiInMemoryTable, EuiPanel, EuiLoadingContent } fro import type { ExceptionListSchema, ListArray } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import type { FindRulesReferencedByExceptionsListProp } from '../../../../../detections/containers/detection_engine/rules'; +import type { FindRulesReferencedByExceptionsListProp } from '../../../../rule_management/logic'; import * as i18n from './translations'; import { getSharedListsTableColumns } from '../utils'; import { useFindExceptionListReferences } from '../../../logic/use_find_references'; -import type { ExceptionListRuleReferencesSchema } from '../../../../../../common/detection_engine/schemas/response'; +import type { ExceptionListRuleReferencesSchema } from '../../../../../../common/detection_engine/rule_exceptions'; interface ExceptionsAddToListsComponentProps { /** diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.test.tsx index 8084231a53676..fe65b3ce0384e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.test.tsx @@ -10,15 +10,17 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ExceptionsAddToRulesOptions } from '.'; import { TestProviders } from '../../../../../common/mock'; -import { useFindRules } from '../../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'; -import { getRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import { useFindRulesInMemory } from '../../../../rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory'; +import { getRulesSchemaMock } from '../../../../../../common/detection_engine/rule_schema/mocks'; +import type { Rule } from '../../../../rule_management/logic/types'; -jest.mock('../../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'); +jest.mock( + '../../../../rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory' +); describe('ExceptionsAddToRulesOptions', () => { beforeEach(() => { - (useFindRules as jest.Mock).mockReturnValue({ + (useFindRulesInMemory as jest.Mock).mockReturnValue({ data: { rules: [getRulesSchemaMock(), { ...getRulesSchemaMock(), id: '345', name: 'My rule' }], total: 0, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.tsx index 424f8221b5a48..67ef993479713 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_options/index.tsx @@ -9,7 +9,7 @@ import React, { useMemo } from 'react'; import { EuiRadio, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../../rule_management/logic/types'; import { ExceptionsAddToRulesTable } from '../add_to_rules_table'; export type AddToRuleListsRadioOptions = 'select_rules_to_add_to' | 'add_to_rules' | 'add_to_rule'; 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 d0d5a265a2c4f..48a710cc66ad8 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 @@ -10,15 +10,17 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ExceptionsAddToRulesTable } from '.'; import { TestProviders } from '../../../../../common/mock'; -import { useFindRules } from '../../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'; -import { getRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import { useFindRulesInMemory } from '../../../../rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory'; +import { getRulesSchemaMock } from '../../../../../../common/detection_engine/rule_schema/mocks'; +import type { Rule } from '../../../../rule_management/logic/types'; -jest.mock('../../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'); +jest.mock( + '../../../../rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory' +); describe('ExceptionsAddToRulesTable', () => { it('it displays loading state while fetching rules', () => { - (useFindRules as jest.Mock).mockReturnValue({ + (useFindRulesInMemory as jest.Mock).mockReturnValue({ data: { rules: [], total: 0 }, isFetched: false, }); @@ -34,7 +36,7 @@ describe('ExceptionsAddToRulesTable', () => { }); it('it displays fetched rules', () => { - (useFindRules as jest.Mock).mockReturnValue({ + (useFindRulesInMemory as jest.Mock).mockReturnValue({ data: { rules: [getRulesSchemaMock(), { ...getRulesSchemaMock(), id: '345', name: 'My rule' }], total: 0, 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 6b56b0eceb2f3..b4112228c923f 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 @@ -11,8 +11,8 @@ import { EuiSpacer, EuiPanel, EuiText, EuiInMemoryTable, EuiLoadingContent } fro import { i18n } from '@kbn/i18n'; import * as myI18n from './translations'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; -import { useFindRules } from '../../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'; +import type { Rule } from '../../../../rule_management/logic/types'; +import { useFindRulesInMemory } from '../../../../rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory'; import { getRulesTableColumn } from '../utils'; interface ExceptionsAddToRulesComponentProps { @@ -24,7 +24,7 @@ const ExceptionsAddToRulesTableComponent: React.FC { - const { data: { rules } = { rules: [], total: 0 }, isFetched } = useFindRules({ + const { data: { rules } = { rules: [], total: 0 }, isFetched } = useFindRulesInMemory({ isInMemorySorting: true, filterOptions: { filter: '', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.test.tsx index a5d6de83b0655..81f8925565f36 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.test.tsx @@ -10,8 +10,8 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ExceptionsConditions } from '.'; import { TestProviders, mockIndexPattern } from '../../../../../common/mock'; -import { getRulesEqlSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import { getRulesEqlSchemaMock } from '../../../../../../common/detection_engine/rule_schema/mocks'; +import type { Rule } from '../../../../rule_management/logic/types'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import * as i18n from './translations'; 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 46f16ec468873..c1f11b17cbbd9 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 { 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 type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../../rule_management/logic/types'; import { useKibana } from '../../../../../common/lib/kibana'; import * as i18n from './translations'; import * as sharedI18n from '../../../utils/translations'; @@ -266,6 +266,7 @@ const ExceptionsConditionsComponent: React.FC ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_list/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_list/index.tsx index 55a748ae7dffd..f09b15bda16a1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_list/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_list/index.tsx @@ -10,7 +10,7 @@ import { EuiTitle, EuiSpacer, EuiPanel, EuiInMemoryTable, EuiLoadingContent } fr import styled, { css } from 'styled-components'; import * as i18n from './translations'; -import type { ExceptionListRuleReferencesSchema } from '../../../../../../common/detection_engine/schemas/response'; +import type { ExceptionListRuleReferencesSchema } from '../../../../../../common/detection_engine/rule_exceptions'; import { getSharedListsTableColumns } from '../utils'; interface ExceptionsLinkedToListComponentProps { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx index 56cf481282d34..42e59832f8abb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx @@ -10,10 +10,10 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ExceptionsLinkedToRule } from '.'; import { TestProviders } from '../../../../../common/mock'; -import { getRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import { getRulesSchemaMock } from '../../../../../../common/detection_engine/rule_schema/mocks'; +import type { Rule } from '../../../../rule_management/logic/types'; -jest.mock('../../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'); +jest.mock('../../../../rule_management/logic/use_find_rules'); describe('ExceptionsLinkedToRule', () => { it('it displays rule name and link', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.tsx index 289660317025c..64a378e8fb33a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.tsx @@ -10,7 +10,7 @@ import { EuiTitle, EuiSpacer, EuiInMemoryTable } from '@elastic/eui'; import styled, { css } from 'styled-components'; import * as i18n from './translations'; -import type { Rule } from '../../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../../rule_management/logic/types'; import { getRulesTableColumn } from '../utils'; interface ExceptionsLinkedToRuleComponentProps { 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 77e881fdad6f0..a8674883253c0 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 @@ -22,14 +22,14 @@ import { } from '../../utils/helpers'; import { SecuritySolutionLinkAnchor } from '../../../../common/components/links'; import { getRuleDetailsTabUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; -import { RuleDetailTabs } from '../../../../detections/pages/detection_engine/rules/details'; +import { RuleDetailTabs } from '../../../rule_details_ui/pages/rule_details'; import { SecurityPageName } from '../../../../../common/constants'; import { PopoverItems } from '../../../../common/components/popover_items'; import type { ExceptionListRuleReferencesInfoSchema, ExceptionListRuleReferencesSchema, -} from '../../../../../common/detection_engine/schemas/response'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; +} from '../../../../../common/detection_engine/rule_exceptions'; +import type { Rule } from '../../../rule_management/logic/types'; import * as i18n from './translations'; /** diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx index 214d0041fb9a2..47933db0b3522 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx @@ -110,7 +110,6 @@ describe('ExceptionItemComments', () => { ); - expect(wrapper.find('[data-test-subj="exceptionItemCommentsAccordion"]').exists()).toBeFalsy(); expect( wrapper.find('[data-test-subj="newExceptionItemCommentTextArea"]').at(1).props().value ).toEqual('This is a new comment'); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx index fa514850e30b4..a3553c78f8b30 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx @@ -82,10 +82,6 @@ export const ExceptionItemComments = memo(function ExceptionItemComments({ setShouldShowComments(isOpen); }, []); - const exceptionItemsExist: boolean = useMemo(() => { - return exceptionItemComments != null && exceptionItemComments.length > 0; - }, [exceptionItemComments]); - const commentsAccordionTitle = useMemo(() => { if (exceptionItemComments && exceptionItemComments.length > 0) { return ( @@ -110,32 +106,30 @@ export const ExceptionItemComments = memo(function ExceptionItemComments({ return (
    - {exceptionItemsExist && ( - handleTriggerOnClick(isOpen)} - > - - - )} - - - - - - - - + handleTriggerOnClick(isOpen)} + > + + + + + + + + + +
    ); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/translations.ts new file mode 100644 index 0000000000000..8c1ceb9f639fb --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/translations.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 { i18n } from '@kbn/i18n'; + +export const CLOSE_ALERTS_SUCCESS = (numAlerts: number) => + i18n.translate('xpack.securitySolution.ruleExceptions.logic.closeAlerts.success', { + values: { numAlerts }, + defaultMessage: + 'Successfully updated {numAlerts} {numAlerts, plural, =1 {alert} other {alerts}}', + }); + +export const CLOSE_ALERTS_ERROR = i18n.translate( + 'xpack.securitySolution.ruleExceptions.logic.closeAlerts.error', + { + defaultMessage: 'Failed to close alerts', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_exception.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_exception.test.tsx deleted file mode 100644 index e882e05f6e085..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_exception.test.tsx +++ /dev/null @@ -1,423 +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 { RenderHookResult } from '@testing-library/react-hooks'; -import { act, renderHook } from '@testing-library/react-hooks'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { coreMock } from '@kbn/core/public/mocks'; -import { KibanaServices } from '../../../common/lib/kibana'; - -import * as alertsApi from '../../../detections/containers/detection_engine/alerts/api'; -import * as listsApi from '@kbn/securitysolution-list-api'; -import * as getQueryFilterHelper from '../../../detections/containers/detection_engine/exceptions/get_es_query_filter'; -import * as buildFilterHelpers from '../../../detections/components/alerts_table/default_config'; -import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import { getCreateExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; -import { getUpdateExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_exception_list_item_schema.mock'; -import type { - ExceptionListItemSchema, - CreateExceptionListItemSchema, - UpdateExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { TestProviders } from '../../../common/mock'; -import type { - UseAddOrUpdateExceptionProps, - ReturnUseAddOrUpdateException, - AddOrUpdateExceptionItemsFunc, -} from './use_add_exception'; -import { useAddOrUpdateException } from './use_add_exception'; - -const mockKibanaHttpService = coreMock.createStart().http; -const mockKibanaServices = KibanaServices.get as jest.Mock; -jest.mock('../../../common/lib/kibana'); -jest.mock('@kbn/securitysolution-list-api'); - -const fetchMock = jest.fn(); -mockKibanaServices.mockReturnValue({ http: { fetch: fetchMock } }); - -describe('useAddOrUpdateException', () => { - let updateAlertStatus: jest.SpyInstance>; - let addExceptionListItem: jest.SpyInstance>; - let updateExceptionListItem: jest.SpyInstance>; - let getQueryFilter: jest.SpyInstance>; - let buildAlertStatusesFilter: jest.SpyInstance< - ReturnType - >; - let buildAlertsFilter: jest.SpyInstance>; - let addOrUpdateItemsArgs: Parameters; - let render: () => RenderHookResult; - const onError = jest.fn(); - const onSuccess = jest.fn(); - const ruleStaticId = 'rule-id'; - const alertIdToClose = 'idToClose'; - const bulkCloseIndex = ['.custom']; - const itemsToAdd: CreateExceptionListItemSchema[] = [ - { - ...getCreateExceptionListItemSchemaMock(), - name: 'item to add 1', - }, - { - ...getCreateExceptionListItemSchemaMock(), - name: 'item to add 2', - }, - ]; - const itemsToUpdate: ExceptionListItemSchema[] = [ - { - ...getExceptionListItemSchemaMock(), - name: 'item to update 1', - }, - { - ...getExceptionListItemSchemaMock(), - name: 'item to update 2', - }, - ]; - const itemsToUpdateFormatted: UpdateExceptionListItemSchema[] = itemsToUpdate.map( - (item: ExceptionListItemSchema) => { - const formatted: UpdateExceptionListItemSchema = getUpdateExceptionListItemSchemaMock(); - const newObj = (Object.keys(formatted) as Array).reduce( - (acc, key) => { - return { - ...acc, - [key]: item[key], - }; - }, - {} as UpdateExceptionListItemSchema - ); - return newObj; - } - ); - - const itemsToAddOrUpdate = [...itemsToAdd, ...itemsToUpdate]; - - const waitForAddOrUpdateFunc: (arg: { - waitForNextUpdate: RenderHookResult< - UseAddOrUpdateExceptionProps, - ReturnUseAddOrUpdateException - >['waitForNextUpdate']; - rerender: RenderHookResult< - UseAddOrUpdateExceptionProps, - ReturnUseAddOrUpdateException - >['rerender']; - result: RenderHookResult['result']; - }) => Promise = async ({ - waitForNextUpdate, - rerender, - result, - }) => { - await waitForNextUpdate(); - rerender(); - expect(result.current[1]).not.toBeNull(); - return Promise.resolve(result.current[1]); - }; - - beforeEach(() => { - updateAlertStatus = jest.spyOn(alertsApi, 'updateAlertStatus'); - - addExceptionListItem = jest - .spyOn(listsApi, 'addExceptionListItem') - .mockResolvedValue(getExceptionListItemSchemaMock()); - - updateExceptionListItem = jest - .spyOn(listsApi, 'updateExceptionListItem') - .mockResolvedValue(getExceptionListItemSchemaMock()); - - getQueryFilter = jest - .spyOn(getQueryFilterHelper, 'getEsQueryFilter') - .mockResolvedValue({ bool: { must_not: [], must: [], filter: [], should: [] } }); - - buildAlertStatusesFilter = jest.spyOn(buildFilterHelpers, 'buildAlertStatusesFilter'); - - buildAlertsFilter = jest.spyOn(buildFilterHelpers, 'buildAlertsFilter'); - - addOrUpdateItemsArgs = [ruleStaticId, itemsToAddOrUpdate]; - render = () => - renderHook( - () => - useAddOrUpdateException({ - http: mockKibanaHttpService, - onError, - onSuccess, - }), - { - wrapper: TestProviders, - } - ); - }); - - afterEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - it('initializes hook', async () => { - await act(async () => { - const { result, waitForNextUpdate } = render(); - await waitForNextUpdate(); - expect(result.current).toEqual([{ isLoading: false }, result.current[1]]); - }); - }); - - it('invokes "onError" if call to add exception item fails', async () => { - const mockError = new Error('error adding item'); - - addExceptionListItem = jest - .spyOn(listsApi, 'addExceptionListItem') - .mockRejectedValue(mockError); - - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(onError).toHaveBeenCalledWith(mockError, null, null); - }); - }); - - it('invokes "onError" if call to update exception item fails', async () => { - const mockError = new Error('error updating item'); - - updateExceptionListItem = jest - .spyOn(listsApi, 'updateExceptionListItem') - .mockRejectedValue(mockError); - - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(onError).toHaveBeenCalledWith(mockError, null, null); - }); - }); - - describe('when alertIdToClose is not passed in', () => { - it('should not update the alert status', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(updateAlertStatus).not.toHaveBeenCalled(); - }); - }); - - it('creates new items', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(addExceptionListItem).toHaveBeenCalledTimes(2); - expect(addExceptionListItem.mock.calls[1][0].listItem).toEqual(itemsToAdd[1]); - }); - }); - it('updates existing items', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(updateExceptionListItem).toHaveBeenCalledTimes(2); - expect(updateExceptionListItem.mock.calls[1][0].listItem).toEqual( - itemsToUpdateFormatted[1] - ); - }); - }); - }); - - describe('when alertIdToClose is passed in', () => { - beforeEach(() => { - addOrUpdateItemsArgs = [ruleStaticId, itemsToAddOrUpdate, alertIdToClose]; - }); - it('should update the alert status', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(updateAlertStatus).toHaveBeenCalledTimes(1); - }); - }); - it('creates new items', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(addExceptionListItem).toHaveBeenCalledTimes(2); - expect(addExceptionListItem.mock.calls[1][0].listItem).toEqual(itemsToAdd[1]); - }); - }); - it('updates existing items', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(updateExceptionListItem).toHaveBeenCalledTimes(2); - expect(updateExceptionListItem.mock.calls[1][0].listItem).toEqual( - itemsToUpdateFormatted[1] - ); - }); - }); - }); - - describe('when bulkCloseIndex is passed in', () => { - beforeEach(() => { - addOrUpdateItemsArgs = [ruleStaticId, itemsToAddOrUpdate, undefined, bulkCloseIndex]; - }); - it('should update the status of only alerts that are open', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(buildAlertStatusesFilter).toHaveBeenCalledTimes(1); - expect(buildAlertStatusesFilter.mock.calls[0][0]).toEqual([ - 'open', - 'acknowledged', - 'in-progress', - ]); - }); - }); - it('should update the status of only alerts generated by the provided rule', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(buildAlertsFilter).toHaveBeenCalledTimes(1); - expect(buildAlertsFilter.mock.calls[0][0]).toEqual(ruleStaticId); - }); - }); - it('should generate the query filter using exceptions', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(getQueryFilter).toHaveBeenCalledTimes(1); - expect(getQueryFilter.mock.calls[0][4]).toEqual(itemsToAddOrUpdate); - expect(getQueryFilter.mock.calls[0][5]).toEqual(false); - }); - }); - it('should update the alert status', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(updateAlertStatus).toHaveBeenCalledTimes(1); - }); - }); - it('creates new items', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(addExceptionListItem).toHaveBeenCalledTimes(2); - expect(addExceptionListItem.mock.calls[1][0].listItem).toEqual(itemsToAdd[1]); - }); - }); - it('updates existing items', async () => { - await act(async () => { - const { rerender, result, waitForNextUpdate } = render(); - const addOrUpdateItems = await waitForAddOrUpdateFunc({ - rerender, - result, - waitForNextUpdate, - }); - if (addOrUpdateItems) { - addOrUpdateItems(...addOrUpdateItemsArgs); - } - await waitForNextUpdate(); - expect(updateExceptionListItem).toHaveBeenCalledTimes(2); - expect(updateExceptionListItem.mock.calls[1][0].listItem).toEqual( - itemsToUpdateFormatted[1] - ); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_exception.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_exception.tsx deleted file mode 100644 index a6149f366dfaf..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_exception.tsx +++ /dev/null @@ -1,192 +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 { useEffect, useRef, useState, useCallback } from 'react'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { - ExceptionListItemSchema, - CreateExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { useApi, removeIdFromExceptionItemsEntries } from '@kbn/securitysolution-list-hooks'; -import type { HttpStart } from '@kbn/core/public'; - -import { updateAlertStatus } from '../../../detections/containers/detection_engine/alerts/api'; -import { getUpdateAlertsQuery } from '../../../detections/components/alerts_table/actions'; -import { - buildAlertsFilter, - buildAlertStatusesFilter, -} from '../../../detections/components/alerts_table/default_config'; -import { getEsQueryFilter } from '../../../detections/containers/detection_engine/exceptions/get_es_query_filter'; -import type { Index } from '../../../../common/detection_engine/schemas/common/schemas'; -import { formatExceptionItemForUpdate, prepareExceptionItemsForBulkClose } from '../utils/helpers'; -import { useKibana } from '../../../common/lib/kibana'; - -/** - * Adds exception items to the list. Also optionally closes alerts. - * - * @param ruleStaticId static id of the rule (rule.ruleId, not rule.id) where the exception updates will be applied - * @param exceptionItemsToAddOrUpdate array of ExceptionListItemSchema to add or update - * @param alertIdToClose - optional string representing alert to close - * @param bulkCloseIndex - optional index used to create bulk close query - * - */ -export type AddOrUpdateExceptionItemsFunc = ( - ruleStaticId: string, - exceptionItemsToAddOrUpdate: Array, - alertIdToClose?: string, - bulkCloseIndex?: Index -) => Promise; - -export type ReturnUseAddOrUpdateException = [ - { isLoading: boolean }, - AddOrUpdateExceptionItemsFunc | null -]; - -export interface UseAddOrUpdateExceptionProps { - http: HttpStart; - onError: (arg: Error, code: number | null, message: string | null) => void; - onSuccess: (updated: number, conficts: number) => void; -} - -/** - * Hook for adding and updating an exception item - * - * @param http Kibana http service - * @param onError error callback - * @param onSuccess callback when all lists fetched successfully - * - */ -export const useAddOrUpdateException = ({ - http, - onError, - onSuccess, -}: UseAddOrUpdateExceptionProps): ReturnUseAddOrUpdateException => { - const { services } = useKibana(); - const [isLoading, setIsLoading] = useState(false); - const addOrUpdateExceptionRef = useRef(null); - const { addExceptionListItem, updateExceptionListItem } = useApi(services.http); - const addOrUpdateException = useCallback( - async (ruleStaticId, exceptionItemsToAddOrUpdate, alertIdToClose, bulkCloseIndex) => { - if (addOrUpdateExceptionRef.current != null) { - addOrUpdateExceptionRef.current( - ruleStaticId, - exceptionItemsToAddOrUpdate, - alertIdToClose, - bulkCloseIndex - ); - } - }, - [] - ); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - - const onUpdateExceptionItemsAndAlertStatus: AddOrUpdateExceptionItemsFunc = async ( - ruleStaticId, - exceptionItemsToAddOrUpdate, - alertIdToClose, - bulkCloseIndex - ) => { - const addOrUpdateItems = async ( - exceptionListItems: Array - ): Promise => { - await Promise.all( - exceptionListItems.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); - let alertIdResponse: estypes.UpdateByQueryResponse | undefined; - let bulkResponse: estypes.UpdateByQueryResponse | undefined; - if (alertIdToClose != null) { - alertIdResponse = await updateAlertStatus({ - query: getUpdateAlertsQuery([alertIdToClose]), - status: 'closed', - signal: abortCtrl.signal, - }); - } - - if (bulkCloseIndex != null) { - const alertStatusFilter = buildAlertStatusesFilter([ - 'open', - 'acknowledged', - 'in-progress', - ]); - - const exceptionsToFilter = exceptionItemsToAddOrUpdate.map((exception) => - removeIdFromExceptionItemsEntries(exception) - ); - - const filter = await getEsQueryFilter( - '', - 'kuery', - [...buildAlertsFilter(ruleStaticId), ...alertStatusFilter], - bulkCloseIndex, - prepareExceptionItemsForBulkClose(exceptionsToFilter), - false - ); - - bulkResponse = await updateAlertStatus({ - query: { - query: filter, - }, - status: 'closed', - signal: abortCtrl.signal, - }); - } - - await addOrUpdateItems(exceptionItemsToAddOrUpdate); - - // NOTE: there could be some overlap here... it's possible that the first response had conflicts - // but that the alert was closed in the second call. In this case, a conflict will be reported even - // though it was already resolved. I'm not sure that there's an easy way to solve this, but it should - // have minimal impact on the user... they'd see a warning that indicates a possible conflict, but the - // state of the alerts and their representation in the UI would be consistent. - const updated = (alertIdResponse?.updated ?? 0) + (bulkResponse?.updated ?? 0); - const conflicts = - alertIdResponse?.version_conflicts ?? 0 + (bulkResponse?.version_conflicts ?? 0); - if (isSubscribed) { - setIsLoading(false); - onSuccess(updated, conflicts); - } - } catch (error) { - if (isSubscribed) { - setIsLoading(false); - if (error.body != null) { - onError(error, error.body.status_code, error.body.message); - } else { - onError(error, null, null); - } - } - } - }; - - addOrUpdateExceptionRef.current = onUpdateExceptionItemsAndAlertStatus; - return (): void => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [addExceptionListItem, http, onSuccess, onError, updateExceptionListItem]); - - return [{ isLoading }, addOrUpdateException]; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_rule_exception.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_rule_exception.tsx new file mode 100644 index 0000000000000..c25ffda8ece14 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_rule_exception.tsx @@ -0,0 +1,72 @@ +/* + * 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 { + CreateRuleExceptionListItemSchema, + ExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { useEffect, useRef, useState } from 'react'; + +import { addRuleExceptions } from '../../rule_management/api/api'; +import type { Rule } from '../../rule_management/logic/types'; + +/** + * Adds exception items to rules default exception list + * + * @param exceptions exception items to be added + * @param ruleId `id` of rule to add exceptions to + * + */ +export type AddRuleExceptionsFunc = ( + exceptions: CreateRuleExceptionListItemSchema[], + rules: Rule[] +) => Promise; + +export type ReturnUseAddRuleException = [boolean, AddRuleExceptionsFunc | null]; + +/** + * Hook for adding exceptions to a rule default exception list + * + */ +export const useAddRuleDefaultException = (): ReturnUseAddRuleException => { + const [isLoading, setIsLoading] = useState(false); + const addRuleExceptionFunc = useRef(null); + + useEffect(() => { + const abortCtrl = new AbortController(); + + const addExceptionItemsToRule: AddRuleExceptionsFunc = async ( + exceptions: CreateRuleExceptionListItemSchema[], + rules: Rule[] + ): Promise => { + 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, + }) + ) + ); + + setIsLoading(false); + + return result.flatMap((r) => r); + }; + addRuleExceptionFunc.current = addExceptionItemsToRule; + + return (): void => { + setIsLoading(false); + abortCtrl.abort(); + }; + }, []); + + return [isLoading, addRuleExceptionFunc.current]; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_close_alerts.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_close_alerts.tsx new file mode 100644 index 0000000000000..a6dce444527d0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_close_alerts.tsx @@ -0,0 +1,133 @@ +/* + * 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 { useEffect, useRef, useState } from 'react'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { updateAlertStatus } from '../../../detections/containers/detection_engine/alerts/api'; +import { getUpdateAlertsQuery } from '../../../detections/components/alerts_table/actions'; +import { + buildAlertStatusesFilter, + buildAlertsFilter, +} from '../../../detections/components/alerts_table/default_config'; +import { getEsQueryFilter } from '../../../detections/containers/detection_engine/exceptions/get_es_query_filter'; +import type { IndexPatternArray } from '../../../../common/detection_engine/rule_schema'; +import { prepareExceptionItemsForBulkClose } from '../utils/helpers'; +import * as i18nCommon from '../../../common/translations'; +import * as i18n from './translations'; +import { useAppToasts } from '../../../common/hooks/use_app_toasts'; + +/** + * Closes alerts. + * + * @param ruleStaticIds static id of the rules (rule.ruleId, not rule.id) where the exception updates will be applied + * @param exceptionItems array of ExceptionListItemSchema to add or update + * @param alertIdToClose - optional string representing alert to close + * @param bulkCloseIndex - optional index used to create bulk close query + * + */ +export type AddOrUpdateExceptionItemsFunc = ( + ruleStaticIds: string[], + exceptionItems: ExceptionListItemSchema[], + alertIdToClose?: string, + bulkCloseIndex?: IndexPatternArray +) => Promise; + +export type ReturnUseCloseAlertsFromExceptions = [boolean, AddOrUpdateExceptionItemsFunc | null]; + +/** + * Hook for closing alerts from exceptions + */ +export const useCloseAlertsFromExceptions = (): ReturnUseCloseAlertsFromExceptions => { + const { addSuccess, addError, addWarning } = useAppToasts(); + + const [isLoading, setIsLoading] = useState(false); + const closeAlertsRef = useRef(null); + + useEffect(() => { + let isSubscribed = true; + const abortCtrl = new AbortController(); + + const onUpdateAlerts: AddOrUpdateExceptionItemsFunc = async ( + ruleStaticIds, + exceptionItems, + alertIdToClose, + bulkCloseIndex + ) => { + try { + setIsLoading(true); + let alertIdResponse: estypes.UpdateByQueryResponse | undefined; + let bulkResponse: estypes.UpdateByQueryResponse | undefined; + if (alertIdToClose != null) { + alertIdResponse = await updateAlertStatus({ + query: getUpdateAlertsQuery([alertIdToClose]), + status: 'closed', + signal: abortCtrl.signal, + }); + } + + if (bulkCloseIndex != null) { + const alertStatusFilter = buildAlertStatusesFilter([ + 'open', + 'acknowledged', + 'in-progress', + ]); + + const filter = await getEsQueryFilter( + '', + 'kuery', + [...ruleStaticIds.flatMap((id) => buildAlertsFilter(id)), ...alertStatusFilter], + bulkCloseIndex, + prepareExceptionItemsForBulkClose(exceptionItems), + false + ); + + bulkResponse = await updateAlertStatus({ + query: { + query: filter, + }, + status: 'closed', + signal: abortCtrl.signal, + }); + } + + // NOTE: there could be some overlap here... it's possible that the first response had conflicts + // but that the alert was closed in the second call. In this case, a conflict will be reported even + // though it was already resolved. I'm not sure that there's an easy way to solve this, but it should + // have minimal impact on the user... they'd see a warning that indicates a possible conflict, but the + // state of the alerts and their representation in the UI would be consistent. + const updated = (alertIdResponse?.updated ?? 0) + (bulkResponse?.updated ?? 0); + const conflicts = + alertIdResponse?.version_conflicts ?? 0 + (bulkResponse?.version_conflicts ?? 0); + if (isSubscribed) { + setIsLoading(false); + addSuccess(i18n.CLOSE_ALERTS_SUCCESS(updated)); + if (conflicts > 0) { + addWarning({ + title: i18nCommon.UPDATE_ALERT_STATUS_FAILED(conflicts), + text: i18nCommon.UPDATE_ALERT_STATUS_FAILED_DETAILED(updated, conflicts), + }); + } + } + } catch (error) { + if (isSubscribed) { + setIsLoading(false); + addError(error, { title: i18n.CLOSE_ALERTS_ERROR }); + } + } + }; + + closeAlertsRef.current = onUpdateAlerts; + return (): void => { + isSubscribed = false; + abortCtrl.abort(); + }; + }, [addSuccess, addError, addWarning]); + + return [isLoading, closeAlertsRef.current]; +}; 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 new file mode 100644 index 0000000000000..fbe9c0d46e6b3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_create_update_exception.tsx @@ -0,0 +1,68 @@ +/* + * 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 { useEffect, useRef, useState } from 'react'; +import type { + CreateExceptionListItemSchema, + ExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { useApi } from '@kbn/securitysolution-list-hooks'; + +import { formatExceptionItemForUpdate } from '../utils/helpers'; +import { useKibana } from '../../../common/lib/kibana'; + +export type CreateOrUpdateExceptionItemsFunc = ( + args: Array +) => Promise; + +export type ReturnUseCreateOrUpdateException = [boolean, CreateOrUpdateExceptionItemsFunc | null]; + +/** + * Hook for adding and/or updating an exception item + */ +export const useCreateOrUpdateException = (): ReturnUseCreateOrUpdateException => { + const { + services: { http }, + } = useKibana(); + const [isLoading, setIsLoading] = useState(false); + const addOrUpdateExceptionRef = useRef(null); + const { addExceptionListItem, updateExceptionListItem } = useApi(http); + + useEffect(() => { + 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, + }); + } + }) + ); + + setIsLoading(false); + + return itemsAdded; + }; + + addOrUpdateExceptionRef.current = onCreateOrUpdateExceptionItem; + return (): void => { + setIsLoading(false); + abortCtrl.abort(); + }; + }, [updateExceptionListItem, http, addExceptionListItem]); + + return [isLoading, addOrUpdateExceptionRef.current]; +}; 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 new file mode 100644 index 0000000000000..cec9be976592e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx @@ -0,0 +1,99 @@ +/* + * 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 { useEffect, useState, useMemo } from 'react'; +import type { DataViewBase } from '@kbn/es-query'; + +import type { Rule } from '../../rule_management/logic/types'; +import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; +import { useKibana } from '../../../common/lib/kibana'; +import { useFetchIndex } from '../../../common/containers/source'; + +export interface ReturnUseFetchExceptionFlyoutData { + isLoading: boolean; + indexPatterns: DataViewBase; +} + +/** + * Hook for fetching the fields to be used for populating the exception + * item conditions options. + * + */ +export const useFetchIndexPatterns = (rules: Rule[] | null): ReturnUseFetchExceptionFlyoutData => { + const { data } = useKibana().services; + const [dataViewLoading, setDataViewLoading] = useState(false); + const isSingleRule = useMemo(() => rules != null && rules.length === 1, [rules]); + const isMLRule = useMemo( + () => rules != null && isSingleRule && rules[0].type === 'machine_learning', + [isSingleRule, rules] + ); + // 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-default', + [isSingleRule, rules] + ); + + const memoNonDataViewIndexPatterns = useMemo( + () => + !memoDataViewId && rules != null && isSingleRule && rules[0].index != null + ? rules[0].index + : [], + [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 { loading: mlJobLoading, jobs } = useGetInstalledJob(memoMlJobIds); + + // We only want to provide a non empty array if it's an ML rule and we were able to fetch + // the index patterns, or if it's a rule not using data views. Otherwise, return an empty + // empty array to avoid making the `useFetchIndex` call + const memoRuleIndices = useMemo(() => { + if (isMLRule && jobs.length > 0) { + return jobs[0].results_index_name ? [`.ml-anomalies-${jobs[0].results_index_name}`] : []; + } else if (memoDataViewId != null) { + return []; + } else { + return memoNonDataViewIndexPatterns; + } + }, [jobs, isMLRule, memoDataViewId, memoNonDataViewIndexPatterns]); + + const [isIndexPatternLoading, { indexPatterns: indexIndexPatterns }] = + useFetchIndex(memoRuleIndices); + + // Data view logic + const [dataViewIndexPatterns, setDataViewIndexPatterns] = useState(null); + useEffect(() => { + const fetchSingleDataView = async () => { + if (memoDataViewId) { + setDataViewLoading(true); + const dv = await data.dataViews.get(memoDataViewId); + setDataViewLoading(false); + setDataViewIndexPatterns(dv); + } + }; + + fetchSingleDataView(); + }, [memoDataViewId, data.dataViews, setDataViewIndexPatterns]); + + // Determine whether to use index patterns or data views + const indexPatternsToUse = useMemo( + (): DataViewBase => + memoDataViewId && dataViewIndexPatterns != null ? dataViewIndexPatterns : indexIndexPatterns, + [memoDataViewId, dataViewIndexPatterns, indexIndexPatterns] + ); + + return { + isLoading: isIndexPatternLoading || mlJobLoading || dataViewLoading, + indexPatterns: indexPatternsToUse, + }; +}; 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 d3bc6214b28ac..c4085910faf25 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 @@ -9,10 +9,10 @@ import type { RenderHookResult } from '@testing-library/react-hooks'; import { act, renderHook } from '@testing-library/react-hooks'; import { coreMock } from '@kbn/core/public/mocks'; -import * as rulesApi from '../../../detections/containers/detection_engine/rules/api'; +import * as rulesApi from '../../rule_management/api/api'; import * as listsApi from '@kbn/securitysolution-list-api'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; -import { savedRuleMock } from '../../../detections/containers/detection_engine/rules/mock'; +import { savedRuleMock } from '../../rule_management/logic/mock'; import type { ExceptionListType, ListArray, @@ -26,7 +26,7 @@ import type { import { useFetchOrCreateRuleExceptionList } from './use_fetch_or_create_rule_exception_list'; const mockKibanaHttpService = coreMock.createStart().http; -jest.mock('../../../detections/containers/detection_engine/rules/api'); +jest.mock('../../rule_management/api/api'); jest.mock('@kbn/securitysolution-list-api'); describe('useFetchOrCreateRuleExceptionList', () => { 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 ff7883ba910cb..a42ecbf586440 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,11 +20,8 @@ import { import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import type { HttpStart } from '@kbn/core/public'; -import type { Rule } from '../../../detections/containers/detection_engine/rules/types'; -import { - fetchRuleById, - patchRule, -} from '../../../detections/containers/detection_engine/rules/api'; +import type { Rule } from '../../rule_management/logic/types'; +import { fetchRuleById, patchRule } from '../../rule_management/api/api'; export type ReturnUseFetchOrCreateRuleExceptionList = [boolean, ExceptionListSchema | null]; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_find_references.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_find_references.tsx index a051f140ec2cb..b039f32c5e17f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_find_references.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_find_references.tsx @@ -7,10 +7,10 @@ import { useEffect, useRef, useState } from 'react'; -import type { ExceptionListRuleReferencesSchema } from '../../../../common/detection_engine/schemas/response'; -import { findRuleExceptionReferences } from '../../../detections/containers/detection_engine/rules/api'; +import type { ExceptionListRuleReferencesSchema } from '../../../../common/detection_engine/rule_exceptions'; +import { findRuleExceptionReferences } from '../../rule_management/api/api'; import { useToasts } from '../../../common/lib/kibana'; -import type { FindRulesReferencedByExceptionsListProp } from '../../../detections/containers/detection_engine/rules/types'; +import type { FindRulesReferencedByExceptionsListProp } from '../../rule_management/logic/types'; import * as i18n from '../utils/translations'; export interface RuleReferences { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx index c88a7d16b6c4d..a9a43ef2e47aa 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx @@ -16,8 +16,6 @@ import { enrichNewExceptionItemsWithComments, enrichExistingExceptionItemWithComments, enrichExceptionItemsWithOS, - entryHasListType, - entryHasNonEcsType, prepareExceptionItemsForBulkClose, lowercaseHashValues, getPrepopulatedEndpointException, @@ -34,7 +32,6 @@ import type { OsTypeArray, ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import type { DataViewBase } from '@kbn/es-query'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; @@ -317,32 +314,6 @@ describe('Exception helpers', () => { }); }); - describe('#entryHasListType', () => { - test('it should return false with an empty array', () => { - const payload: ExceptionListItemSchema[] = []; - const result = entryHasListType(payload); - expect(result).toEqual(false); - }); - - test("it should return false with exception items that don't contain a list type", () => { - const payload = [getExceptionListItemSchemaMock(), getExceptionListItemSchemaMock()]; - const result = entryHasListType(payload); - expect(result).toEqual(false); - }); - - test('it should return true with exception items that do contain a list type', () => { - const payload = [ - { - ...getExceptionListItemSchemaMock(), - entries: [{ type: OperatorTypeEnum.LIST }] as EntriesArray, - }, - getExceptionListItemSchemaMock(), - ]; - const result = entryHasListType(payload); - expect(result).toEqual(true); - }); - }); - describe('#getCodeSignatureValue', () => { test('it should return empty string if code_signature nested value are undefined', () => { // Using the unsafe casting because with our types this shouldn't be possible but there have been issues with old data having undefined values in these fields @@ -354,47 +325,6 @@ describe('Exception helpers', () => { }); }); - describe('#entryHasNonEcsType', () => { - const mockEcsIndexPattern = { - title: 'testIndex', - fields: [ - { - name: 'some.parentField', - }, - { - name: 'some.not.nested.field', - }, - { - name: 'nested.field', - }, - ], - } as DataViewBase; - - test('it should return false with an empty array', () => { - const payload: ExceptionListItemSchema[] = []; - const result = entryHasNonEcsType(payload, mockEcsIndexPattern); - expect(result).toEqual(false); - }); - - test("it should return false with exception items that don't contain a non ecs type", () => { - const payload = [getExceptionListItemSchemaMock(), getExceptionListItemSchemaMock()]; - const result = entryHasNonEcsType(payload, mockEcsIndexPattern); - expect(result).toEqual(false); - }); - - test('it should return true with exception items that do contain a non ecs type', () => { - const payload = [ - { - ...getExceptionListItemSchemaMock(), - entries: [{ field: 'some.nonEcsField' }] as EntriesArray, - }, - getExceptionListItemSchemaMock(), - ]; - const result = entryHasNonEcsType(payload, mockEcsIndexPattern); - expect(result).toEqual(true); - }); - }); - describe('#prepareExceptionItemsForBulkClose', () => { test('it should return no exceptionw when passed in an empty array', () => { const payload: ExceptionListItemSchema[] = []; @@ -509,7 +439,7 @@ describe('Exception helpers', () => { test('it returns prepopulated fields with empty values', () => { const prepopulatedItem = getPrepopulatedEndpointException({ listId: 'some_id', - ruleName: 'my rule', + name: 'my rule', codeSignature: { subjectName: '', trusted: '' }, eventCode: '', alertEcsData: { ...alertDataMock, file: { path: '', hash: { sha256: '' } } }, @@ -534,7 +464,7 @@ describe('Exception helpers', () => { test('it returns prepopulated items with actual values', () => { const prepopulatedItem = getPrepopulatedEndpointException({ listId: 'some_id', - ruleName: 'my rule', + name: 'my rule', codeSignature: { subjectName: 'someSubjectName', trusted: 'false' }, eventCode: 'some-event-code', alertEcsData: alertDataMock, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.tsx index f876f11be9e3d..41d588a23763a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.tsx @@ -21,26 +21,19 @@ import type { OsTypeArray, ExceptionListType, ExceptionListItemSchema, - CreateExceptionListItemSchema, UpdateExceptionListItemSchema, ExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { - comment, - osType, - ListOperatorTypeEnum as OperatorTypeEnum, -} from '@kbn/securitysolution-io-ts-list-types'; +import { comment, osType } from '@kbn/securitysolution-io-ts-list-types'; import type { ExceptionsBuilderExceptionItem, ExceptionsBuilderReturnExceptionItem, } from '@kbn/securitysolution-list-utils'; -import { - getOperatorType, - getNewExceptionItem, - addIdToEntries, -} from '@kbn/securitysolution-list-utils'; +import { getNewExceptionItem, addIdToEntries } from '@kbn/securitysolution-list-utils'; import type { DataViewBase } from '@kbn/es-query'; +import { removeIdFromExceptionItemsEntries } from '@kbn/securitysolution-list-hooks'; + import * as i18n from './translations'; import type { AlertData, Flattened } from './types'; @@ -145,9 +138,9 @@ export const formatExceptionItemForUpdate = ( * @param exceptionItems new or existing ExceptionItem[] */ export const prepareExceptionItemsForBulkClose = ( - exceptionItems: Array -): Array => { - return exceptionItems.map((item: ExceptionListItemSchema | CreateExceptionListItemSchema) => { + exceptionItems: ExceptionListItemSchema[] +): ExceptionListItemSchema[] => { + return exceptionItems.map((item: ExceptionListItemSchema) => { if (item.entries !== undefined) { const newEntries = item.entries.map((itemEntry: Entry | EntryNested) => { return { @@ -285,17 +278,6 @@ export const lowercaseHashValues = ( }); }; -export const entryHasListType = (exceptionItems: ExceptionsBuilderReturnExceptionItem[]) => { - for (const { entries } of exceptionItems) { - for (const exceptionEntry of entries ?? []) { - if (getOperatorType(exceptionEntry) === OperatorTypeEnum.LIST) { - return true; - } - } - } - return false; -}; - /** * Returns the value for `file.Ext.code_signature` which * can be an object or array of objects @@ -377,7 +359,7 @@ function filterEmptyExceptionEntries(entries: T[]): T[ */ export const getPrepopulatedEndpointException = ({ listId, - ruleName, + name, codeSignature, eventCode, listNamespace = 'agnostic', @@ -385,7 +367,7 @@ export const getPrepopulatedEndpointException = ({ }: { listId: string; listNamespace?: NamespaceType; - ruleName: string; + name: string; codeSignature: { subjectName: string; trusted: string }; eventCode: string; alertEcsData: Flattened; @@ -449,7 +431,7 @@ export const getPrepopulatedEndpointException = ({ }; return { - ...getNewExceptionItem({ listId, namespaceType: listNamespace, ruleName }), + ...getNewExceptionItem({ listId, namespaceType: listNamespace, name }), entries: entriesToAdd(), }; }; @@ -459,7 +441,7 @@ export const getPrepopulatedEndpointException = ({ */ export const getPrepopulatedRansomwareException = ({ listId, - ruleName, + name, codeSignature, eventCode, listNamespace = 'agnostic', @@ -467,7 +449,7 @@ export const getPrepopulatedRansomwareException = ({ }: { listId: string; listNamespace?: NamespaceType; - ruleName: string; + name: string; codeSignature: { subjectName: string; trusted: string }; eventCode: string; alertEcsData: Flattened; @@ -477,7 +459,7 @@ export const getPrepopulatedRansomwareException = ({ const executable = process?.executable ?? ''; const ransomwareFeature = Ransomware?.feature ?? ''; return { - ...getNewExceptionItem({ listId, namespaceType: listNamespace, ruleName }), + ...getNewExceptionItem({ listId, namespaceType: listNamespace, name }), entries: addIdToEntries([ { field: 'process.Ext.code_signature', @@ -527,14 +509,14 @@ export const getPrepopulatedRansomwareException = ({ export const getPrepopulatedMemorySignatureException = ({ listId, - ruleName, + name, eventCode, listNamespace = 'agnostic', alertEcsData, }: { listId: string; listNamespace?: NamespaceType; - ruleName: string; + name: string; eventCode: string; alertEcsData: Flattened; }): ExceptionsBuilderExceptionItem => { @@ -566,20 +548,20 @@ export const getPrepopulatedMemorySignatureException = ({ }, ]); return { - ...getNewExceptionItem({ listId, namespaceType: listNamespace, ruleName }), + ...getNewExceptionItem({ listId, namespaceType: listNamespace, name }), entries: addIdToEntries(entries), }; }; export const getPrepopulatedMemoryShellcodeException = ({ listId, - ruleName, + name, eventCode, listNamespace = 'agnostic', alertEcsData, }: { listId: string; listNamespace?: NamespaceType; - ruleName: string; + name: string; eventCode: string; alertEcsData: Flattened; }): ExceptionsBuilderExceptionItem => { @@ -618,21 +600,21 @@ export const getPrepopulatedMemoryShellcodeException = ({ ]); return { - ...getNewExceptionItem({ listId, namespaceType: listNamespace, ruleName }), + ...getNewExceptionItem({ listId, namespaceType: listNamespace, name }), entries: addIdToEntries(entries), }; }; export const getPrepopulatedBehaviorException = ({ listId, - ruleName, + name, eventCode, listNamespace = 'agnostic', alertEcsData, }: { listId: string; listNamespace?: NamespaceType; - ruleName: string; + name: string; eventCode: string; alertEcsData: Flattened; }): ExceptionsBuilderExceptionItem => { @@ -748,47 +730,17 @@ export const getPrepopulatedBehaviorException = ({ }, ]); return { - ...getNewExceptionItem({ listId, namespaceType: listNamespace, ruleName }), + ...getNewExceptionItem({ listId, namespaceType: listNamespace, name }), entries: addIdToEntries(entries), }; }; -/** - * Determines whether or not any entries within the given exceptionItems contain values not in the specified ECS mapping - */ -export const entryHasNonEcsType = ( - exceptionItems: ExceptionsBuilderReturnExceptionItem[], - indexPatterns: DataViewBase -): boolean => { - const doesFieldNameExist = (exceptionEntry: Entry): boolean => { - return indexPatterns.fields.some(({ name }) => name === exceptionEntry.field); - }; - - if (exceptionItems.length === 0) { - return false; - } - for (const { entries } of exceptionItems) { - for (const exceptionEntry of entries ?? []) { - if (exceptionEntry.type === 'nested') { - for (const nestedExceptionEntry of exceptionEntry.entries) { - if (doesFieldNameExist(nestedExceptionEntry) === false) { - return true; - } - } - } else if (doesFieldNameExist(exceptionEntry) === false) { - return true; - } - } - } - return false; -}; - /** * Returns the default values from the alert data to autofill new endpoint exceptions */ export const defaultEndpointExceptionItems = ( listId: string, - ruleName: string, + name: string, alertEcsData: Flattened & { 'event.code'?: string } ): ExceptionsBuilderExceptionItem[] => { const eventCode = alertEcsData['event.code'] ?? alertEcsData.event?.code; @@ -798,7 +750,7 @@ export const defaultEndpointExceptionItems = ( return [ getPrepopulatedBehaviorException({ listId, - ruleName, + name, eventCode, alertEcsData, }), @@ -807,7 +759,7 @@ export const defaultEndpointExceptionItems = ( return [ getPrepopulatedMemorySignatureException({ listId, - ruleName, + name, eventCode, alertEcsData, }), @@ -816,7 +768,7 @@ export const defaultEndpointExceptionItems = ( return [ getPrepopulatedMemoryShellcodeException({ listId, - ruleName, + name, eventCode, alertEcsData, }), @@ -825,7 +777,7 @@ export const defaultEndpointExceptionItems = ( return getProcessCodeSignature(alertEcsData).map((codeSignature) => getPrepopulatedRansomwareException({ listId, - ruleName, + name, eventCode, codeSignature, alertEcsData, @@ -836,7 +788,7 @@ export const defaultEndpointExceptionItems = ( return getFileCodeSignature(alertEcsData).map((codeSignature) => getPrepopulatedEndpointException({ listId, - ruleName, + name, eventCode: eventCode ?? '', codeSignature, alertEcsData, @@ -872,7 +824,7 @@ export const enrichRuleExceptions = ( ): ExceptionsBuilderReturnExceptionItem[] => { return exceptionItems.map((item: ExceptionsBuilderReturnExceptionItem) => { return { - ...item, + ...removeIdFromExceptionItemsEntries(item), list_id: undefined, namespace_type: 'single', }; @@ -891,7 +843,7 @@ export const enrichSharedExceptions = ( return lists.flatMap((list) => { return exceptionItems.map((item) => { return { - ...item, + ...removeIdFromExceptionItemsEntries(item), list_id: list.list_id, namespace_type: list.namespace_type, }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts index 8f189c7aaf7db..012f4e677a5b2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts @@ -94,14 +94,14 @@ export const MODAL_ERROR_ACCORDION_TEXT = i18n.translate( } ); -export const DISSASOCIATE_LIST_SUCCESS = (id: string) => - i18n.translate('xpack.securitySolution.exceptions.dissasociateListSuccessText', { +export const DISASSOCIATE_LIST_SUCCESS = (id: string) => + i18n.translate('xpack.securitySolution.exceptions.disassociateListSuccessText', { values: { id }, defaultMessage: 'Exception list ({id}) has successfully been removed', }); -export const DISSASOCIATE_EXCEPTION_LIST_ERROR = i18n.translate( - 'xpack.securitySolution.exceptions.dissasociateExceptionListError', +export const DISASSOCIATE_EXCEPTION_LIST_ERROR = i18n.translate( + 'xpack.securitySolution.exceptions.disassociateExceptionListError', { defaultMessage: 'Failed to remove exception list', } diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/columns.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/columns.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/columns.tsx index 2257d9b79905c..4b196968de008 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/columns.tsx @@ -10,12 +10,12 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; -import { DEFAULT_RELATIVE_DATE_THRESHOLD } from '../../../../../../../common/constants'; -import type { FormatUrl } from '../../../../../../common/components/link_to'; -import { PopoverItems } from '../../../../../../common/components/popover_items'; -import { FormattedRelativePreferenceDate } from '../../../../../../common/components/formatted_date'; -import { getRuleDetailsUrl } from '../../../../../../common/components/link_to/redirect_to_detection_engine'; -import { LinkAnchor } from '../../../../../../common/components/links'; +import { DEFAULT_RELATIVE_DATE_THRESHOLD } from '../../../../../common/constants'; +import type { FormatUrl } from '../../../../common/components/link_to'; +import { PopoverItems } from '../../../../common/components/popover_items'; +import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; +import { getRuleDetailsUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; +import { LinkAnchor } from '../../../../common/components/links'; import * as i18n from './translations'; import type { ExceptionListInfo } from './use_all_exception_lists'; import type { ExceptionsTableItem } from './types'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_search_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_search_bar.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_search_bar.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_search_bar.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table.test.tsx similarity index 89% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table.test.tsx index 5c1300ce377a2..c443968c14015 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table.test.tsx @@ -8,18 +8,18 @@ import React from 'react'; import { mount } from 'enzyme'; -import { TestProviders } from '../../../../../../common/mock'; +import { TestProviders } from '../../../../common/mock'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; -import { useUserData } from '../../../../../components/user_info'; +import { useUserData } from '../../../../detections/components/user_info'; import { ExceptionListsTable } from './exceptions_table'; import { useApi, useExceptionLists } from '@kbn/securitysolution-list-hooks'; import { useAllExceptionLists } from './use_all_exception_lists'; import { useHistory } from 'react-router-dom'; -import { generateHistoryMock } from '../../../../../../common/utils/route/mocks'; +import { generateHistoryMock } from '../../../../common/utils/route/mocks'; -jest.mock('../../../../../components/user_info'); -jest.mock('../../../../../../common/lib/kibana'); +jest.mock('../../../../detections/components/user_info'); +jest.mock('../../../../common/lib/kibana'); jest.mock('./use_all_exception_lists'); jest.mock('@kbn/securitysolution-list-hooks'); jest.mock('react-router-dom', () => { @@ -39,7 +39,7 @@ jest.mock('@kbn/i18n-react', () => { }; }); -jest.mock('../../../../../containers/detection_engine/lists/use_lists_config', () => ({ +jest.mock('../../../../detections/containers/detection_engine/lists/use_lists_config', () => ({ useListsConfig: jest.fn().mockReturnValue({ loading: false }), })); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table.tsx index d7908d0bbce66..b2d3d078abb54 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table.tsx @@ -19,28 +19,29 @@ import { import type { NamespaceType, ExceptionListFilter } from '@kbn/securitysolution-io-ts-list-types'; import { useApi, useExceptionLists } from '@kbn/securitysolution-list-hooks'; -import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; -import { AutoDownload } from '../../../../../../common/components/auto_download/auto_download'; -import { useKibana } from '../../../../../../common/lib/kibana'; -import { useFormatUrl } from '../../../../../../common/components/link_to'; -import { Loader } from '../../../../../../common/components/loader'; + +import { AutoDownload } from '../../../../common/components/auto_download/auto_download'; +import { useFormatUrl } from '../../../../common/components/link_to'; +import { Loader } from '../../../../common/components/loader'; +import { useKibana } from '../../../../common/lib/kibana'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; import * as i18n from './translations'; import { ExceptionsTableUtilityBar } from './exceptions_table_utility_bar'; import type { AllExceptionListsColumns } from './columns'; import { getAllExceptionListsColumns } from './columns'; import { useAllExceptionLists } from './use_all_exception_lists'; -import { ReferenceErrorModal } from '../../../../../components/value_lists_management_flyout/reference_error_modal'; -import { patchRule } from '../../../../../containers/detection_engine/rules/api'; +import { ReferenceErrorModal } from '../../../../detections/components/value_lists_management_flyout/reference_error_modal'; +import { patchRule } from '../../../rule_management/api/api'; import { ExceptionsSearchBar } from './exceptions_search_bar'; -import { getSearchFilters } from '../helpers'; -import { SecurityPageName } from '../../../../../../../common/constants'; -import { useUserData } from '../../../../../components/user_info'; -import { userHasPermissions } from '../../helpers'; -import { useListsConfig } from '../../../../../containers/detection_engine/lists/use_lists_config'; +import { getSearchFilters } from '../../../rule_management_ui/components/rules_table/helpers'; +import { SecurityPageName } from '../../../../../common/constants'; +import { useUserData } from '../../../../detections/components/user_info'; +import { useListsConfig } from '../../../../detections/containers/detection_engine/lists/use_lists_config'; import type { ExceptionsTableItem } from './types'; -import { MissingPrivilegesCallOut } from '../../../../../components/callouts/missing_privileges_callout'; -import { ALL_ENDPOINT_ARTIFACT_LIST_IDS } from '../../../../../../../common/endpoint/service/artifacts/constants'; +import { MissingPrivilegesCallOut } from '../../../../detections/components/callouts/missing_privileges_callout'; +import { ALL_ENDPOINT_ARTIFACT_LIST_IDS } from '../../../../../common/endpoint/service/artifacts/constants'; export type Func = () => Promise; @@ -63,7 +64,7 @@ const exceptionReferenceModalInitialState: ReferenceModalState = { export const ExceptionListsTable = React.memo(() => { const { formatUrl } = useFormatUrl(SecurityPageName.rules); const [{ loading: userInfoLoading, canUserCRUD, canUserREAD }] = useUserData(); - const hasPermissions = userHasPermissions(canUserCRUD); + const hasPermissions = hasUserCRUDPermission(canUserCRUD); const { loading: listsConfigLoading } = useListsConfig(); const loading = userInfoLoading || listsConfigLoading; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table_utility_bar.test.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table_utility_bar.test.tsx index d2bf2b8547f68..f40e0d66cb492 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table_utility_bar.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { TestProviders } from '../../../../../../common/mock'; +import { TestProviders } from '../../../../common/mock'; import { render, screen, within } from '@testing-library/react'; import { ExceptionsTableUtilityBar } from './exceptions_table_utility_bar'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table_utility_bar.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table_utility_bar.tsx index 062b4b0fef8f9..98ac0bf25d8ec 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table_utility_bar.tsx @@ -13,7 +13,7 @@ import { UtilityBarGroup, UtilityBarSection, UtilityBarText, -} from '../../../../../../common/components/utility_bar'; +} from '../../../../common/components/utility_bar'; import * as i18n from './translations'; interface ExceptionsTableUtilityBarProps { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/translations.ts diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/types.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/types.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/types.ts diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/use_all_exception_lists.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/use_all_exception_lists.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/use_all_exception_lists.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/use_all_exception_lists.tsx index f48de2459fea7..cd77e72722132 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/use_all_exception_lists.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions_ui/pages/exceptions/use_all_exception_lists.tsx @@ -8,8 +8,8 @@ import { useCallback, useEffect, useState } from 'react'; import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; -import type { Rule } from '../../../../../containers/detection_engine/rules'; -import { fetchRules } from '../../../../../containers/detection_engine/rules/api'; +import type { Rule } from '../../../rule_management/logic'; +import { fetchRules } from '../../../rule_management/api/api'; export interface ExceptionListInfo extends ExceptionListSchema { rules: Rule[]; } diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/__mocks__/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/__mocks__/api.ts similarity index 56% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/__mocks__/api.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/api/__mocks__/api.ts index e445e5b935af2..e02e0c83dfe70 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/__mocks__/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/__mocks__/api.ts @@ -5,11 +5,9 @@ * 2.0. */ -import type { FullResponseSchema } from '../../../../../../common/detection_engine/schemas/request'; -import type { GetInstalledIntegrationsResponse } from '../../../../../../common/detection_engine/schemas/response'; - -import { getRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import { savedRuleMock, rulesMock } from '../mock'; +import type { RuleResponse } from '../../../../../common/detection_engine/rule_schema'; +import { getRulesSchemaMock } from '../../../../../common/detection_engine/rule_schema/mocks'; +import { savedRuleMock, rulesMock } from '../../logic/mock'; import type { PatchRuleProps, @@ -21,18 +19,18 @@ import type { FetchRuleProps, FetchRulesResponse, FetchRulesProps, -} from '../types'; +} from '../../logic/types'; -export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise => +export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise => Promise.resolve(getRulesSchemaMock()); -export const createRule = async ({ rule, signal }: CreateRulesProps): Promise => +export const createRule = async ({ rule, signal }: CreateRulesProps): Promise => Promise.resolve(getRulesSchemaMock()); export const patchRule = async ({ ruleProperties, signal, -}: PatchRuleProps): Promise => Promise.resolve(getRulesSchemaMock()); +}: PatchRuleProps): Promise => Promise.resolve(getRulesSchemaMock()); export const getPrePackagedRulesStatus = async ({ signal, @@ -62,30 +60,4 @@ export const fetchRules = async (_: FetchRulesProps): Promise => Promise.resolve(['elastic', 'love', 'quality', 'code']); -// do not delete -export const fetchInstalledIntegrations = async ({ - packages, - signal, -}: { - packages?: string[]; - signal?: AbortSignal; -}): Promise => { - return Promise.resolve({ - installed_integrations: [ - { - package_name: 'atlassian_bitbucket', - package_title: 'Atlassian Bitbucket', - package_version: '1.0.1', - integration_name: 'audit', - integration_title: 'Audit Logs', - is_enabled: true, - }, - { - package_name: 'system', - package_title: 'System', - package_version: '1.6.4', - is_enabled: true, - }, - ], - }); -}; +export const performBulkAction = jest.fn(); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts similarity index 97% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts index 2511e8da834f0..ca84045e06c65 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts @@ -6,7 +6,18 @@ */ import { buildEsQuery } from '@kbn/es-query'; -import { KibanaServices } from '../../../../common/lib/kibana'; +import { KibanaServices } from '../../../common/lib/kibana'; + +import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '../../../../common/detection_engine/rule_exceptions'; +import { getPatchRulesSchemaMock } from '../../../../common/detection_engine/rule_management/mocks'; +import { + getCreateRulesSchemaMock, + getUpdateRulesSchemaMock, + getRulesSchemaMock, +} from '../../../../common/detection_engine/rule_schema/mocks'; + +import { rulesMock } from '../logic/mock'; +import type { FindRulesReferencedByExceptionsListProp } from '../logic/types'; import { createRule, @@ -22,19 +33,10 @@ import { previewRule, findRuleExceptionReferences, } from './api'; -import { getRulesSchemaMock } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import { - getCreateRulesSchemaMock, - getUpdateRulesSchemaMock, -} from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { getPatchRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/patch_rules_schema.mock'; -import { rulesMock } from './mock'; -import type { FindRulesReferencedByExceptionsListProp } from './types'; -import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '../../../../../common/constants'; const abortCtrl = new AbortController(); const mockKibanaServices = KibanaServices.get as jest.Mock; -jest.mock('../../../../common/lib/kibana'); +jest.mock('../../../common/lib/kibana'); const fetchMock = jest.fn(); mockKibanaServices.mockReturnValue({ http: { fetch: fetchMock } }); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts similarity index 64% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index 1a1238c36ca34..3fd5fd65bb639 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -6,60 +6,65 @@ */ import { camelCase } from 'lodash'; -import type { HttpStart } from '@kbn/core/public'; +import type { + CreateRuleExceptionListItemSchema, + ExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import type { BulkActionsDryRunErrCode } from '../../../../common/constants'; import { - DETECTION_ENGINE_RULES_URL, - DETECTION_ENGINE_PREPACKAGED_URL, - DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL, - DETECTION_ENGINE_TAGS_URL, DETECTION_ENGINE_RULES_BULK_ACTION, DETECTION_ENGINE_RULES_PREVIEW, - DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL, + DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_RULES_URL_FIND, - DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL, -} from '../../../../../common/constants'; -import type { BulkAction } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; + DETECTION_ENGINE_TAGS_URL, +} from '../../../../common/constants'; + +import { + PREBUILT_RULES_STATUS_URL, + PREBUILT_RULES_URL, +} from '../../../../common/detection_engine/prebuilt_rules'; + +import type { RulesReferencedByExceptionListsSchema } from '../../../../common/detection_engine/rule_exceptions'; +import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '../../../../common/detection_engine/rule_exceptions'; + +import type { BulkActionEditPayload } from '../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkAction } from '../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; + import type { - FullResponseSchema, + RuleResponse, PreviewResponse, -} from '../../../../../common/detection_engine/schemas/request'; -import type { - GetInstalledIntegrationsResponse, - RulesReferencedByExceptionListsSchema, -} from '../../../../../common/detection_engine/schemas/response'; +} from '../../../../common/detection_engine/rule_schema'; +import { KibanaServices } from '../../../common/lib/kibana'; +import * as i18n from '../../../detections/pages/detection_engine/rules/translations'; import type { - UpdateRulesProps, CreateRulesProps, + ExportDocumentsProps, + FetchRuleProps, FetchRulesProps, FetchRulesResponse, - Rule, - FetchRuleProps, + FindRulesReferencedByExceptionsProps, ImportDataProps, - ExportDocumentsProps, ImportDataResponse, - PrePackagedRulesStatusResponse, PatchRuleProps, - BulkActionProps, - BulkActionResponseMap, + PrePackagedRulesStatusResponse, PreviewRulesProps, - FindRulesReferencedByExceptionsProps, -} from './types'; -import { KibanaServices } from '../../../../common/lib/kibana'; -import * as i18n from '../../../pages/detection_engine/rules/translations'; -import { convertRulesFilterToKQL } from './utils'; + Rule, + UpdateRulesProps, +} from '../logic/types'; +import { convertRulesFilterToKQL } from '../logic/utils'; /** * Create provided Rule * - * @param rule CreateRulesSchema to add + * @param rule RuleCreateProps to add * @param signal to cancel request * * @throws An error if response is not OK */ -export const createRule = async ({ rule, signal }: CreateRulesProps): Promise => - KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { +export const createRule = async ({ rule, signal }: CreateRulesProps): Promise => + KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { method: 'POST', body: JSON.stringify(rule), signal, @@ -68,13 +73,13 @@ export const createRule = async ({ rule, signal }: CreateRulesProps): 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', body: JSON.stringify(rule), signal, @@ -94,8 +99,8 @@ export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise => - KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { +}: PatchRuleProps): Promise => + KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { method: 'PATCH', body: JSON.stringify(ruleProperties), signal, @@ -104,7 +109,7 @@ export const patchRule = async ({ /** * Preview provided Rule * - * @param rule CreateRulesSchema to add + * @param rule RuleCreateProps to add * @param signal to cancel request * * @throws An error if response is not OK @@ -173,28 +178,49 @@ export const fetchRules = async ({ * @throws An error if response is not OK */ export const fetchRuleById = async ({ id, signal }: FetchRuleProps): Promise => - pureFetchRuleById({ id, http: KibanaServices.get().http, signal }); - -/** - * Fetch a Rule by providing a Rule ID - * - * @param id Rule ID's (not rule_id) - * @param http Kibana http service - * @param signal to cancel request - * - * @throws An error if response is not OK - */ -export const pureFetchRuleById = async ({ - id, - http, - signal, -}: FetchRuleProps & { http: HttpStart }): Promise => - http.fetch(DETECTION_ENGINE_RULES_URL, { + KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { method: 'GET', query: { id }, signal, }); +export interface BulkActionSummary { + failed: number; + succeeded: number; + total: number; +} + +export interface BulkActionResult { + updated: Rule[]; + created: Rule[]; + deleted: Rule[]; +} + +export interface BulkActionAggregatedError { + message: string; + status_code: number; + err_code?: BulkActionsDryRunErrCode; + rules: Array<{ id: string; name?: string }>; +} + +export interface BulkActionResponse { + success?: boolean; + rules_count?: number; + attributes: { + summary: BulkActionSummary; + results: BulkActionResult; + errors?: BulkActionAggregatedError[]; + }; +} + +export interface BulkActionProps { + action: Exclude; + query?: string; + ids?: string[]; + edit?: BulkActionEditPayload[]; + isDryRun?: boolean; +} + /** * Perform bulk action with rules selected by a filter query * @@ -206,48 +232,75 @@ export const pureFetchRuleById = async ({ * * @throws An error if response is not OK */ -export const performBulkAction = async ({ +export const performBulkAction = async ({ action, query, edit, ids, isDryRun, -}: BulkActionProps): Promise> => - KibanaServices.get().http.fetch>( - DETECTION_ENGINE_RULES_BULK_ACTION, - { - method: 'POST', - body: JSON.stringify({ - action, - ...(edit ? { edit } : {}), - ...(ids ? { ids } : {}), - ...(query !== undefined ? { query } : {}), - }), - query: { - ...(isDryRun ? { dry_run: isDryRun } : {}), - }, - } - ); +}: BulkActionProps): Promise => + KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_BULK_ACTION, { + method: 'POST', + body: JSON.stringify({ + action, + ...(edit ? { edit } : {}), + ...(ids ? { ids } : {}), + ...(query !== undefined ? { query } : {}), + }), + query: { + ...(isDryRun ? { dry_run: isDryRun } : {}), + }, + }); + +export interface BulkExportProps { + query?: string; + ids?: string[]; +} + +export type BulkExportResponse = Blob; /** - * Create Prepackaged Rules + * Bulk export rules selected by a filter query * - * @param signal AbortSignal for cancelling request + * @param query filter query to select rules to perform bulk action with + * @param ids string[] rule ids to select rules to perform bulk action with * * @throws An error if response is not OK */ -export const createPrepackagedRules = async (): Promise<{ +export const bulkExportRules = async ({ + query, + ids, +}: BulkExportProps): Promise => + KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_BULK_ACTION, { + method: 'POST', + body: JSON.stringify({ + action: BulkAction.export, + ...(ids ? { ids } : {}), + ...(query !== undefined ? { query } : {}), + }), + }); + +export interface CreatePrepackagedRulesResponse { rules_installed: number; rules_updated: number; timelines_installed: number; timelines_updated: number; -}> => { +} + +/** + * Create Prepackaged Rules + * + * @param signal AbortSignal for cancelling request + * + * @throws An error if response is not OK + */ +export const createPrepackagedRules = async (): Promise => { const result = await KibanaServices.get().http.fetch<{ rules_installed: number; rules_updated: number; timelines_installed: number; timelines_updated: number; - }>(DETECTION_ENGINE_PREPACKAGED_URL, { + }>(PREBUILT_RULES_URL, { method: 'PUT', }); @@ -316,6 +369,8 @@ export const exportRules = async ({ }); }; +export type FetchTagsResponse = string[]; + /** * Fetch all unique Tags used by Rules * @@ -323,8 +378,8 @@ export const exportRules = async ({ * * @throws An error if response is not OK */ -export const fetchTags = async ({ signal }: { signal: AbortSignal }): Promise => - KibanaServices.get().http.fetch(DETECTION_ENGINE_TAGS_URL, { +export const fetchTags = async ({ signal }: { signal?: AbortSignal }): Promise => + KibanaServices.get().http.fetch(DETECTION_ENGINE_TAGS_URL, { method: 'GET', signal, }); @@ -341,39 +396,10 @@ export const getPrePackagedRulesStatus = async ({ }: { signal: AbortSignal | undefined; }): Promise => - KibanaServices.get().http.fetch( - DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL, - { - method: 'GET', - signal, - } - ); - -/** - * Fetch all installed integrations - * - * @param packages array of packages to filter for - * @param signal to cancel request - * - * @throws An error if response is not OK - */ -export const fetchInstalledIntegrations = async ({ - packages, - signal, -}: { - packages?: string[]; - signal?: AbortSignal; -}): Promise => - KibanaServices.get().http.fetch( - DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL, - { - method: 'GET', - query: { - packages: packages?.sort()?.join(','), - }, - signal, - } - ); + KibanaServices.get().http.fetch(PREBUILT_RULES_STATUS_URL, { + method: 'GET', + signal, + }); /** * Fetch info on what exceptions lists are referenced by what rules @@ -406,3 +432,30 @@ export const findRuleExceptionReferences = async ({ } ); }; + +/** + * Add exception items to default rule exception list + * + * @param ruleId `id` of rule to add items to + * @param items CreateRuleExceptionListItemSchema[] + * @param signal to cancel request + * + * @throws An error if response is not OK + */ +export const addRuleExceptions = async ({ + ruleId, + items, + signal, +}: { + ruleId: string; + items: CreateRuleExceptionListItemSchema[]; + signal: AbortSignal | undefined; +}): Promise => + KibanaServices.get().http.fetch( + `${DETECTION_ENGINE_RULES_URL}/${ruleId}/exceptions`, + { + method: 'POST', + body: JSON.stringify({ items }), + signal, + } + ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/__mocks__/mock_react_query_response.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/__mocks__/mock_react_query_response.ts new file mode 100644 index 0000000000000..8a5728bac5462 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/__mocks__/mock_react_query_response.ts @@ -0,0 +1,35 @@ +/* + * 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 { UseQueryResult } from '@tanstack/react-query'; + +export const mockReactQueryResponse = (result: Partial>) => ({ + isLoading: false, + error: null, + isError: false, + isLoadingError: false, + isRefetchError: false, + isSuccess: true, + status: 'success', + dataUpdatedAt: 0, + errorUpdatedAt: 0, + failureCount: 0, + errorUpdateCount: 0, + isFetched: true, + isFetchedAfterMount: true, + isFetching: false, + isPaused: false, + isPlaceholderData: false, + isPreviousData: false, + isRefetching: false, + isStale: false, + refetch: jest.fn(), + remove: jest.fn(), + fetchStatus: 'idle', + data: undefined, + ...result, +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/__mocks__/use_prebuilt_rules_status_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/__mocks__/use_prebuilt_rules_status_query.ts new file mode 100644 index 0000000000000..ea8c6b53a35b5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/__mocks__/use_prebuilt_rules_status_query.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 type { PrePackagedRulesStatusResponse } from '../../../logic'; +import { mockReactQueryResponse } from './mock_react_query_response'; + +export const usePrebuiltRulesStatusQuery = jest.fn(() => + mockReactQueryResponse({ + data: { + rules_custom_installed: 0, + rules_installed: 0, + rules_not_installed: 0, + rules_not_updated: 0, + timelines_installed: 0, + timelines_not_installed: 0, + timelines_not_updated: 0, + }, + }) +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/constants.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/constants.ts new file mode 100644 index 0000000000000..61e0d1e05f7f0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/constants.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. + */ + +const ONE_MINUTE = 60000; + +export const DEFAULT_QUERY_OPTIONS = { + refetchIntervalInBackground: false, + staleTime: ONE_MINUTE * 5, +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts new file mode 100644 index 0000000000000..e52a5cd8e0618 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -0,0 +1,63 @@ +/* + * 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 { UseMutationOptions } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; +import { BulkAction } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { BulkActionProps, BulkActionResponse } from '../api'; +import { performBulkAction } from '../api'; +import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; +import { useInvalidateFindRulesQuery, useUpdateRulesCache } from './use_find_rules_query'; +import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; +import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; + +export const useBulkActionMutation = ( + options?: UseMutationOptions +) => { + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); + const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); + const updateRulesCache = useUpdateRulesCache(); + + return useMutation( + (action: BulkActionProps) => performBulkAction(action), + { + ...options, + onSuccess: (...args) => { + const [res, { action }] = args; + switch (action) { + case BulkAction.enable: + case BulkAction.disable: { + invalidateFetchRuleByIdQuery(); + // This action doesn't affect rule content, no need for invalidation + updateRulesCache(res?.attributes?.results?.updated ?? []); + break; + } + case BulkAction.delete: + invalidateFindRulesQuery(); + invalidateFetchRuleByIdQuery(); + invalidateFetchTagsQuery(); + invalidateFetchPrebuiltRulesStatusQuery(); + break; + case BulkAction.duplicate: + invalidateFindRulesQuery(); + invalidateFetchPrebuiltRulesStatusQuery(); + break; + case BulkAction.edit: + updateRulesCache(res?.attributes?.results?.updated ?? []); + invalidateFetchRuleByIdQuery(); + invalidateFetchTagsQuery(); + break; + } + + if (options?.onSuccess) { + options.onSuccess(...args); + } + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_export_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_export_mutation.ts new file mode 100644 index 0000000000000..bcc5fbcdbb18e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_export_mutation.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 type { UseMutationOptions } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; +import type { BulkExportProps, BulkExportResponse } from '../api'; +import { bulkExportRules } from '../api'; + +export const useBulkExportMutation = ( + options?: UseMutationOptions +) => { + return useMutation( + (action: BulkExportProps) => bulkExportRules(action), + options + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts new file mode 100644 index 0000000000000..2559be0609d08 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts @@ -0,0 +1,36 @@ +/* + * 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 { UseMutationOptions } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; +import type { CreatePrepackagedRulesResponse } from '../api'; +import { createPrepackagedRules } from '../api'; +import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; +import { useInvalidateFindRulesQuery } from './use_find_rules_query'; +import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; + +export const useCreatePrebuiltRulesMutation = ( + options?: UseMutationOptions +) => { + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); + const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + + return useMutation(() => createPrepackagedRules(), { + ...options, + onSuccess: (...args) => { + // Always invalidate all rules and the prepackaged rules status cache as + // the number of rules might change after the installation + invalidatePrePackagedRulesStatus(); + invalidateFindRulesQuery(); + invalidateFetchTagsQuery(); + + if (options?.onSuccess) { + options.onSuccess(...args); + } + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts new file mode 100644 index 0000000000000..8d62927a6261f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { UseMutationOptions } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; +import type { + RuleCreateProps, + RuleResponse, +} from '../../../../../common/detection_engine/rule_schema'; +import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; +import { createRule } from '../api'; +import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; +import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; +import { useInvalidateFindRulesQuery } from './use_find_rules_query'; + +export const useCreateRuleMutation = ( + options?: UseMutationOptions +) => { + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + const invalidateFetchPrePackagedRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); + + return useMutation( + (rule: RuleCreateProps) => createRule({ rule: transformOutput(rule) }), + { + ...options, + onSuccess: (...args) => { + invalidateFetchPrePackagedRulesStatusQuery(); + invalidateFindRulesQuery(); + invalidateFetchTagsQuery(); + + if (options?.onSuccess) { + options.onSuccess(...args); + } + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_prebuilt_rules_status_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_prebuilt_rules_status_query.ts new file mode 100644 index 0000000000000..a0344386ffe04 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_prebuilt_rules_status_query.ts @@ -0,0 +1,47 @@ +/* + * 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 { useCallback } from 'react'; +import type { UseQueryOptions } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { getPrePackagedRulesStatus } from '../api'; +import { DEFAULT_QUERY_OPTIONS } from './constants'; +import type { PrePackagedRulesStatusResponse } from '../../logic'; + +export const PREBUILT_RULES_STATUS_QUERY_KEY = 'prePackagedRulesStatus'; + +export const useFetchPrebuiltRulesStatusQuery = ( + options: UseQueryOptions +) => { + return useQuery( + [PREBUILT_RULES_STATUS_QUERY_KEY], + async ({ signal }) => { + const response = await getPrePackagedRulesStatus({ signal }); + return response; + }, + { + ...DEFAULT_QUERY_OPTIONS, + ...options, + } + ); +}; + +/** + * We should use this hook to invalidate the prepackaged rules cache. For + * example, rule mutations that affect rule set size, like creation or deletion, + * should lead to cache invalidation. + * + * @returns A rules cache invalidation callback + */ +export const useInvalidateFetchPrebuiltRulesStatusQuery = () => { + const queryClient = useQueryClient(); + + return useCallback(() => { + queryClient.invalidateQueries([PREBUILT_RULES_STATUS_QUERY_KEY], { + refetchType: 'active', + }); + }, [queryClient]); +}; 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 new file mode 100644 index 0000000000000..03fe7c6e2df17 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts @@ -0,0 +1,56 @@ +/* + * 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 { UseQueryOptions } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useCallback } from 'react'; +import { transformInput } from '../../../../detections/containers/detection_engine/rules/transforms'; +import type { Rule } from '../../logic'; +import { fetchRuleById } from '../api'; +import { DEFAULT_QUERY_OPTIONS } from './constants'; + +const FIND_ONE_RULE_QUERY_KEY = 'findOneRule'; + +/** + * A wrapper around useQuery provides default values to the underlying query, + * like query key, abortion signal, and error handler. + * + * @param id - rule's id, not rule_id + * @param options - react-query options + * @returns useQuery result + */ +export const useFetchRuleByIdQuery = (id: string, options: UseQueryOptions) => { + return useQuery( + [FIND_ONE_RULE_QUERY_KEY, id], + async ({ signal }) => { + const response = await fetchRuleById({ signal, id }); + + return transformInput(response); + }, + { + ...DEFAULT_QUERY_OPTIONS, + ...options, + } + ); +}; + +/** + * We should use this hook to invalidate the rules cache. For example, rule + * mutations that affect rule set size, like creation or deletion, should lead + * to cache invalidation. + * + * @returns A rules cache invalidation callback + */ +export const useInvalidateFetchRuleByIdQuery = () => { + const queryClient = useQueryClient(); + + return useCallback(() => { + queryClient.invalidateQueries([FIND_ONE_RULE_QUERY_KEY], { + refetchType: 'active', + }); + }, [queryClient]); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_tags_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_tags_query.ts new file mode 100644 index 0000000000000..1be43f992f07f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_tags_query.ts @@ -0,0 +1,43 @@ +/* + * 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 { UseQueryOptions } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useCallback } from 'react'; +import type { FetchTagsResponse } from '../api'; +import { fetchTags } from '../api'; +import { DEFAULT_QUERY_OPTIONS } from './constants'; + +// TODO: https://github.com/elastic/kibana/pull/142950 Let's use more detailed cache keys, e.g. ['GET', DETECTION_ENGINE_TAGS_URL] +const TAGS_QUERY_KEY = 'tags'; + +/** + * Hook for using the list of Tags from the Detection Engine API + * + */ +export const useFetchTagsQuery = (options?: UseQueryOptions) => { + return useQuery( + [TAGS_QUERY_KEY], + async ({ signal }) => { + return fetchTags({ signal }); + }, + { + ...DEFAULT_QUERY_OPTIONS, + ...options, + } + ); +}; + +export const useInvalidateFetchTagsQuery = () => { + const queryClient = useQueryClient(); + + return useCallback(() => { + queryClient.invalidateQueries([TAGS_QUERY_KEY], { + refetchType: 'active', + }); + }, [queryClient]); +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_find_rules_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_find_rules_query.ts similarity index 85% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_find_rules_query.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_find_rules_query.ts index 523a05012ca19..ad50ab471a7fd 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_find_rules_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_find_rules_query.ts @@ -5,13 +5,12 @@ * 2.0. */ -import { useCallback } from 'react'; import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { fetchRules } from './api'; -import * as i18n from './translations'; -import type { FilterOptions, PaginationOptions, Rule, SortingOptions } from './types'; +import { useCallback } from 'react'; +import type { FilterOptions, PaginationOptions, Rule, SortingOptions } from '../../logic'; +import { fetchRules } from '../api'; +import { DEFAULT_QUERY_OPTIONS } from './constants'; export interface FindRulesQueryArgs { filterOptions?: FilterOptions; @@ -21,14 +20,14 @@ export interface FindRulesQueryArgs { const FIND_RULES_QUERY_KEY = 'findRules'; -export interface RulesQueryData { +export interface RulesQueryResponse { rules: Rule[]; total: number; } /** * A wrapper around useQuery provides default values to the underlying query, - * like query key, abortion signal, and error handler. + * like query key, abortion signal. * * @param queryPrefix - query prefix used to differentiate the query from other * findRules queries @@ -37,27 +36,23 @@ export interface RulesQueryData { * @returns useQuery result */ export const useFindRulesQuery = ( - queryPrefix: string[], queryArgs: FindRulesQueryArgs, queryOptions: UseQueryOptions< - RulesQueryData, + RulesQueryResponse, Error, - RulesQueryData, + RulesQueryResponse, [...string[], FindRulesQueryArgs] > ) => { - const { addError } = useAppToasts(); - return useQuery( - [FIND_RULES_QUERY_KEY, ...queryPrefix, queryArgs], + [FIND_RULES_QUERY_KEY, queryArgs], async ({ signal }) => { const response = await fetchRules({ signal, ...queryArgs }); return { rules: response.data, total: response.total }; }, { - refetchIntervalInBackground: false, - onError: (error: Error) => addError(error, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }), + ...DEFAULT_QUERY_OPTIONS, ...queryOptions, } ); @@ -70,7 +65,7 @@ export const useFindRulesQuery = ( * * @returns A rules cache invalidation callback */ -export const useInvalidateRules = () => { +export const useInvalidateFindRulesQuery = () => { const queryClient = useQueryClient(); return useCallback(() => { 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 new file mode 100644 index 0000000000000..6f15fb4fdd8ce --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { UseMutationOptions } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; +import type { + RuleResponse, + RuleUpdateProps, +} from '../../../../../common/detection_engine/rule_schema'; +import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; +import { updateRule } from '../api'; +import { useInvalidateFindRulesQuery } from './use_find_rules_query'; +import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; +import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; + +export const useUpdateRuleMutation = ( + options?: UseMutationOptions +) => { + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); + + return useMutation( + (rule: RuleUpdateProps) => updateRule({ rule: transformOutput(rule) }), + { + ...options, + onSuccess: (...args) => { + invalidateFindRulesQuery(); + invalidateFetchRuleByIdQuery(); + invalidateFetchTagsQuery(); + + if (options?.onSuccess) { + options.onSuccess(...args); + } + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/__mocks__/use_bulk_export.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/__mocks__/use_bulk_export.ts new file mode 100644 index 0000000000000..c72ba1fab45f9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/__mocks__/use_bulk_export.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export const useBulkExport = jest.fn(() => ({ + bulkExport: jest.fn(), +})); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/__mocks__/use_execute_bulk_action.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/__mocks__/use_execute_bulk_action.ts new file mode 100644 index 0000000000000..8e8ad47288027 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/__mocks__/use_execute_bulk_action.ts @@ -0,0 +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. + */ + +export const useExecuteBulkAction = jest.fn(() => ({ + executeBulkAction: jest.fn(), +})); + +export const goToRuleEditPage = jest.fn(); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/translations.ts new file mode 100644 index 0000000000000..314811d0b142d --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/translations.ts @@ -0,0 +1,106 @@ +/* + * 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 { ErrorToastOptions } from '@kbn/core-notifications-browser'; +import { BulkAction } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; +import type { BulkActionSummary } from '../../api/api'; + +export function getErrorToastContent( + action: BulkAction, + summary: BulkActionSummary +): ErrorToastOptions { + let title: string; + let toastMessage: string | undefined; + + switch (action) { + case BulkAction.export: + title = i18n.RULES_BULK_EXPORT_FAILURE; + if (summary) { + toastMessage = i18n.RULES_BULK_EXPORT_FAILURE_DESCRIPTION(summary.failed); + } + break; + case BulkAction.duplicate: + title = i18n.RULES_BULK_DUPLICATE_FAILURE; + if (summary) { + toastMessage = i18n.RULES_BULK_DUPLICATE_FAILURE_DESCRIPTION(summary.failed); + } + break; + case BulkAction.delete: + title = i18n.RULES_BULK_DELETE_FAILURE; + if (summary) { + toastMessage = i18n.RULES_BULK_DELETE_FAILURE_DESCRIPTION(summary.failed); + } + break; + case BulkAction.enable: + title = i18n.RULES_BULK_ENABLE_FAILURE; + if (summary) { + toastMessage = i18n.RULES_BULK_ENABLE_FAILURE_DESCRIPTION(summary.failed); + } + break; + case BulkAction.disable: + title = i18n.RULES_BULK_DISABLE_FAILURE; + if (summary) { + toastMessage = i18n.RULES_BULK_DISABLE_FAILURE_DESCRIPTION(summary.failed); + } + break; + case BulkAction.edit: + title = i18n.RULES_BULK_EDIT_FAILURE; + if (summary) { + toastMessage = i18n.RULES_BULK_EDIT_FAILURE_DESCRIPTION(summary.failed); + } + break; + } + + return { title, toastMessage }; +} + +export function getSuccessToastContent(action: BulkAction, summary: BulkActionSummary) { + let title: string; + let text: string | undefined; + + switch (action) { + case BulkAction.export: + title = i18n.RULES_BULK_EXPORT_SUCCESS; + text = getExportSuccessToastMessage(summary.succeeded, summary.total); + break; + case BulkAction.duplicate: + title = i18n.RULES_BULK_DUPLICATE_SUCCESS; + text = i18n.RULES_BULK_DUPLICATE_SUCCESS_DESCRIPTION(summary.succeeded); + break; + case BulkAction.delete: + title = i18n.RULES_BULK_DELETE_SUCCESS; + text = i18n.RULES_BULK_DELETE_SUCCESS_DESCRIPTION(summary.succeeded); + break; + case BulkAction.enable: + title = i18n.RULES_BULK_ENABLE_SUCCESS; + text = i18n.RULES_BULK_ENABLE_SUCCESS_DESCRIPTION(summary.succeeded); + break; + case BulkAction.disable: + title = i18n.RULES_BULK_DISABLE_SUCCESS; + text = i18n.RULES_BULK_DISABLE_SUCCESS_DESCRIPTION(summary.succeeded); + break; + case BulkAction.edit: + title = i18n.RULES_BULK_EDIT_SUCCESS; + text = i18n.RULES_BULK_EDIT_SUCCESS_DESCRIPTION(summary.succeeded); + break; + } + + return { title, text }; +} + +const getExportSuccessToastMessage = (succeeded: number, total: number) => { + const message = [i18n.RULES_BULK_EXPORT_SUCCESS_DESCRIPTION(succeeded, total)]; + + // if not all rules are successfully exported it means there included prebuilt rules + // display message to users that prebuilt rules were excluded + if (total > succeeded) { + message.push(i18n.RULES_BULK_EXPORT_PREBUILT_RULES_EXCLUDED_DESCRIPTION); + } + + return message.join(' '); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.ts new file mode 100644 index 0000000000000..793580e5d3be0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.ts @@ -0,0 +1,79 @@ +/* + * 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 { useCallback } from 'react'; +import type { BulkActionResponse, BulkActionSummary } from '..'; +import { BulkAction } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { HTTPError } from '../../../../../common/detection_engine/types'; +import type { UseAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { downloadBlob } from '../../../../common/utils/download_blob'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; +import { getExportedRulesCounts } from '../../../rule_management_ui/components/rules_table/helpers'; +import type { RulesTableActions } from '../../../rule_management_ui/components/rules_table/rules_table/rules_table_context'; +import { useBulkExportMutation } from '../../api/hooks/use_bulk_export_mutation'; +import { getErrorToastContent, getSuccessToastContent } from './translations'; + +interface RulesBulkActionArgs { + visibleRuleIds?: string[]; + search: { query: string } | { ids: string[] }; + setLoadingRules?: RulesTableActions['setLoadingRules']; +} + +export const useBulkExport = () => { + const toasts = useAppToasts(); + const { mutateAsync } = useBulkExportMutation(); + + const bulkExport = useCallback( + async ({ visibleRuleIds = [], setLoadingRules, search }: RulesBulkActionArgs) => { + try { + setLoadingRules?.({ ids: visibleRuleIds, action: BulkAction.export }); + return await mutateAsync(search); + } catch (error) { + defaultErrorHandler(toasts, error); + } finally { + setLoadingRules?.({ ids: [], action: null }); + } + }, + [mutateAsync, toasts] + ); + + return { bulkExport }; +}; + +/** + * downloads exported rules, received from export action + * @param params.response - Blob results with exported rules + * @param params.toasts - {@link UseAppToasts} toasts service + * @param params.onSuccess - {@link OnActionSuccessCallback} optional toast to display when action successful + * @param params.onError - {@link OnActionErrorCallback} optional toast to display when action failed + */ +export async function downloadExportedRules({ + response, + toasts, +}: { + response: Blob; + toasts: UseAppToasts; +}) { + try { + downloadBlob(response, `${i18n.EXPORT_FILENAME}.ndjson`); + defaultSuccessHandler(toasts, await getExportedRulesCounts(response)); + } catch (error) { + defaultErrorHandler(toasts, error); + } +} + +function defaultErrorHandler(toasts: UseAppToasts, error: HTTPError): void { + const summary = (error?.body as BulkActionResponse)?.attributes?.summary; + error.stack = JSON.stringify(error.body, null, 2); + + toasts.addError(error, getErrorToastContent(BulkAction.export, summary)); +} + +function defaultSuccessHandler(toasts: UseAppToasts, summary: BulkActionSummary): void { + toasts.addSuccess(getSuccessToastContent(BulkAction.export, summary)); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.ts new file mode 100644 index 0000000000000..3ba9e353f3fcd --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.ts @@ -0,0 +1,122 @@ +/* + * 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 { NavigateToAppOptions } from '@kbn/core/public'; +import { useCallback } from 'react'; +import type { BulkActionResponse, BulkActionSummary } from '..'; +import { APP_UI_ID } from '../../../../../common/constants'; +import type { BulkActionEditPayload } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkAction } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { HTTPError } from '../../../../../common/detection_engine/types'; +import { SecurityPageName } from '../../../../app/types'; +import { getEditRuleUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; +import type { UseAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../../common/lib/telemetry'; +import type { RulesTableActions } from '../../../rule_management_ui/components/rules_table/rules_table/rules_table_context'; +import { useBulkActionMutation } from '../../api/hooks/use_bulk_action_mutation'; +import { getErrorToastContent, getSuccessToastContent } from './translations'; + +export const goToRuleEditPage = ( + ruleId: string, + navigateToApp: (appId: string, options?: NavigateToAppOptions | undefined) => Promise +) => { + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.rules, + path: getEditRuleUrl(ruleId ?? ''), + }); +}; + +type OnActionSuccessCallback = ( + toasts: UseAppToasts, + action: BulkAction, + summary: BulkActionSummary +) => void; + +type OnActionErrorCallback = (toasts: UseAppToasts, action: BulkAction, error: HTTPError) => void; + +interface RulesBulkActionArgs { + action: Exclude; + visibleRuleIds?: string[]; + search: { query: string } | { ids: string[] }; + payload?: { edit?: BulkActionEditPayload[] }; + onError?: OnActionErrorCallback; + onFinish?: () => void; + onSuccess?: OnActionSuccessCallback; + setLoadingRules?: RulesTableActions['setLoadingRules']; +} + +export const useExecuteBulkAction = () => { + const toasts = useAppToasts(); + const { mutateAsync } = useBulkActionMutation(); + + const executeBulkAction = useCallback( + async ({ + visibleRuleIds = [], + action, + setLoadingRules, + search, + payload, + onSuccess = defaultSuccessHandler, + onError = defaultErrorHandler, + onFinish, + }: RulesBulkActionArgs) => { + try { + setLoadingRules?.({ ids: visibleRuleIds, action }); + const response = await mutateAsync({ ...search, action, edit: payload?.edit }); + sendTelemetry(action, response); + onSuccess(toasts, action, response.attributes.summary); + + return response; + } catch (error) { + onError(toasts, action, error); + } finally { + setLoadingRules?.({ ids: [], action: null }); + onFinish?.(); + } + }, + [mutateAsync, toasts] + ); + + return { executeBulkAction }; +}; + +function defaultErrorHandler(toasts: UseAppToasts, action: BulkAction, error: HTTPError) { + const summary = (error?.body as BulkActionResponse)?.attributes?.summary; + error.stack = JSON.stringify(error.body, null, 2); + + toasts.addError(error, getErrorToastContent(action, summary)); +} + +async function defaultSuccessHandler( + toasts: UseAppToasts, + action: BulkAction, + summary: BulkActionSummary +) { + toasts.addSuccess(getSuccessToastContent(action, summary)); +} + +function sendTelemetry(action: BulkAction, response: BulkActionResponse) { + if (action === BulkAction.disable || action === BulkAction.enable) { + if (response.attributes.results.updated.some((rule) => rule.immutable)) { + track( + METRIC_TYPE.COUNT, + action === BulkAction.enable + ? TELEMETRY_EVENT.SIEM_RULE_ENABLED + : TELEMETRY_EVENT.SIEM_RULE_DISABLED + ); + } + if (response.attributes.results.updated.some((rule) => !rule.immutable)) { + track( + METRIC_TYPE.COUNT, + action === BulkAction.disable + ? TELEMETRY_EVENT.CUSTOM_RULE_ENABLED + : TELEMETRY_EVENT.CUSTOM_RULE_DISABLED + ); + } + } +} diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/index.ts similarity index 66% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/index.ts index 42c1eff7435bc..8caaade79ee40 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/index.ts @@ -5,9 +5,10 @@ * 2.0. */ -export * from './api'; +// TODO: https://github.com/elastic/kibana/pull/142950 delete this whole index file +// TODO: https://github.com/elastic/kibana/pull/142950 delete api re-export +export * from '../api/api'; export * from './use_update_rule'; export * from './use_create_rule'; export * from './types'; export * from './use_rule'; -export * from './use_pre_packaged_rules'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/mock.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/mock.ts similarity index 99% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/mock.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/mock.ts index bdcc8e0ec5e8a..6e1c53cb2da21 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/mock.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/mock.ts @@ -7,6 +7,7 @@ import type { FetchRulesResponse, Rule } from './types'; +// TODO move to __mocks__ export const savedRuleMock: Rule = { author: [], actions: [], diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts new file mode 100644 index 0000000000000..36735f1ff11e1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const RULE_AND_TIMELINE_FETCH_FAILURE = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.rulesAndTimelines', + { + defaultMessage: 'Failed to fetch Rules and Timelines', + } +); + +export const RULE_ADD_FAILURE = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.addRuleFailDescription', + { + defaultMessage: 'Failed to add Rule', + } +); + +export const RULE_AND_TIMELINE_PREPACKAGED_FAILURE = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleAndTimelineFailDescription', + { + defaultMessage: 'Failed to installed pre-packaged rules and timelines from elastic', + } +); + +export const RULE_AND_TIMELINE_PREPACKAGED_SUCCESS = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleAndTimelineSuccesDescription', + { + defaultMessage: 'Installed pre-packaged rules and timeline templates from elastic', + } +); + +export const RULE_PREPACKAGED_SUCCESS = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleSuccesDescription', + { + defaultMessage: 'Installed pre-packaged rules from elastic', + } +); + +export const TIMELINE_PREPACKAGED_SUCCESS = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription', + { + defaultMessage: 'Installed pre-packaged timeline templates from elastic', + } +); + +export const TAG_FETCH_FAILURE = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription', + { + defaultMessage: 'Failed to fetch Tags', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts similarity index 58% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts index 842353a6799f8..fa2b7f16ce9f7 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts @@ -7,56 +7,74 @@ import * as t from 'io-ts'; -import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; -import { listArray } from '@kbn/securitysolution-io-ts-list-types'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { - risk_score_mapping, - threat_query, + RiskScore, + RiskScoreMapping, + RuleActionArray, + RuleActionThrottle, + RuleInterval, + RuleIntervalFrom, + RuleIntervalTo, + Severity, + SeverityMapping, + threat_filters, threat_index, threat_indicator_path, - threat_mapping, threat_language, - threat_filters, - threats, + threat_mapping, + threat_query, type, - severity_mapping, - severity, } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; -import { RuleExecutionSummary } from '../../../../../common/detection_engine/rule_monitoring'; - -import type { SortOrder } from '../../../../../common/detection_engine/schemas/common'; -import type { - BulkActionEditPayload, - BulkAction, -} from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { RuleExecutionSummary } from '../../../../common/detection_engine/rule_monitoring'; import { - alias_purpose as savedObjectResolveAliasPurpose, - outcome as savedObjectResolveOutcome, - author, - building_block_type, - license, - rule_name_override, - data_view_id, - timestamp_override, - timestamp_override_fallback_disabled, - timestamp_field, - event_category_override, - tiebreaker_field, - threshold, + 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, -} from '../../../../../common/detection_engine/schemas/common'; - + ThreatArray, + Threshold, + TiebreakerField, + TimelineTemplateId, + TimelineTemplateTitle, + TimestampField, + TimestampOverride, + TimestampOverrideFallbackDisabled, +} from '../../../../common/detection_engine/rule_schema'; + +import type { PatchRuleRequestBody } from '../../../../common/detection_engine/rule_management'; import type { - CreateRulesSchema, - PatchRulesSchema, - UpdateRulesSchema, -} from '../../../../../common/detection_engine/schemas/request'; - -import type { BulkActionsDryRunErrCode } from '../../../../../common/constants'; + RuleCreateProps, + RuleUpdateProps, +} from '../../../../common/detection_engine/rule_schema'; +import type { SortOrder } from '../../../../common/detection_engine/schemas/common'; /** * Params is an "record", since it is a type of RuleActionParams which is action templates. @@ -73,23 +91,23 @@ export const action = t.exact( ); export interface CreateRulesProps { - rule: CreateRulesSchema; - signal: AbortSignal; + rule: RuleCreateProps; + signal?: AbortSignal; } export interface PreviewRulesProps { - rule: CreateRulesSchema & { invocationCount: number; timeframeEnd: string }; - signal: AbortSignal; + rule: RuleCreateProps & { invocationCount: number; timeframeEnd: string }; + signal?: AbortSignal; } export interface UpdateRulesProps { - rule: UpdateRulesSchema; - signal: AbortSignal; + rule: RuleUpdateProps; + signal?: AbortSignal; } export interface PatchRuleProps { - ruleProperties: PatchRulesSchema; - signal: AbortSignal; + ruleProperties: PatchRuleRequestBody; + signal?: AbortSignal; } const MetaRule = t.intersection([ @@ -105,73 +123,73 @@ const MetaRule = t.intersection([ // TODO: make a ticket export const RuleSchema = t.intersection([ t.type({ - author, + author: RuleAuthorArray, created_at: t.string, created_by: t.string, - description: t.string, - enabled: t.boolean, - false_positives: t.array(t.string), - from: t.string, - id: t.string, - interval: t.string, - immutable: t.boolean, - name: t.string, - max_signals: t.number, - references: t.array(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: t.number, - risk_score_mapping, - rule_id: t.string, - severity, - severity_mapping, + risk_score: RiskScore, + risk_score_mapping: RiskScoreMapping, + rule_id: RuleSignatureId, + severity: Severity, + severity_mapping: SeverityMapping, setup: SetupGuide, - tags: t.array(t.string), + tags: RuleTagArray, type, - to: t.string, - threat: threats, + to: RuleIntervalTo, + threat: ThreatArray, updated_at: t.string, updated_by: t.string, - actions: t.array(action), - throttle: t.union([t.string, t.null]), + actions: RuleActionArray, + throttle: t.union([RuleActionThrottle, t.null]), }), t.partial({ - outcome: savedObjectResolveOutcome, - alias_target_id: t.string, - alias_purpose: savedObjectResolveAliasPurpose, - building_block_type, + outcome: SavedObjectResolveOutcome, + alias_target_id: SavedObjectResolveAliasTargetId, + alias_purpose: SavedObjectResolveAliasPurpose, + building_block_type: BuildingBlockType, anomaly_threshold: t.number, - filters: t.array(t.unknown), - index: t.array(t.string), - data_view_id, + filters: RuleFilterArray, + index: IndexPatternArray, + data_view_id: DataViewId, language: t.string, - license, + 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: t.string, - query: t.string, - rule_name_override, + output_index: AlertsIndex, + query: RuleQuery, + rule_name_override: RuleNameOverride, saved_id: t.string, - threshold, + threshold: Threshold, threat_query, threat_filters, threat_index, threat_indicator_path, threat_mapping, threat_language, - timeline_id: t.string, - timeline_title: t.string, - timestamp_override, - timestamp_override_fallback_disabled, - timestamp_field, - event_category_override, - tiebreaker_field, - note: t.string, - exceptions_list: listArray, + 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: t.number, + version: RuleVersion, execution_summary: RuleExecutionSummary, }), ]); @@ -230,55 +248,9 @@ export interface FetchRulesResponse { export interface FetchRuleProps { id: string; - signal: AbortSignal; -} - -export interface BulkActionProps { - action: Action; - query?: string; - ids?: string[]; - edit?: BulkActionEditPayload[]; - isDryRun?: boolean; -} - -export interface BulkActionSummary { - failed: number; - succeeded: number; - total: number; -} - -export interface BulkActionResult { - updated: Rule[]; - created: Rule[]; - deleted: Rule[]; -} - -export interface BulkActionAggregatedError { - message: string; - status_code: number; - err_code?: BulkActionsDryRunErrCode; - rules: Array<{ id: string; name?: string }>; -} - -export interface BulkActionResponse { - success?: boolean; - rules_count?: number; - attributes: { - summary: BulkActionSummary; - results: BulkActionResult; - errors?: BulkActionAggregatedError[]; - }; + signal?: AbortSignal; } -export type BulkActionResponseMap = { - [BulkAction.delete]: BulkActionResponse; - [BulkAction.disable]: BulkActionResponse; - [BulkAction.enable]: BulkActionResponse; - [BulkAction.duplicate]: BulkActionResponse; - [BulkAction.export]: Blob; - [BulkAction.edit]: BulkActionResponse; -}[Action]; - export interface BasicFetchProps { signal: AbortSignal; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_create_pre_packaged_rules.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_create_pre_packaged_rules.ts new file mode 100644 index 0000000000000..c1de79159918f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_create_pre_packaged_rules.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback } from 'react'; +import { useUserData } from '../../../detections/components/user_info'; +import { useInstallPrePackagedRules } from './use_install_pre_packaged_rules'; + +export const useCreatePrePackagedRules = () => { + const [{ isSignalIndexExists, isAuthenticated, hasEncryptionKey, canUserCRUD, hasIndexWrite }] = + useUserData(); + const { mutateAsync: installPrePackagedRules, isLoading } = useInstallPrePackagedRules(); + + const canCreatePrePackagedRules = + canUserCRUD && hasIndexWrite && isAuthenticated && hasEncryptionKey && isSignalIndexExists; + + const createPrePackagedRules = useCallback(async () => { + if (canCreatePrePackagedRules) { + await installPrePackagedRules(); + } + }, [canCreatePrePackagedRules, installPrePackagedRules]); + + return { + isLoading, + createPrePackagedRules, + canCreatePrePackagedRules, + }; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_create_rule.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_create_rule.ts new file mode 100644 index 0000000000000..65cb3a8bc0460 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_create_rule.ts @@ -0,0 +1,20 @@ +/* + * 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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useCreateRuleMutation } from '../api/hooks/use_create_rule_mutation'; +import * as i18n from './translations'; + +export const useCreateRule = () => { + const { addError } = useAppToasts(); + + return useCreateRuleMutation({ + onError: (error) => { + addError(error, { title: i18n.RULE_ADD_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_dissasociate_exception_list.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_disassociate_exception_list.ts similarity index 78% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_dissasociate_exception_list.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_disassociate_exception_list.ts index ecb9b7c095786..67a30233c59d7 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_dissasociate_exception_list.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_disassociate_exception_list.ts @@ -9,12 +9,12 @@ import { useEffect, useState, useRef } from 'react'; import type { List } from '@kbn/securitysolution-io-ts-list-types'; import type { HttpStart } from '@kbn/core/public'; -import { patchRule } from './api'; +import { patchRule } from '../api/api'; type Func = (lists: List[]) => void; -export type ReturnUseDissasociateExceptionList = [boolean, Func | null]; +export type ReturnUseDisassociateExceptionList = [boolean, Func | null]; -export interface UseDissasociateExceptionListProps { +export interface UseDisassociateExceptionListProps { http: HttpStart; ruleRuleId: string; onError: (arg: Error) => void; @@ -30,20 +30,20 @@ export interface UseDissasociateExceptionListProps { * @param onSuccess success callback * */ -export const useDissasociateExceptionList = ({ +export const useDisassociateExceptionList = ({ http, ruleRuleId, onError, onSuccess, -}: UseDissasociateExceptionListProps): ReturnUseDissasociateExceptionList => { +}: UseDisassociateExceptionListProps): ReturnUseDisassociateExceptionList => { const [isLoading, setLoading] = useState(false); - const dissasociateList = useRef(null); + const disassociateList = useRef(null); useEffect(() => { let isSubscribed = true; const abortCtrl = new AbortController(); - const dissasociateListFromRule = + const disassociateListFromRule = (id: string) => async (exceptionLists: List[]): Promise => { try { @@ -69,7 +69,7 @@ export const useDissasociateExceptionList = ({ } }; - dissasociateList.current = dissasociateListFromRule(ruleRuleId); + disassociateList.current = disassociateListFromRule(ruleRuleId); return (): void => { isSubscribed = false; @@ -77,5 +77,5 @@ export const useDissasociateExceptionList = ({ }; }, [http, ruleRuleId, onError, onSuccess]); - return [isLoading, dissasociateList.current]; + return [isLoading, disassociateList.current]; }; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_dissasociate_exception_list.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts similarity index 67% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_dissasociate_exception_list.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts index 1a40d260b476c..9671dac1039a1 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_dissasociate_exception_list.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts @@ -9,17 +9,17 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { coreMock } from '@kbn/core/public/mocks'; -import * as api from './api'; -import { getRulesSchemaMock } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; +import * as api from '../api/api'; +import { getRulesSchemaMock } from '../../../../common/detection_engine/rule_schema/mocks'; import type { - ReturnUseDissasociateExceptionList, - UseDissasociateExceptionListProps, -} from './use_dissasociate_exception_list'; -import { useDissasociateExceptionList } from './use_dissasociate_exception_list'; + ReturnUseDisassociateExceptionList, + UseDisassociateExceptionListProps, +} from './use_disassociate_exception_list'; +import { useDisassociateExceptionList } from './use_disassociate_exception_list'; const mockKibanaHttpService = coreMock.createStart().http; -describe('useDissasociateExceptionList', () => { +describe('useDisassociateExceptionList', () => { const onError = jest.fn(); const onSuccess = jest.fn(); @@ -34,10 +34,10 @@ describe('useDissasociateExceptionList', () => { test('initializes hook', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook< - UseDissasociateExceptionListProps, - ReturnUseDissasociateExceptionList + UseDisassociateExceptionListProps, + ReturnUseDisassociateExceptionList >(() => - useDissasociateExceptionList({ + useDisassociateExceptionList({ http: mockKibanaHttpService, ruleRuleId: 'rule_id', onError, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_find_rules.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_find_rules.ts new file mode 100644 index 0000000000000..653f1de8e3b3f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_find_rules.ts @@ -0,0 +1,38 @@ +/* + * 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 { UseQueryOptions } from '@tanstack/react-query'; +import { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import type { FindRulesQueryArgs } from '../api/hooks/use_find_rules_query'; +import { useFindRulesQuery } from '../api/hooks/use_find_rules_query'; +import * as i18n from './translations'; +import type { Rule } from './types'; + +export interface RulesQueryData { + rules: Rule[]; + total: number; +} + +/** + * A wrapper around useQuery provides default values to the underlying query, + * like query key, abortion signal, and error handler. + * + * @param requestArgs - fetch rules filters/pagination + * @param options - react-query options + * @returns useQuery result + */ +export const useFindRules = ( + requestArgs: FindRulesQueryArgs, + options: UseQueryOptions +) => { + const { addError } = useAppToasts(); + + return useFindRulesQuery(requestArgs, { + onError: (error: Error) => addError(error, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }), + ...options, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_install_pre_packaged_rules.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_install_pre_packaged_rules.ts similarity index 63% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_install_pre_packaged_rules.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_install_pre_packaged_rules.ts index 3f56cac04fb02..21ea298986598 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_install_pre_packaged_rules.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_install_pre_packaged_rules.ts @@ -4,28 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useMutation } from '@tanstack/react-query'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { createPrepackagedRules } from './api'; +import { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useCreatePrebuiltRulesMutation } from '../api/hooks/use_create_prebuilt_rules_mutation'; import * as i18n from './translations'; -import { useInvalidateRules } from './use_find_rules_query'; -import { useInvalidatePrePackagedRulesStatus } from './use_pre_packaged_rules_status'; export const useInstallPrePackagedRules = () => { const { addError, addSuccess } = useAppToasts(); - const invalidateRules = useInvalidateRules(); - const invalidatePrePackagedRulesStatus = useInvalidatePrePackagedRulesStatus(); - return useMutation(() => createPrepackagedRules(), { + return useCreatePrebuiltRulesMutation({ onError: (err) => { addError(err, { title: i18n.RULE_AND_TIMELINE_PREPACKAGED_FAILURE }); }, onSuccess: (result) => { addSuccess(getSuccessToastMessage(result)); - // Always invalidate all rules and the prepackaged rules status cache as - // the number of rules might change after the installation - invalidatePrePackagedRulesStatus(); - invalidateRules(); }, }); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_rules_installation_status.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_rules_installation_status.ts new file mode 100644 index 0000000000000..d45109ee078ed --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_rules_installation_status.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 { getPrePackagedRuleInstallationStatus } from '../../../detections/pages/detection_engine/rules/helpers'; +import { usePrePackagedRulesStatus } from './use_pre_packaged_rules_status'; + +export const usePrePackagedRulesInstallationStatus = () => { + const { data: prePackagedRulesStatus } = usePrePackagedRulesStatus(); + + return getPrePackagedRuleInstallationStatus( + prePackagedRulesStatus?.rules_installed, + prePackagedRulesStatus?.rules_not_installed, + prePackagedRulesStatus?.rules_not_updated + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_rules_status.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_rules_status.ts new file mode 100644 index 0000000000000..889b670432d54 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_rules_status.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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useFetchPrebuiltRulesStatusQuery } from '../api/hooks/use_fetch_prebuilt_rules_status_query'; +import * as i18n from './translations'; + +export const usePrePackagedRulesStatus = () => { + const { addError } = useAppToasts(); + + return useFetchPrebuiltRulesStatusQuery({ + onError: (err) => { + addError(err, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_timelines_installation_status.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_timelines_installation_status.ts new file mode 100644 index 0000000000000..61933d625ba18 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_pre_packaged_timelines_installation_status.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 { getPrePackagedTimelineInstallationStatus } from '../../../detections/pages/detection_engine/rules/helpers'; +import { usePrePackagedRulesStatus } from './use_pre_packaged_rules_status'; + +export const usePrePackagedTimelinesInstallationStatus = () => { + const { data: prePackagedRulesStatus } = usePrePackagedRulesStatus(); + + return getPrePackagedTimelineInstallationStatus( + prePackagedRulesStatus?.timelines_installed, + prePackagedRulesStatus?.timelines_not_installed, + prePackagedRulesStatus?.timelines_not_updated + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule.ts new file mode 100644 index 0000000000000..234ba95de54d6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule.ts @@ -0,0 +1,26 @@ +/* + * 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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useFetchRuleByIdQuery } from '../api/hooks/use_fetch_rule_by_id_query'; +import * as i18n from './translations'; + +/** + * Hook for using to get a Rule from the Detection Engine API + * + * @param id desired Rule ID's (not rule_id) + * + */ +export const useRule = (id: string) => { + const { addError } = useAppToasts(); + + return useFetchRuleByIdQuery(id, { + onError: (error) => { + addError(error, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_indices.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts similarity index 92% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_indices.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts index d22b9a8d83220..b04cda31daf5f 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_indices.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts @@ -8,9 +8,9 @@ import { renderHook } from '@testing-library/react-hooks'; import { useRuleIndices } from './use_rule_indices'; -import { useGetInstalledJob } from '../../../../common/components/ml/hooks/use_get_jobs'; +import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; -jest.mock('../../../../common/components/ml/hooks/use_get_jobs'); +jest.mock('../../../common/components/ml/hooks/use_get_jobs'); describe('useRuleIndices', () => { beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_indices.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.ts similarity index 90% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_indices.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.ts index 77ffc49bb7413..4dbb28514255a 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_indices.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.ts @@ -6,7 +6,7 @@ */ import { useMemo } from 'react'; -import { useGetInstalledJob } from '../../../../common/components/ml/hooks/use_get_jobs'; +import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; export const useRuleIndices = (machineLearningJobId?: string[], defaultRuleIndices?: string[]) => { const memoMlJobIds = useMemo(() => machineLearningJobId ?? [], [machineLearningJobId]); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_with_fallback.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.ts similarity index 79% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_with_fallback.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.ts index d832dd64cff70..6290c4ae6622f 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_with_fallback.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.ts @@ -5,20 +5,18 @@ * 2.0. */ -import { useCallback, useEffect, useMemo } from 'react'; import { ALERT_RULE_UUID } from '@kbn/rule-data-utils'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; import { isNotFoundError } from '@kbn/securitysolution-t-grid'; -import { expandDottedObject } from '../../../../../common/utils/expand_dotted'; - -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import type { AlertSearchResponse } from '../alerts/types'; -import { useQueryAlerts } from '../alerts/use_query'; -import { ALERTS_QUERY_NAMES } from '../alerts/constants'; -import { fetchRuleById } from './api'; -import { transformInput } from './transforms'; +import { useEffect, useMemo } from 'react'; +import { expandDottedObject } from '../../../../common/utils/expand_dotted'; +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 { error: unknown; @@ -55,10 +53,6 @@ interface RACRule { }; } -const fetchWithOptionsSignal = withOptionalSignal(fetchRuleById); - -const useFetchRule = () => useAsync(fetchWithOptionsSignal); - const buildLastAlertQuery = (ruleId: string) => ({ query: { bool: { @@ -83,17 +77,9 @@ const buildLastAlertQuery = (ruleId: string) => ({ * In that case, try to fetch the latest alert generated by the rule and retrieve the rule data from the alert (fallback). */ export const useRuleWithFallback = (ruleId: string): UseRuleWithFallback => { - const { start, loading: ruleLoading, result: ruleData, error } = useFetchRule(); + const { isLoading: ruleLoading, data: ruleData, error, refetch } = useRule(ruleId); const { addError } = useAppToasts(); - const fetch = useCallback(() => { - start({ id: ruleId }); - }, [ruleId, start]); - - useEffect(() => { - fetch(); - }, [fetch]); - const isExistingRule = !isNotFoundError(error); const { loading: alertsLoading, data: alertsData } = useQueryAlerts({ @@ -122,7 +108,7 @@ export const useRuleWithFallback = (ruleId: string): UseRuleWithFallback => { return { error, loading: ruleLoading || alertsLoading, - refresh: fetch, + refresh: refetch, rule: rule ?? null, isExistingRule, }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_tags.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_tags.ts new file mode 100644 index 0000000000000..ab3671f262f8a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_tags.ts @@ -0,0 +1,24 @@ +/* + * 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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useFetchTagsQuery } from '../api/hooks/use_fetch_tags_query'; +import * as i18n from './translations'; + +/** + * Hook for using the list of Tags from the Detection Engine API + * + */ +export const useTags = () => { + const { addError } = useAppToasts(); + + return useFetchTagsQuery({ + onError: (err) => { + addError(err, { title: i18n.TAG_FETCH_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_update_rule.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_update_rule.ts new file mode 100644 index 0000000000000..900b3c30ccaa2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_update_rule.ts @@ -0,0 +1,20 @@ +/* + * 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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useUpdateRuleMutation } from '../api/hooks/use_update_rule_mutation'; +import * as i18n from './translations'; + +export const useUpdateRule = () => { + const { addError } = useAppToasts(); + + return useUpdateRuleMutation({ + onError: (error) => { + addError(error, { title: i18n.RULE_ADD_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/utils.test.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.test.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/utils.test.ts diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/utils.ts similarity index 97% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/utils.ts index b4de6a95daaf1..67e64dab36a36 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { escapeKuery } from '../../../../common/lib/kuery'; +import { escapeKuery } from '../../../common/lib/kuery'; import type { FilterOptions } from './types'; const SEARCHABLE_RULE_PARAMS = [ diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/__mocks__/mock.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts similarity index 89% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/__mocks__/mock.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts index 967ba8a90d4f4..ac22095820255 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/__mocks__/mock.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts @@ -6,12 +6,17 @@ */ import { FilterStateStore } from '@kbn/es-query'; -import type { Rule } from '../../../../../containers/detection_engine/rules'; -import type { AboutStepRule, ActionsStepRule, DefineStepRule, ScheduleStepRule } from '../../types'; -import { DataSourceType } from '../../types'; -import type { FieldValueQueryBar } from '../../../../../components/rules/query_bar'; -import { fillEmptySeverityMappings } from '../../helpers'; -import { getThreatMock } from '../../../../../../../common/detection_engine/schemas/types/threat.mock'; +import type { Rule } from '../../../../rule_management/logic'; +import type { + AboutStepRule, + ActionsStepRule, + DefineStepRule, + ScheduleStepRule, +} from '../../../../../detections/pages/detection_engine/rules/types'; +import { DataSourceType } from '../../../../../detections/pages/detection_engine/rules/types'; +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'; export const mockQueryBar: FieldValueQueryBar = { query: { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_dry_run_confirmation.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_dry_run_confirmation.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_dry_run_confirmation.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_dry_run_confirmation.tsx index 9207e0813ab70..941339be4fa31 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_dry_run_confirmation.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_dry_run_confirmation.tsx @@ -8,10 +8,10 @@ import React from 'react'; import { EuiConfirmModal } from '@elastic/eui'; -import * as i18n from '../../translations'; +import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { BulkActionRuleErrorsList } from './bulk_action_rule_errors_list'; -import { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { assertUnreachable } from '../../../../../../../common/utility_types'; +import { BulkAction } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { assertUnreachable } from '../../../../../../common/utility_types'; import type { BulkActionForConfirmation, DryRunResult } from './types'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx similarity index 92% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx index 987b244dd9fc6..758ccf0893e36 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx @@ -11,9 +11,9 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render, screen } from '@testing-library/react'; import { BulkActionRuleErrorsList } from './bulk_action_rule_errors_list'; -import { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; +import { BulkActionsDryRunErrCode } from '../../../../../../common/constants'; import type { DryRunResult } from './types'; -import { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { BulkAction } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; const Wrapper: FC = ({ children }) => { return ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx similarity index 96% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx index 8f0275000a4ef..9789377f13ef3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx @@ -9,8 +9,8 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; -import { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { BulkActionsDryRunErrCode } from '../../../../../../common/constants'; +import { BulkAction } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import type { DryRunResult, BulkActionForConfirmation } from './types'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_edit_flyout.tsx similarity index 78% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_edit_flyout.tsx index 194d4d90f860a..4f109fab7a8ba 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_edit_flyout.tsx @@ -7,8 +7,8 @@ import React from 'react'; -import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { IndexPatternsForm } from './forms/index_patterns_form'; import { TagsForm } from './forms/tags_form'; @@ -21,10 +21,9 @@ interface BulkEditFlyoutProps { onConfirm: (bulkActionEditPayload: BulkActionEditPayload) => void; editAction: BulkActionEditType; rulesCount: number; - tags: string[]; } -const BulkEditFlyoutComponent = ({ editAction, tags, ...props }: BulkEditFlyoutProps) => { +const BulkEditFlyoutComponent = ({ editAction, ...props }: BulkEditFlyoutProps) => { switch (editAction) { case BulkActionEditType.add_index_patterns: case BulkActionEditType.delete_index_patterns: @@ -34,7 +33,7 @@ const BulkEditFlyoutComponent = ({ editAction, tags, ...props }: BulkEditFlyoutP case BulkActionEditType.add_tags: case BulkActionEditType.delete_tags: case BulkActionEditType.set_tags: - return ; + return ; case BulkActionEditType.set_timeline: return ; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/bulk_edit_form_wrapper.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/bulk_edit_form_wrapper.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/bulk_edit_form_wrapper.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/bulk_edit_form_wrapper.tsx index a4fafd8d21bfd..364774465bd2d 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/bulk_edit_form_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/bulk_edit_form_wrapper.tsx @@ -21,10 +21,10 @@ import { EuiFlyoutBody, } from '@elastic/eui'; -import type { FormHook } from '../../../../../../../shared_imports'; -import { Form } from '../../../../../../../shared_imports'; +import type { FormHook } from '../../../../../../shared_imports'; +import { Form } from '../../../../../../shared_imports'; -import * as i18n from '../../../translations'; +import * as i18n from '../../../../../../detections/pages/detection_engine/rules/translations'; interface BulkEditFormWrapperProps { form: FormHook; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/index_patterns_form.tsx similarity index 92% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/index_patterns_form.tsx index adb19e397027b..2ea8b20dcd42c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/index_patterns_form.tsx @@ -9,15 +9,15 @@ import React from 'react'; import { EuiFormRow, EuiCallOut } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import * as i18n from '../../../translations'; +import * as i18n from '../../../../../../detections/pages/detection_engine/rules/translations'; -import { DEFAULT_INDEX_KEY } from '../../../../../../../../common/constants'; -import { useKibana } from '../../../../../../../common/lib/kibana'; +import { DEFAULT_INDEX_KEY } from '../../../../../../../common/constants'; +import { useKibana } from '../../../../../../common/lib/kibana'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; -import type { FormSchema } from '../../../../../../../shared_imports'; +import type { FormSchema } from '../../../../../../shared_imports'; import { Field, getUseField, @@ -25,7 +25,7 @@ import { useForm, FIELD_TYPES, fieldValidators, -} from '../../../../../../../shared_imports'; +} from '../../../../../../shared_imports'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; const CommonUseField = getUseField({ component: Field }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/rule_actions_form.tsx similarity index 87% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/rule_actions_form.tsx index ec7d81e8b08a9..0bff754f20f4f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/rule_actions_form.tsx @@ -13,7 +13,7 @@ import type { ActionTypeRegistryContract, } from '@kbn/triggers-actions-ui-plugin/public'; -import type { FormSchema } from '../../../../../../../shared_imports'; +import type { FormSchema } from '../../../../../../shared_imports'; import { useForm, UseField, @@ -21,27 +21,27 @@ import { useFormData, getUseField, Field, -} from '../../../../../../../shared_imports'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +} from '../../../../../../shared_imports'; +import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import type { BulkActionEditPayload, ThrottleForBulkActions, -} from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { NOTIFICATION_THROTTLE_RULE } from '../../../../../../../../common/constants'; +} from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { NOTIFICATION_THROTTLE_RULE } from '../../../../../../../common/constants'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; import { bulkAddRuleActions as i18n } from '../translations'; -import { useKibana } from '../../../../../../../common/lib/kibana'; +import { useKibana } from '../../../../../../common/lib/kibana'; import { ThrottleSelectField, THROTTLE_OPTIONS_FOR_BULK_RULE_ACTIONS, -} from '../../../../../../components/rules/throttle_select_field'; -import { getAllActionMessageParams } from '../../../helpers'; +} from '../../../../../../detections/components/rules/throttle_select_field'; +import { getAllActionMessageParams } from '../../../../../../detections/pages/detection_engine/rules/helpers'; -import { RuleActionsField } from '../../../../../../components/rules/rule_actions_field'; -import { validateRuleActionsField } from '../../../../../../containers/detection_engine/rules/validate_rule_actions_field'; +import { RuleActionsField } from '../../../../../../detections/components/rules/rule_actions_field'; +import { validateRuleActionsField } from '../../../../../../detections/containers/detection_engine/rules/validate_rule_actions_field'; const CommonUseField = getUseField({ component: Field }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/schedule_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/schedule_form.tsx similarity index 85% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/schedule_form.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/schedule_form.tsx index eb27aee61f93b..68e7a4ddfb2d3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/schedule_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/schedule_form.tsx @@ -5,16 +5,15 @@ * 2.0. */ -import React, { useCallback } from 'react'; import { EuiCallOut } from '@elastic/eui'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request'; -import { useForm, UseField } from '../../../../../../../shared_imports'; -import type { FormSchema } from '../../../../../../../shared_imports'; -import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; -import { ScheduleItem } from '../../../../../../components/rules/schedule_item_form'; - +import React, { useCallback } from 'react'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { ScheduleItem } from '../../../../../../detections/components/rules/schedule_item_form'; +import type { FormSchema } from '../../../../../../shared_imports'; +import { UseField, useForm } from '../../../../../../shared_imports'; import { bulkSetSchedule as i18n } from '../translations'; +import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; export interface ScheduleFormData { interval: string; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx similarity index 87% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx index e53469e27a09a..4288342c03d10 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx @@ -5,26 +5,27 @@ * 2.0. */ -import React, { useMemo } from 'react'; -import { EuiFormRow, EuiCallOut } from '@elastic/eui'; +import { EuiCallOut, EuiFormRow } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import React, { useMemo } from 'react'; -import * as i18n from '../../../translations'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import * as i18n from '../../../../../../detections/pages/detection_engine/rules/translations'; import { caseInsensitiveSort } from '../../helpers'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { FormSchema } from '../../../../../../../shared_imports'; +import type { FormSchema } from '../../../../../../shared_imports'; import { - useForm, Field, + fieldValidators, + FIELD_TYPES, getUseField, + useForm, useFormData, - FIELD_TYPES, - fieldValidators, -} from '../../../../../../../shared_imports'; +} from '../../../../../../shared_imports'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; +import { useTags } from '../../../../../rule_management/logic/use_tags'; type TagsEditActions = | BulkActionEditType.add_tags @@ -74,10 +75,10 @@ interface TagsFormProps { rulesCount: number; onClose: () => void; onConfirm: (bulkActionEditPayload: BulkActionEditPayload) => void; - tags: string[]; } -const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm, tags }: TagsFormProps) => { +const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm }: TagsFormProps) => { + const { data: tags = [] } = useTags(); const { form } = useForm({ defaultValue: initialFormData, schema, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/timeline_template_form.tsx similarity index 85% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/timeline_template_form.tsx index 6aa5a3100c100..4ad3d04af03d5 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/timeline_template_form.tsx @@ -8,11 +8,11 @@ import React, { useCallback } from 'react'; import { EuiCallOut } from '@elastic/eui'; -import type { FormSchema } from '../../../../../../../shared_imports'; -import { useForm, UseField } from '../../../../../../../shared_imports'; -import { PickTimeline } from '../../../../../../components/rules/pick_timeline'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import type { FormSchema } from '../../../../../../shared_imports'; +import { useForm, UseField } from '../../../../../../shared_imports'; +import { PickTimeline } from '../../../../../../detections/components/rules/pick_timeline'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; import { bulkApplyTimelineTemplate as i18n } from '../translations'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/translations.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/translations.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/types.ts similarity index 86% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/types.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/types.ts index d81c7c995a2fe..c8250269dbe61 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/types.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/types.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; -import type { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import type { BulkActionsDryRunErrCode } from '../../../../../../common/constants'; +import type { BulkAction } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; /** * Only 2 bulk actions are supported for for confirmation dry run modal: diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx similarity index 76% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx index 17443855a6abf..48e45e144e479 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx @@ -6,43 +6,39 @@ */ /* eslint-disable complexity */ -import React, { useCallback } from 'react'; import type { EuiContextMenuPanelDescriptor } from '@elastic/eui'; -import { EuiTextColor, EuiFlexGroup, EuiButton, EuiFlexItem } from '@elastic/eui'; -import { euiThemeVars } from '@kbn/ui-theme'; -import { useIsMounted } from '@kbn/securitysolution-hook-utils'; - +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTextColor } from '@elastic/eui'; import type { Toast } from '@kbn/core/public'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; -import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { euiThemeVars } from '@kbn/ui-theme'; +import React, { useCallback } from 'react'; +import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkAction, BulkActionEditType, -} from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { isMlRule } from '../../../../../../../common/machine_learning/helpers'; -import { canEditRuleWithActions } from '../../../../../../common/utils/privileges'; -import { useRulesTableContext } from '../rules_table/rules_table_context'; -import * as detectionI18n from '../../../translations'; -import * as i18n from '../../translations'; -import { executeRulesBulkAction, downloadExportedRules } from '../actions'; +} from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { isMlRule } from '../../../../../../common/machine_learning/helpers'; +import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; +import { BULK_RULE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; +import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; +import { canEditRuleWithActions } from '../../../../../common/utils/privileges'; +import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; +import * as detectionI18n from '../../../../../detections/pages/detection_engine/translations'; +import { + downloadExportedRules, + useBulkExport, +} from '../../../../rule_management/logic/bulk_actions/use_bulk_export'; +import { useExecuteBulkAction } from '../../../../rule_management/logic/bulk_actions/use_execute_bulk_action'; +import type { FilterOptions } from '../../../../rule_management/logic/types'; +import { convertRulesFilterToKQL } from '../../../../rule_management/logic/utils'; import { getExportedRulesDetails } from '../helpers'; +import { useRulesTableContext } from '../rules_table/rules_table_context'; import { useHasActionsPrivileges } from '../use_has_actions_privileges'; import { useHasMlPermissions } from '../use_has_ml_permissions'; -import { transformExportDetailsToDryRunResult } from './utils/dry_run_result'; +import type { BulkActionForConfirmation, DryRunResult } from './types'; import type { ExecuteBulkActionsDryRun } from './use_bulk_actions_dry_run'; -import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; -import { convertRulesFilterToKQL } from '../../../../../containers/detection_engine/rules/utils'; +import { transformExportDetailsToDryRunResult } from './utils/dry_run_result'; import { prepareSearchParams } from './utils/prepare_search_params'; -import type { FilterOptions } from '../../../../../containers/detection_engine/rules/types'; -import { - useInvalidateRules, - useUpdateRulesCache, -} from '../../../../../containers/detection_engine/rules/use_find_rules_query'; -import { BULK_RULE_ACTIONS } from '../../../../../../common/lib/apm/user_actions'; -import { useStartTransaction } from '../../../../../../common/lib/apm/use_start_transaction'; -import { useInvalidatePrePackagedRulesStatus } from '../../../../../containers/detection_engine/rules/use_pre_packaged_rules_status'; - -import type { DryRunResult, BulkActionForConfirmation } from './types'; interface UseBulkActionsArgs { filterOptions: FilterOptions; @@ -54,7 +50,6 @@ interface UseBulkActionsArgs { completeBulkEditForm: ( bulkActionEditType: BulkActionEditType ) => Promise; - reFetchTags: () => void; executeBulkActionsDryRun: ExecuteBulkActionsDryRun; } @@ -63,33 +58,16 @@ export const useBulkActions = ({ confirmDeletion, showBulkActionConfirmation, completeBulkEditForm, - reFetchTags, executeBulkActionsDryRun, }: UseBulkActionsArgs) => { const hasMlPermissions = useHasMlPermissions(); const rulesTableContext = useRulesTableContext(); - const invalidateRules = useInvalidateRules(); - const updateRulesCache = useUpdateRulesCache(); - const invalidatePrePackagedRulesStatus = useInvalidatePrePackagedRulesStatus(); const hasActionsPrivileges = useHasActionsPrivileges(); const toasts = useAppToasts(); - const getIsMounted = useIsMounted(); const filterQuery = convertRulesFilterToKQL(filterOptions); const { startTransaction } = useStartTransaction(); - - // refetch tags if edit action is related to tags: add_tags/delete_tags/set_tags - const resolveTagsRefetch = useCallback( - async (bulkEditActionType: BulkActionEditType) => { - const isTagsAction = [ - BulkActionEditType.add_tags, - BulkActionEditType.set_tags, - BulkActionEditType.delete_tags, - ].includes(bulkEditActionType); - - return isTagsAction ? reFetchTags() : null; - }, - [reFetchTags] - ); + const { executeBulkAction } = useExecuteBulkAction(); + const { bulkExport } = useBulkExport(); const { state: { isAllSelected, rules, loadingRuleIds, selectedRuleIds }, @@ -125,14 +103,12 @@ export const useBulkActions = ({ ? disabledRules.map(({ id }) => id) : disabledRulesNoML.map(({ id }) => id); - const res = await executeRulesBulkAction({ + await executeBulkAction({ visibleRuleIds: ruleIds, action: BulkAction.enable, setLoadingRules, - toasts, search: isAllSelected ? { query: filterQuery } : { ids: ruleIds }, }); - updateRulesCache(res?.attributes?.results?.updated ?? []); }; const handleDisableActions = async () => { @@ -141,32 +117,24 @@ export const useBulkActions = ({ const enabledIds = selectedRules.filter(({ enabled }) => enabled).map(({ id }) => id); - const res = await executeRulesBulkAction({ + await executeBulkAction({ visibleRuleIds: enabledIds, action: BulkAction.disable, setLoadingRules, - toasts, search: isAllSelected ? { query: filterQuery } : { ids: enabledIds }, }); - updateRulesCache(res?.attributes?.results?.updated ?? []); }; const handleDuplicateAction = async () => { startTransaction({ name: BULK_RULE_ACTIONS.DUPLICATE }); closePopover(); - await executeRulesBulkAction({ + await executeBulkAction({ visibleRuleIds: selectedRuleIds, action: BulkAction.duplicate, setLoadingRules, - toasts, search: isAllSelected ? { query: filterQuery } : { ids: selectedRuleIds }, }); - invalidateRules(); - // We use prePackagedRulesStatus to display Prebuilt/Custom rules - // counters, so we need to invalidate it when the total number of rules - // changes. - invalidatePrePackagedRulesStatus(); clearRulesSelection(); }; @@ -182,29 +150,21 @@ export const useBulkActions = ({ startTransaction({ name: BULK_RULE_ACTIONS.DELETE }); - await executeRulesBulkAction({ + await executeBulkAction({ visibleRuleIds: selectedRuleIds, action: BulkAction.delete, setLoadingRules, - toasts, search: isAllSelected ? { query: filterQuery } : { ids: selectedRuleIds }, }); - invalidateRules(); - // We use prePackagedRulesStatus to display Prebuilt/Custom rules - // counters, so we need to invalidate it when the total number of rules - // changes. - invalidatePrePackagedRulesStatus(); }; const handleExportAction = async () => { closePopover(); startTransaction({ name: BULK_RULE_ACTIONS.EXPORT }); - const response = await executeRulesBulkAction({ + const response = await bulkExport({ visibleRuleIds: selectedRuleIds, - action: BulkAction.export, setLoadingRules, - toasts, search: isAllSelected ? { query: filterQuery } : { ids: selectedRuleIds }, }); @@ -232,7 +192,6 @@ export const useBulkActions = ({ let longTimeWarningToast: Toast; let isBulkEditFinished = false; - // disabling auto-refresh so user's selected rules won't disappear after table refresh closePopover(); const dryRunResult = await executeBulkActionsDryRun({ @@ -296,11 +255,10 @@ export const useBulkActions = ({ ); }, 5 * 1000); - const res = await executeRulesBulkAction({ + await executeBulkAction({ visibleRuleIds: selectedRuleIds, action: BulkAction.edit, setLoadingRules, - toasts, payload: { edit: [editPayload] }, onFinish: () => hideWarningToast(), search: prepareSearchParams({ @@ -310,10 +268,6 @@ export const useBulkActions = ({ }); isBulkEditFinished = true; - updateRulesCache(res?.attributes?.results?.updated ?? []); - if (getIsMounted()) { - await resolveTagsRefetch(bulkEditActionType); - } }; const isDeleteDisabled = containsLoading || selectedRuleIds.length === 0; @@ -332,7 +286,9 @@ export const useBulkActions = ({ disabled: missingActionPrivileges || containsLoading || (!containsDisabled && !isAllSelected), onClick: handleEnableAction, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -342,7 +298,9 @@ export const useBulkActions = ({ 'data-test-subj': 'duplicateRuleBulk', disabled: isEditDisabled, onClick: handleDuplicateAction, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -366,7 +324,9 @@ export const useBulkActions = ({ 'data-test-subj': 'addRuleActionsBulk', disabled: !hasActionsPrivileges || isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.add_rule_actions), - toolTipContent: !hasActionsPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: !hasActionsPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -376,7 +336,9 @@ export const useBulkActions = ({ 'data-test-subj': 'setScheduleBulk', disabled: isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.set_schedule), - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -386,7 +348,9 @@ export const useBulkActions = ({ 'data-test-subj': 'applyTimelineTemplateBulk', disabled: isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.set_timeline), - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -405,7 +369,9 @@ export const useBulkActions = ({ disabled: missingActionPrivileges || containsLoading || (!containsEnabled && !isAllSelected), onClick: handleDisableActions, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -439,7 +405,9 @@ export const useBulkActions = ({ 'data-test-subj': 'addTagsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.add_tags), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, { @@ -448,7 +416,9 @@ export const useBulkActions = ({ 'data-test-subj': 'deleteTagsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.delete_tags), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, ], @@ -463,7 +433,9 @@ export const useBulkActions = ({ 'data-test-subj': 'addIndexPatternsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.add_index_patterns), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, { @@ -472,7 +444,9 @@ export const useBulkActions = ({ 'data-test-subj': 'deleteIndexPatternsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.delete_index_patterns), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, ], @@ -487,20 +461,17 @@ export const useBulkActions = ({ loadingRuleIds, startTransaction, hasMlPermissions, + executeBulkAction, setLoadingRules, - toasts, filterQuery, - updateRulesCache, - invalidateRules, - invalidatePrePackagedRulesStatus, + toasts, clearRulesSelection, confirmDeletion, + bulkExport, showBulkActionConfirmation, executeBulkActionsDryRun, filterOptions, completeBulkEditForm, - getIsMounted, - resolveTagsRefetch, ] ); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_confirmation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_confirmation.ts similarity index 89% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_confirmation.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_confirmation.ts index d840abae1f2e2..9ce813fc6d9a2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_confirmation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_confirmation.ts @@ -7,13 +7,14 @@ import { useState, useCallback } from 'react'; import { useAsyncConfirmation } from '../rules_table/use_async_confirmation'; -import { useBoolState } from '../../../../../../common/hooks/use_bool_state'; +import { useBoolState } from '../../../../../common/hooks/use_bool_state'; import type { DryRunResult, BulkActionForConfirmation } from './types'; /** * hook that controls bulk actions confirmation modal window and its content */ +// TODO Why does this hook exist? Consider removing it altogether export const useBulkActionsConfirmation = () => { const [bulkAction, setBulkAction] = useState(); const [dryRunResult, setDryRunResult] = useState(); @@ -31,6 +32,7 @@ export const useBulkActionsConfirmation = () => { // show bulk action confirmation window only if there is at least one failed rule, otherwise return early const hasFailedRules = (result?.failedRulesCount ?? 0) > 0; + // TODO Why is this logic here? Extract it out of this hook. if (!hasFailedRules) { return true; } diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_dry_run.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_dry_run.ts similarity index 88% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_dry_run.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_dry_run.ts index 5e14c0a57bf51..d11a2d6c167b8 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_dry_run.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_dry_run.ts @@ -11,9 +11,9 @@ import { useMutation } from '@tanstack/react-query'; import type { BulkAction, BulkActionEditType, -} from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { BulkActionResponse } from '../../../../../containers/detection_engine/rules'; -import { performBulkAction } from '../../../../../containers/detection_engine/rules'; +} from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { BulkActionResponse } from '../../../../rule_management/logic'; +import { performBulkAction } from '../../../../rule_management/logic'; import { computeDryRunPayload } from './utils/compute_dry_run_payload'; import { processDryRunResult } from './utils/dry_run_result'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_edit_form_flyout.ts similarity index 89% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_edit_form_flyout.ts index 6d629ae1869b4..063d10a737810 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_edit_form_flyout.ts @@ -10,8 +10,8 @@ import { useAsyncConfirmation } from '../rules_table/use_async_confirmation'; import type { BulkActionEditPayload, BulkActionEditType, -} from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { useBoolState } from '../../../../../../common/hooks/use_bool_state'; +} from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { useBoolState } from '../../../../../common/hooks/use_bool_state'; export const useBulkEditFormFlyout = () => { const dataFormRef = useRef(null); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_payload.test.ts similarity index 93% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.test.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_payload.test.ts index 361f7edc4823f..b3fe47dd214a0 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_payload.test.ts @@ -8,7 +8,7 @@ import { BulkAction, BulkActionEditType, -} from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +} from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { computeDryRunPayload } from './compute_dry_run_payload'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_payload.ts similarity index 87% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_payload.ts index d8e6f78e33397..36ebb0d5a644d 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_payload.ts @@ -5,12 +5,12 @@ * 2.0. */ -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkAction, BulkActionEditType, -} from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { assertUnreachable } from '../../../../../../../../common/utility_types'; +} from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { assertUnreachable } from '../../../../../../../common/utility_types'; /** * helper utility that creates payload for _bulk_action API in dry mode diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/dry_run_result.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/dry_run_result.ts similarity index 85% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/dry_run_result.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/dry_run_result.ts index 5a15f03b9810d..627b7bf54cfd3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/dry_run_result.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/dry_run_result.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { BulkActionsDryRunErrCode } from '../../../../../../../../common/constants'; -import type { ExportRulesDetails } from '../../../../../../../../common/detection_engine/schemas/response/export_rules_details_schema'; -import type { BulkActionResponse } from '../../../../../../containers/detection_engine/rules'; +import { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; +import type { ExportRulesDetails } from '../../../../../../../common/detection_engine/rule_management'; +import type { BulkActionResponse } from '../../../../../rule_management/logic'; import type { DryRunResult } from '../types'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/prepare_search_params.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/prepare_search_params.test.ts similarity index 87% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/prepare_search_params.test.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/prepare_search_params.test.ts index ed7f18376c3f4..3c5dc13ffab66 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/prepare_search_params.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/prepare_search_params.test.ts @@ -6,14 +6,14 @@ */ import type { DryRunResult } from '../types'; -import type { FilterOptions } from '../../../../../../containers/detection_engine/rules/types'; +import type { FilterOptions } from '../../../../../rule_management/logic/types'; -import { convertRulesFilterToKQL } from '../../../../../../containers/detection_engine/rules/utils'; -import { BulkActionsDryRunErrCode } from '../../../../../../../../common/constants'; +import { convertRulesFilterToKQL } from '../../../../../rule_management/logic/utils'; +import { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; import { prepareSearchParams } from './prepare_search_params'; -jest.mock('../../../../../../containers/detection_engine/rules/utils', () => ({ +jest.mock('../../../../../rule_management/logic/utils', () => ({ convertRulesFilterToKQL: jest.fn().mockReturnValue('str'), })); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/prepare_search_params.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/prepare_search_params.ts similarity index 88% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/prepare_search_params.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/prepare_search_params.ts index 72a74a9fa500d..c761e56f4bfef 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/prepare_search_params.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/prepare_search_params.ts @@ -6,10 +6,10 @@ */ import type { DryRunResult } from '../types'; -import type { FilterOptions } from '../../../../../../containers/detection_engine/rules/types'; +import type { FilterOptions } from '../../../../../rule_management/logic/types'; -import { convertRulesFilterToKQL } from '../../../../../../containers/detection_engine/rules/utils'; -import { BulkActionsDryRunErrCode } from '../../../../../../../../common/constants'; +import { convertRulesFilterToKQL } from '../../../../../rule_management/logic/utils'; +import { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; type PrepareSearchFilterProps = | { selectedRuleIds: string[]; dryRunResult?: DryRunResult } diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/feature_tour/README.md b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/feature_tour/README.md similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/feature_tour/README.md rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/feature_tour/README.md diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/feature_tour/rules_feature_tour.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/feature_tour/rules_feature_tour.tsx similarity index 98% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/feature_tour/rules_feature_tour.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/feature_tour/rules_feature_tour.tsx index 9558aab5239bb..d2f64ec882840 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/feature_tour/rules_feature_tour.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/feature_tour/rules_feature_tour.tsx @@ -23,8 +23,8 @@ import { import { noop } from 'lodash'; import type { FC } from 'react'; import React, { useEffect, useMemo, useState } from 'react'; -import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '../../../../../../../common/constants'; -import { useKibana } from '../../../../../../common/lib/kibana'; +import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '../../../../../../common/constants'; +import { useKibana } from '../../../../../common/lib/kibana'; import * as i18n from './translations'; export interface RulesFeatureTourContextType { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/feature_tour/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/feature_tour/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/feature_tour/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/feature_tour/translations.ts diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/helpers.test.ts similarity index 60% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.test.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/helpers.test.ts index aa65c05db762c..babedf3c14905 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/helpers.test.ts @@ -6,52 +6,10 @@ */ import { Query } from '@elastic/eui'; -import { EXCEPTIONS_SEARCH_SCHEMA } from './exceptions/exceptions_search_bar'; -import { caseInsensitiveSort, getSearchFilters, showRulesTable } from './helpers'; +import { EXCEPTIONS_SEARCH_SCHEMA } from '../../../rule_exceptions_ui/pages/exceptions/exceptions_search_bar'; +import { caseInsensitiveSort, getSearchFilters } from './helpers'; describe('AllRulesTable Helpers', () => { - describe('showRulesTable', () => { - test('returns false when rulesCustomInstalled and rulesInstalled are null', () => { - const result = showRulesTable({ - rulesCustomInstalled: undefined, - rulesInstalled: undefined, - }); - expect(result).toBeFalsy(); - }); - - test('returns false when rulesCustomInstalled and rulesInstalled are 0', () => { - const result = showRulesTable({ - rulesCustomInstalled: 0, - rulesInstalled: 0, - }); - expect(result).toBeFalsy(); - }); - - test('returns false when both rulesCustomInstalled and rulesInstalled checks return false', () => { - const result = showRulesTable({ - rulesCustomInstalled: 0, - rulesInstalled: undefined, - }); - expect(result).toBeFalsy(); - }); - - test('returns true if rulesCustomInstalled is not null or 0', () => { - const result = showRulesTable({ - rulesCustomInstalled: 5, - rulesInstalled: undefined, - }); - expect(result).toBeTruthy(); - }); - - test('returns true if rulesInstalled is not null or 0', () => { - const result = showRulesTable({ - rulesCustomInstalled: undefined, - rulesInstalled: 5, - }); - expect(result).toBeTruthy(); - }); - }); - describe('caseInsensitiveSort', () => { describe('when an array of differently cased tags is passed', () => { const unsortedTags = ['atest', 'Ctest', 'Btest', 'ctest', 'btest', 'Atest']; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/helpers.ts similarity index 82% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/helpers.ts index bc95640d2d292..13666f514b0be 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/helpers.ts @@ -6,18 +6,8 @@ */ import type { Query } from '@elastic/eui'; -import type { ExportRulesDetails } from '../../../../../../common/detection_engine/schemas/response/export_rules_details_schema'; -import type { BulkActionSummary } from '../../../../containers/detection_engine/rules'; - -export const showRulesTable = ({ - rulesCustomInstalled, - rulesInstalled, -}: { - rulesCustomInstalled?: number; - rulesInstalled?: number; -}) => - (rulesCustomInstalled != null && rulesCustomInstalled > 0) || - (rulesInstalled != null && rulesInstalled > 0); +import type { ExportRulesDetails } from '../../../../../common/detection_engine/rule_management'; +import type { BulkActionSummary } from '../../../rule_management/logic'; export const caseInsensitiveSort = (tags: string[]): string[] => { return tags.sort((a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase())); // Case insensitive diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/index.tsx new file mode 100644 index 0000000000000..5e93508339980 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/index.tsx @@ -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 { EuiSpacer } from '@elastic/eui'; +import React, { useState } from 'react'; +import { RulesTables } from './rules_tables'; +import { AllRulesTabs, RulesTableToolbar } from './rules_table_toolbar'; + +/** + * Table Component for displaying all Rules for a given cluster. Provides the ability to filter + * by name, sort by enabled, and perform the following actions: + * * Enable/Disable + * * Duplicate + * * Delete + * * Import/Export + */ +export const AllRules = React.memo(() => { + const [activeTab, setActiveTab] = useState(AllRulesTabs.rules); + + return ( + <> + + + + + ); +}); + +AllRules.displayName = 'AllRules'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/popover_tooltip.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/popover_tooltip.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/popover_tooltip.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/popover_tooltip.tsx index 564f73c379c63..2d11e2e9a8009 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/popover_tooltip.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/popover_tooltip.tsx @@ -7,7 +7,7 @@ import React, { useState } from 'react'; import { EuiPopover, EuiButtonIcon } from '@elastic/eui'; -import * as i18n from '../translations'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; interface PopoverTooltipProps { columnName: string; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/__mocks__/rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/__mocks__/rules_table_context.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/__mocks__/rules_table_context.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/__mocks__/rules_table_context.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.tsx similarity index 96% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/rules_table_context.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.tsx index 91f7079011aa1..78c391d175747 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.tsx @@ -14,16 +14,16 @@ import React, { useState, useRef, } from 'react'; -import { DEFAULT_RULES_TABLE_REFRESH_SETTING } from '../../../../../../../common/constants'; -import { invariant } from '../../../../../../../common/utils/invariant'; -import { useKibana, useUiSetting$ } from '../../../../../../common/lib/kibana'; +import { DEFAULT_RULES_TABLE_REFRESH_SETTING } from '../../../../../../common/constants'; +import { invariant } from '../../../../../../common/utils/invariant'; +import { useKibana, useUiSetting$ } from '../../../../../common/lib/kibana'; import type { FilterOptions, PaginationOptions, Rule, SortingOptions, -} from '../../../../../containers/detection_engine/rules/types'; -import { useFindRules } from './use_find_rules'; +} from '../../../../rule_management/logic/types'; +import { useFindRulesInMemory } from './use_find_rules_in_memory'; import { getRulesComparator } from './utils'; export interface RulesTableState { @@ -121,7 +121,7 @@ export interface LoadingRules { } export interface RulesTableActions { - reFetchRules: ReturnType['refetch']; + reFetchRules: ReturnType['refetch']; setFilterOptions: (newFilter: Partial) => void; setIsAllSelected: React.Dispatch>; setIsInMemorySorting: (value: boolean) => void; @@ -239,7 +239,7 @@ export const RulesTableContextProvider = ({ children }: RulesTableContextProvide isFetching, isLoading, isRefetching, - } = useFindRules({ + } = useFindRulesInMemory({ isInMemorySorting, filterOptions, sortingOptions, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/use_async_confirmation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_async_confirmation.ts similarity index 97% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/use_async_confirmation.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_async_confirmation.ts index cce45f87d8ce3..3042906f87cf3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/use_async_confirmation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_async_confirmation.ts @@ -18,6 +18,7 @@ interface UseAsyncConfirmationArgs { onFinish: () => void; } +// TODO move to common hooks export const useAsyncConfirmation = ({ onInit, onFinish, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/use_find_rules.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory.ts similarity index 79% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/use_find_rules.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory.ts index 2cdd3ab4b8e46..c1429fddbd312 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/use_find_rules.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_find_rules_in_memory.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { FindRulesQueryArgs } from '../../../../../containers/detection_engine/rules/use_find_rules_query'; -import { useFindRulesQuery } from '../../../../../containers/detection_engine/rules/use_find_rules_query'; +import type { FindRulesQueryArgs } from '../../../../rule_management/api/hooks/use_find_rules_query'; +import { useFindRules } from '../../../../rule_management/logic/use_find_rules'; interface UseFindRulesArgs extends FindRulesQueryArgs { isInMemorySorting: boolean; @@ -23,12 +23,11 @@ const MAX_RULES_PER_PAGE = 10000; * @param args - find rules arguments * @returns rules query result */ -export const useFindRules = (args: UseFindRulesArgs) => { +export const useFindRulesInMemory = (args: UseFindRulesArgs) => { const { pagination, filterOptions, sortingOptions, isInMemorySorting, refetchInterval } = args; // Use this query result when isInMemorySorting = true - const allRules = useFindRulesQuery( - ['all'], + const allRules = useFindRules( { pagination: { page: 1, perPage: MAX_RULES_PER_PAGE }, filterOptions }, { refetchInterval, @@ -38,8 +37,7 @@ export const useFindRules = (args: UseFindRulesArgs) => { ); // Use this query result when isInMemorySorting = false - const pagedRules = useFindRulesQuery( - ['paged'], + const pagedRules = useFindRules( { pagination, filterOptions, sortingOptions }, { refetchInterval, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/utils.ts similarity index 95% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/utils.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/utils.ts index 13fe9230d2114..5382a740f8213 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table/utils.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/utils.ts @@ -6,7 +6,7 @@ */ import { get } from 'lodash'; -import type { Rule, SortingOptions } from '../../../../../containers/detection_engine/rules/types'; +import type { Rule, SortingOptions } from '../../../../rule_management/logic/types'; /** * Returns a comparator function to be used with .sort() diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx similarity index 84% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx index 1f266fd62ff82..784d3dfc62427 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx @@ -15,11 +15,13 @@ import { import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; import styled from 'styled-components'; -import { RULES_TABLE_ACTIONS } from '../../../../../../common/lib/apm/user_actions'; -import { useStartTransaction } from '../../../../../../common/lib/apm/use_start_transaction'; -import * as i18n from '../../translations'; +import { RULES_TABLE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; +import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; +import { usePrePackagedRulesStatus } from '../../../../rule_management/logic/use_pre_packaged_rules_status'; +import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { useRulesTableContext } from '../rules_table/rules_table_context'; import { TagsFilterPopover } from './tags_filter_popover'; +import { useTags } from '../../../../rule_management/logic/use_tags'; const FilterWrapper = styled(EuiFlexGroup)` margin-bottom: ${({ theme }) => theme.eui.euiSizeXS}; @@ -34,26 +36,20 @@ const SearchBarWrapper = styled(EuiFlexItem)` } `; -interface RulesTableFiltersProps { - rulesCustomInstalled?: number; - rulesInstalled?: number; - allTags: string[]; -} - /** * Collection of filters for filtering data within the RulesTable. Contains search bar, Elastic/Custom * Rules filter button toggle, and tag selection */ -const RulesTableFiltersComponent = ({ - rulesCustomInstalled, - rulesInstalled, - allTags, -}: RulesTableFiltersProps) => { +const RulesTableFiltersComponent = () => { const { startTransaction } = useStartTransaction(); const { state: { filterOptions }, actions: { setFilterOptions }, } = useRulesTableContext(); + const { data: allTags = [] } = useTags(); + const { data: prePackagedRulesStatus } = usePrePackagedRulesStatus(); + const rulesCustomInstalled = prePackagedRulesStatus?.rules_custom_installed; + const rulesInstalled = prePackagedRulesStatus?.rules_installed; const { showCustomRules, showElasticRules, tags: selectedTags } = filterOptions; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.test.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx index 683e36c391614..b74cf38cc9266 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover.tsx @@ -19,8 +19,8 @@ import { EuiPopoverTitle, } from '@elastic/eui'; import styled from 'styled-components'; -import * as i18n from '../../translations'; -import { toggleSelectedGroup } from '../../../../../../common/components/ml_popover/jobs_table/filters/toggle_selected_group'; +import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; +import { toggleSelectedGroup } from '../../../../../common/components/ml_popover/jobs_table/filters/toggle_selected_group'; import { caseInsensitiveSort } from '../helpers'; interface TagsFilterPopoverProps { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_toolbar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_toolbar.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_toolbar.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_toolbar.tsx index cf8d253dbcc89..7d9fda7203702 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_toolbar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_toolbar.tsx @@ -10,9 +10,9 @@ import { EuiSwitch, EuiTab, EuiTabs, EuiToolTip } from '@elastic/eui'; import React, { useCallback } from 'react'; import styled from 'styled-components'; import { useRulesTableContext } from './rules_table/rules_table_context'; -import * as i18n from '../translations'; -import { RULES_TABLE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; -import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; +import { RULES_TABLE_ACTIONS } from '../../../../common/lib/apm/user_actions'; +import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; const ToolbarLayout = styled.div` display: grid; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_utility_bar.test.tsx similarity index 67% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_utility_bar.test.tsx index 4fecfc4afa6a2..2b88020f4ff35 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_utility_bar.test.tsx @@ -10,26 +10,28 @@ import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; import { getShowingRulesParams, RulesTableUtilityBar } from './rules_table_utility_bar'; -import { TestProviders } from '../../../../../common/mock'; +import { TestProviders } from '../../../../common/mock'; +import { useRulesTableContextMock } from './rules_table/__mocks__/rules_table_context'; +import { useRulesTableContext } from './rules_table/rules_table_context'; jest.mock('./rules_table/rules_table_context'); describe('RulesTableUtilityBar', () => { it('renders RulesTableUtilityBar total rules and selected rules', () => { + const rulesTableContext = useRulesTableContextMock.create(); + rulesTableContext.state.pagination = { + page: 1, + perPage: 10, + total: 21, + }; + rulesTableContext.state.selectedRuleIds = ['testId']; + (useRulesTableContext as jest.Mock).mockReturnValue(rulesTableContext); + const wrapper = mount( @@ -43,45 +45,12 @@ describe('RulesTableUtilityBar', () => { ); }); - it('renders correct pagination label according to pagination data', () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('[data-test-subj="showingRules"]').at(0).text()).toEqual( - 'Showing 1-10 of 21 rules' - ); - }); - it('renders utility actions if user has permissions', () => { const wrapper = mount( @@ -95,16 +64,7 @@ describe('RulesTableUtilityBar', () => { @@ -113,22 +73,15 @@ describe('RulesTableUtilityBar', () => { expect(wrapper.find('[data-test-subj="bulkActions"]').exists()).toBeFalsy(); }); - it('invokes refresh on refresh action click', () => { - const mockRefresh = jest.fn(); + it('invokes rules refetch on refresh action click', () => { + const rulesTableContext = useRulesTableContextMock.create(); + (useRulesTableContext as jest.Mock).mockReturnValue(rulesTableContext); + const wrapper = mount( @@ -136,25 +89,19 @@ describe('RulesTableUtilityBar', () => { wrapper.find('[data-test-subj="refreshRulesAction"] button').at(0).simulate('click'); - expect(mockRefresh).toHaveBeenCalled(); + expect(rulesTableContext.actions.reFetchRules).toHaveBeenCalledTimes(1); }); - it('invokes onRefreshSwitch when auto refresh switch is clicked if there are not selected items', async () => { - const mockSwitch = jest.fn(); + it('invokes rule refetch when auto refresh switch is clicked if there are not selected items', async () => { + const rulesTableContext = useRulesTableContextMock.create(); + rulesTableContext.state.isRefreshOn = false; + (useRulesTableContext as jest.Mock).mockReturnValue(rulesTableContext); + const wrapper = mount( @@ -163,26 +110,21 @@ describe('RulesTableUtilityBar', () => { await waitFor(() => { wrapper.find('[data-test-subj="refreshSettings"] button').first().simulate('click'); wrapper.find('[data-test-subj="refreshSettingsSwitch"] button').first().simulate('click'); - expect(mockSwitch).toHaveBeenCalledTimes(1); + expect(rulesTableContext.actions.reFetchRules).toHaveBeenCalledTimes(1); }); }); it('does not invokes onRefreshSwitch when auto refresh switch is clicked if there are selected items', async () => { - const mockSwitch = jest.fn(); + const rulesTableContext = useRulesTableContextMock.create(); + rulesTableContext.state.isRefreshOn = false; + rulesTableContext.state.selectedRuleIds = ['testId']; + (useRulesTableContext as jest.Mock).mockReturnValue(rulesTableContext); + const wrapper = mount( @@ -191,7 +133,7 @@ describe('RulesTableUtilityBar', () => { await waitFor(() => { wrapper.find('[data-test-subj="refreshSettings"] button').first().simulate('click'); wrapper.find('[data-test-subj="refreshSettingsSwitch"] button').first().simulate('click'); - expect(mockSwitch).not.toHaveBeenCalled(); + expect(rulesTableContext.actions.reFetchRules).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_utility_bar.tsx similarity index 78% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_utility_bar.tsx index 7f9b0dba04881..7c91e27423697 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_utility_bar.tsx @@ -22,11 +22,13 @@ import { UtilityBarGroup, UtilityBarSection, UtilityBarText, -} from '../../../../../common/components/utility_bar'; -import * as i18n from '../translations'; -import { useKibana } from '../../../../../common/lib/kibana'; +} from '../../../../common/components/utility_bar'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; +import { useKibana } from '../../../../common/lib/kibana'; import { useRulesTableContext } from './rules_table/rules_table_context'; -import type { PaginationOptions } from '../../../../containers/detection_engine/rules/types'; +import type { PaginationOptions } from '../../../rule_management/logic/types'; +import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; +import { RULES_TABLE_ACTIONS } from '../../../../common/lib/apm/user_actions'; export const getShowingRulesParams = ({ page, perPage, total: totalRules }: PaginationOptions) => { const firstInPage = totalRules === 0 ? 0 : (page - 1) * perPage + 1; @@ -37,35 +39,27 @@ export const getShowingRulesParams = ({ page, perPage, total: totalRules }: Pagi interface RulesTableUtilityBarProps { canBulkEdit: boolean; - isAllSelected?: boolean; - isAutoRefreshOn?: boolean; - numberSelectedItems: number; onGetBulkItemsPopoverContent?: (closePopover: () => void) => EuiContextMenuPanelDescriptor[]; - onRefresh: () => void; - onRefreshSwitch: (checked: boolean) => void; onToggleSelectAll: () => void; - pagination: PaginationOptions; isBulkActionInProgress?: boolean; - hasDisabledActions?: boolean; } export const RulesTableUtilityBar = React.memo( - ({ - canBulkEdit, - isAllSelected, - isAutoRefreshOn, - numberSelectedItems, - onGetBulkItemsPopoverContent, - onRefresh, - onRefreshSwitch, - onToggleSelectAll, - pagination, - isBulkActionInProgress, - hasDisabledActions, - }) => { + ({ canBulkEdit, onGetBulkItemsPopoverContent, onToggleSelectAll, isBulkActionInProgress }) => { const { timelines } = useKibana().services; + const { startTransaction } = useStartTransaction(); const rulesTableContext = useRulesTableContext(); - const isAnyRuleSelected = numberSelectedItems > 0; + const { pagination, selectedRuleIds, isRefreshOn, isAllSelected, loadingRulesAction } = + rulesTableContext.state; + const { reFetchRules, setIsRefreshOn } = rulesTableContext.actions; + const selectedRulesCount = isAllSelected ? pagination.total : selectedRuleIds.length; + const isAnyRuleSelected = selectedRulesCount > 0; + const hasDisabledActions = loadingRulesAction != null; + + const handleRefreshRules = useCallback(() => { + startTransaction({ name: RULES_TABLE_ACTIONS.REFRESH }); + reFetchRules(); + }, [reFetchRules, startTransaction]); const handleGetBulkItemsPopoverContent = useCallback( (closePopover: () => void): JSX.Element | null => { @@ -85,12 +79,14 @@ export const RulesTableUtilityBar = React.memo( const handleAutoRefreshSwitch = useCallback( (closePopover: () => void) => (e: EuiSwitchEvent) => { - if (onRefreshSwitch != null) { - onRefreshSwitch(e.target.checked); - closePopover(); + const refreshOn = e.target.checked; + if (refreshOn) { + reFetchRules(); } + setIsRefreshOn(refreshOn); + closePopover(); }, - [onRefreshSwitch] + [reFetchRules, setIsRefreshOn] ); const handleGetRefreshSettingsPopoverContent = useCallback( @@ -100,7 +96,7 @@ export const RulesTableUtilityBar = React.memo( ( ]} /> ), - [isAutoRefreshOn, handleAutoRefreshSwitch, isAnyRuleSelected] + [isRefreshOn, handleAutoRefreshSwitch, isAnyRuleSelected] ); return ( @@ -136,7 +132,7 @@ export const RulesTableUtilityBar = React.memo( <> - {i18n.SELECTED_RULES(numberSelectedItems)} + {i18n.SELECTED_RULES(selectedRulesCount)} {canBulkEdit && ( @@ -170,7 +166,7 @@ export const RulesTableUtilityBar = React.memo( dataTestSubj="refreshRulesAction" iconSide="left" iconType="refresh" - onClick={onRefresh} + onClick={handleRefreshRules} > {i18n.REFRESH} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx new file mode 100644 index 0000000000000..4379674c9738f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx @@ -0,0 +1,290 @@ +/* + * 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 { + EuiBasicTable, + EuiConfirmModal, + EuiEmptyPrompt, + EuiLoadingContent, + EuiProgress, +} from '@elastic/eui'; +import React, { useCallback, useMemo, useRef } from 'react'; +import { RULES_TABLE_PAGE_SIZE_OPTIONS } from '../../../../../common/constants'; +import { Loader } from '../../../../common/components/loader'; +import { useBoolState } from '../../../../common/hooks/use_bool_state'; +import { useValueChanged } from '../../../../common/hooks/use_value_changed'; +import { PrePackagedRulesPrompt } from '../../../../detections/components/rules/pre_packaged_rules/load_empty_prompt'; +import type { Rule, RulesSortingFields } from '../../../rule_management/logic'; +import { usePrePackagedRulesStatus } from '../../../rule_management/logic/use_pre_packaged_rules_status'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; +import type { EuiBasicTableOnChange } from '../../../../detections/pages/detection_engine/rules/types'; +import { BulkActionDryRunConfirmation } from './bulk_actions/bulk_action_dry_run_confirmation'; +import { BulkEditFlyout } from './bulk_actions/bulk_edit_flyout'; +import { useBulkActions } from './bulk_actions/use_bulk_actions'; +import { useBulkActionsConfirmation } from './bulk_actions/use_bulk_actions_confirmation'; +import { useBulkActionsDryRun } from './bulk_actions/use_bulk_actions_dry_run'; +import { useBulkEditFormFlyout } from './bulk_actions/use_bulk_edit_form_flyout'; +import { useRulesTableContext } from './rules_table/rules_table_context'; +import { useAsyncConfirmation } from './rules_table/use_async_confirmation'; +import { RulesTableFilters } from './rules_table_filters/rules_table_filters'; +import { AllRulesTabs } from './rules_table_toolbar'; +import { RulesTableUtilityBar } from './rules_table_utility_bar'; +import { useMonitoringColumns, useRulesColumns } from './use_columns'; +import { useUserData } from '../../../../detections/components/user_info'; +import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; + +const INITIAL_SORT_FIELD = 'enabled'; + +interface RulesTableProps { + selectedTab: AllRulesTabs; +} + +const NO_ITEMS_MESSAGE = ( + {i18n.NO_RULES}} titleSize="xs" body={i18n.NO_RULES_BODY} /> +); + +/** + * Table Component for displaying all Rules for a given cluster. Provides the ability to filter + * by name, sort by enabled, and perform the following actions: + * * Enable/Disable + * * Duplicate + * * Delete + * * Import/Export + */ +// eslint-disable-next-line complexity +export const RulesTables = React.memo(({ selectedTab }) => { + const [{ canUserCRUD }] = useUserData(); + const hasPermissions = hasUserCRUDPermission(canUserCRUD); + + const tableRef = useRef(null); + const rulesTableContext = useRulesTableContext(); + const { data: prePackagedRulesStatus, isLoading: isPrepackagedStatusLoading } = + usePrePackagedRulesStatus(); + + const { + state: { + rules, + filterOptions, + isActionInProgress, + isAllSelected, + isFetched, + isLoading, + isRefetching, + loadingRuleIds, + loadingRulesAction, + pagination, + selectedRuleIds, + sortingOptions, + }, + actions: { setIsAllSelected, setPage, setPerPage, setSelectedRuleIds, setSortingOptions }, + } = rulesTableContext; + + const [isDeleteConfirmationVisible, showDeleteConfirmation, hideDeleteConfirmation] = + useBoolState(); + + const [confirmDeletion, handleDeletionConfirm, handleDeletionCancel] = useAsyncConfirmation({ + onInit: showDeleteConfirmation, + onFinish: hideDeleteConfirmation, + }); + + const { + bulkActionsDryRunResult, + bulkAction, + isBulkActionConfirmationVisible, + showBulkActionConfirmation, + cancelBulkActionConfirmation, + approveBulkActionConfirmation, + } = useBulkActionsConfirmation(); + + const { + bulkEditActionType, + isBulkEditFlyoutVisible, + handleBulkEditFormConfirm, + handleBulkEditFormCancel, + completeBulkEditForm, + } = useBulkEditFormFlyout(); + + const { isBulkActionsDryRunLoading, executeBulkActionsDryRun } = useBulkActionsDryRun(); + + const getBulkItemsPopoverContent = useBulkActions({ + filterOptions, + confirmDeletion, + showBulkActionConfirmation, + completeBulkEditForm, + executeBulkActionsDryRun, + }); + + const paginationMemo = useMemo( + () => ({ + pageIndex: pagination.page - 1, + pageSize: pagination.perPage, + totalItemCount: pagination.total, + pageSizeOptions: RULES_TABLE_PAGE_SIZE_OPTIONS, + }), + [pagination] + ); + + const tableOnChangeCallback = useCallback( + ({ page, sort }: EuiBasicTableOnChange) => { + setSortingOptions({ + field: (sort?.field as RulesSortingFields) ?? INITIAL_SORT_FIELD, // Narrowing EuiBasicTable sorting types + order: sort?.direction ?? 'desc', + }); + setPage(page.index + 1); + setPerPage(page.size); + }, + [setPage, setPerPage, setSortingOptions] + ); + + const rulesColumns = useRulesColumns({ hasCRUDPermissions: hasPermissions }); + const monitoringColumns = useMonitoringColumns({ hasCRUDPermissions: hasPermissions }); + + const isSelectAllCalled = useRef(false); + + // TODO Remove this synchronization logic after https://github.com/elastic/eui/issues/6184 is implemented + // Synchronize selectedRuleIds with EuiBasicTable's selected rows + useValueChanged((ruleIds) => { + if (tableRef.current != null) { + tableRef.current.setSelection(rules.filter((rule) => ruleIds.includes(rule.id))); + } + }, selectedRuleIds); + + const euiBasicTableSelectionProps = useMemo( + () => ({ + selectable: (item: Rule) => !loadingRuleIds.includes(item.id), + onSelectionChange: (selected: Rule[]) => { + /** + * EuiBasicTable doesn't provide declarative API to control selected rows. + * This limitation requires us to synchronize selection state manually using setSelection(). + * But it creates a chain reaction when the user clicks Select All: + * selectAll() -> setSelection() -> onSelectionChange() -> setSelection(). + * To break the chain we should check whether the onSelectionChange was triggered + * by the Select All action or not. + * + */ + if (isSelectAllCalled.current) { + isSelectAllCalled.current = false; + // Handle special case of unselecting all rules via checkbox + // after all rules were selected via Bulk select. + if (selected.length === 0) { + setIsAllSelected(false); + setSelectedRuleIds([]); + } + } else { + setSelectedRuleIds(selected.map(({ id }) => id)); + setIsAllSelected(false); + } + }, + }), + [loadingRuleIds, setIsAllSelected, setSelectedRuleIds] + ); + + const toggleSelectAll = useCallback(() => { + isSelectAllCalled.current = true; + setIsAllSelected(!isAllSelected); + setSelectedRuleIds(!isAllSelected ? rules.map(({ id }) => id) : []); + }, [rules, isAllSelected, setIsAllSelected, setSelectedRuleIds]); + + const isTableEmpty = + !isPrepackagedStatusLoading && + prePackagedRulesStatus?.rules_custom_installed === 0 && + prePackagedRulesStatus.rules_installed === 0; + + const shouldShowRulesTable = !isPrepackagedStatusLoading && !isLoading && !isTableEmpty; + + const tableProps = + selectedTab === AllRulesTabs.rules + ? { + 'data-test-subj': 'rules-table', + columns: rulesColumns, + } + : { 'data-test-subj': 'monitoring-table', columns: monitoringColumns }; + + const shouldShowLinearProgress = isFetched && isRefetching; + const shouldShowLoadingOverlay = (!isFetched && isRefetching) || isActionInProgress; + + return ( + <> + {shouldShowLinearProgress && ( + + )} + {shouldShowLoadingOverlay && ( + + )} + {shouldShowRulesTable && } + {isTableEmpty && } + {isLoading && ( + + )} + {isDeleteConfirmationVisible && ( + +

    {i18n.DELETE_CONFIRMATION_BODY}

    +
    + )} + {isBulkActionConfirmationVisible && bulkAction && ( + + )} + {isBulkEditFlyoutVisible && bulkEditActionType !== undefined && ( + + )} + {shouldShowRulesTable && ( + <> + + + + )} + + ); +}); + +RulesTables.displayName = 'RulesTables'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/table_header_tooltip_cell.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/table_header_tooltip_cell.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/table_header_tooltip_cell.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/table_header_tooltip_cell.test.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/table_header_tooltip_cell.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/table_header_tooltip_cell.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/table_header_tooltip_cell.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/table_header_tooltip_cell.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx similarity index 77% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx index c5032a1eb9b72..e169faa0be3a8 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx @@ -8,50 +8,49 @@ import type { EuiBasicTableColumn, EuiTableActionsColumnType } from '@elastic/eui'; import { EuiBadge, EuiLink, EuiText, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useMemo } from 'react'; import moment from 'moment'; -import { IntegrationsPopover } from '../../../../components/rules/related_integrations/integrations_popover'; +import React, { useMemo } from 'react'; import { DEFAULT_RELATIVE_DATE_THRESHOLD, SecurityPageName, SHOW_RELATED_INTEGRATIONS_SETTING, -} from '../../../../../../common/constants'; -import { isMlRule } from '../../../../../../common/machine_learning/helpers'; -import { getEmptyTagValue } from '../../../../../common/components/empty_value'; -import { FormattedRelativePreferenceDate } from '../../../../../common/components/formatted_date'; -import { getRuleDetailsTabUrl } from '../../../../../common/components/link_to/redirect_to_detection_engine'; -import { PopoverItems } from '../../../../../common/components/popover_items'; -import { useKibana, useUiSetting$ } from '../../../../../common/lib/kibana'; -import { canEditRuleWithActions, getToolTipContent } from '../../../../../common/utils/privileges'; -import { RuleSwitch } from '../../../../components/rules/rule_switch'; -import { SeverityBadge } from '../../../../components/rules/severity_badge'; -import type { Rule } from '../../../../containers/detection_engine/rules'; -import { useRulesTableContext } from './rules_table/rules_table_context'; -import * as i18n from '../translations'; +} from '../../../../../common/constants'; +import type { + DurationMetric, + RuleExecutionSummary, +} from '../../../../../common/detection_engine/rule_monitoring'; +import { isMlRule } from '../../../../../common/machine_learning/helpers'; +import { getEmptyTagValue } from '../../../../common/components/empty_value'; +import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; +import { SecuritySolutionLinkAnchor } from '../../../../common/components/links'; +import { getRuleDetailsTabUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; +import { PopoverItems } from '../../../../common/components/popover_items'; +import { useKibana, useUiSetting$ } from '../../../../common/lib/kibana'; +import { + canEditRuleWithActions, + explainLackOfPermission, +} from '../../../../common/utils/privileges'; +import { IntegrationsPopover } from '../../../../detections/components/rules/related_integrations/integrations_popover'; +import { RuleStatusBadge } from '../../../../detections/components/rules/rule_execution_status'; +import { RuleSwitch } from '../../../../detections/components/rules/rule_switch'; +import { SeverityBadge } from '../../../../detections/components/rules/severity_badge'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; +import { RuleDetailTabs } from '../../../rule_details_ui/pages/rule_details'; +import type { Rule } from '../../../rule_management/logic'; import { PopoverTooltip } from './popover_tooltip'; +import { useRulesTableContext } from './rules_table/rules_table_context'; import { TableHeaderTooltipCell } from './table_header_tooltip_cell'; import { useHasActionsPrivileges } from './use_has_actions_privileges'; import { useHasMlPermissions } from './use_has_ml_permissions'; -import { getRulesTableActions } from './rules_table_actions'; -import { RuleStatusBadge } from '../../../../components/rules/rule_execution_status'; -import type { - DurationMetric, - RuleExecutionSummary, -} from '../../../../../../common/detection_engine/rule_monitoring'; -import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; -import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; -import { useInvalidateRules } from '../../../../containers/detection_engine/rules/use_find_rules_query'; -import { useInvalidatePrePackagedRulesStatus } from '../../../../containers/detection_engine/rules/use_pre_packaged_rules_status'; -import { SecuritySolutionLinkAnchor } from '../../../../../common/components/links'; -import { RuleDetailTabs } from '../details'; +import { useRulesTableActions } from './use_rules_table_actions'; export type TableColumn = EuiBasicTableColumn | EuiTableActionsColumnType; interface ColumnsProps { - hasPermissions: boolean; + hasCRUDPermissions: boolean; } -const useEnabledColumn = ({ hasPermissions }: ColumnsProps): TableColumn => { +const useEnabledColumn = ({ hasCRUDPermissions }: ColumnsProps): TableColumn => { const hasMlPermissions = useHasMlPermissions(); const hasActionsPrivileges = useHasActionsPrivileges(); const { loadingRulesAction, loadingRuleIds } = useRulesTableContext().state; @@ -68,14 +67,19 @@ const useEnabledColumn = ({ hasPermissions }: ColumnsProps): TableColumn => { render: (_, rule: Rule) => ( { width: '95px', sortable: true, }), - [hasActionsPrivileges, hasMlPermissions, hasPermissions, loadingIds] + [hasActionsPrivileges, hasMlPermissions, hasCRUDPermissions, loadingIds] ); }; @@ -162,42 +166,14 @@ const INTEGRATIONS_COLUMN: TableColumn = { }; const useActionsColumn = (): EuiTableActionsColumnType => { - const { navigateToApp } = useKibana().services.application; - const hasActionsPrivileges = useHasActionsPrivileges(); - const toasts = useAppToasts(); - const { setLoadingRules } = useRulesTableContext().actions; - const { startTransaction } = useStartTransaction(); - const invalidateRules = useInvalidateRules(); - const invalidatePrePackagedRulesStatus = useInvalidatePrePackagedRulesStatus(); + const actions = useRulesTableActions(); - return useMemo( - () => ({ - actions: getRulesTableActions({ - toasts, - navigateToApp, - invalidateRules, - invalidatePrePackagedRulesStatus, - actionsPrivileges: hasActionsPrivileges, - setLoadingRules, - startTransaction, - }), - width: '40px', - }), - [ - hasActionsPrivileges, - invalidatePrePackagedRulesStatus, - invalidateRules, - navigateToApp, - setLoadingRules, - startTransaction, - toasts, - ] - ); + return useMemo(() => ({ actions, width: '40px' }), [actions]); }; -export const useRulesColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] => { +export const useRulesColumns = ({ hasCRUDPermissions }: ColumnsProps): TableColumn[] => { const actionsColumn = useActionsColumn(); - const enabledColumn = useEnabledColumn({ hasPermissions }); + const enabledColumn = useEnabledColumn({ hasCRUDPermissions }); const ruleNameColumn = useRuleNameColumn(); const { isInMemorySorting } = useRulesTableContext().state; const [showRelatedIntegrations] = useUiSetting$(SHOW_RELATED_INTEGRATIONS_SETTING); @@ -292,12 +268,12 @@ export const useRulesColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] width: '65px', }, enabledColumn, - ...(hasPermissions ? [actionsColumn] : []), + ...(hasCRUDPermissions ? [actionsColumn] : []), ], [ actionsColumn, enabledColumn, - hasPermissions, + hasCRUDPermissions, isInMemorySorting, ruleNameColumn, showRelatedIntegrations, @@ -305,10 +281,10 @@ export const useRulesColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] ); }; -export const useMonitoringColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] => { +export const useMonitoringColumns = ({ hasCRUDPermissions }: ColumnsProps): TableColumn[] => { const docLinks = useKibana().services.docLinks; const actionsColumn = useActionsColumn(); - const enabledColumn = useEnabledColumn({ hasPermissions }); + const enabledColumn = useEnabledColumn({ hasCRUDPermissions }); const ruleNameColumn = useRuleNameColumn(); const { isInMemorySorting } = useRulesTableContext().state; const [showRelatedIntegrations] = useUiSetting$(SHOW_RELATED_INTEGRATIONS_SETTING); @@ -425,13 +401,13 @@ export const useMonitoringColumns = ({ hasPermissions }: ColumnsProps): TableCol width: '16%', }, enabledColumn, - ...(hasPermissions ? [actionsColumn] : []), + ...(hasCRUDPermissions ? [actionsColumn] : []), ], [ actionsColumn, docLinks.links.siem.troubleshootGaps, enabledColumn, - hasPermissions, + hasCRUDPermissions, isInMemorySorting, ruleNameColumn, showRelatedIntegrations, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_has_actions_privileges.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_has_actions_privileges.ts similarity index 78% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_has_actions_privileges.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_has_actions_privileges.ts index c2acbed3158f1..fddf86e97646d 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_has_actions_privileges.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_has_actions_privileges.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { useKibana } from '../../../../../common/lib/kibana'; -import { isBoolean } from '../../../../../common/utils/privileges'; +import { useKibana } from '../../../../common/lib/kibana'; +import { isBoolean } from '../../../../common/utils/privileges'; export const useHasActionsPrivileges = () => { const { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_has_ml_permissions.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_has_ml_permissions.ts similarity index 62% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_has_ml_permissions.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_has_ml_permissions.ts index c941ba7183b86..cedec36b33ebd 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_has_ml_permissions.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_has_ml_permissions.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { hasMlAdminPermissions } from '../../../../../../common/machine_learning/has_ml_admin_permissions'; -import { hasMlLicense } from '../../../../../../common/machine_learning/has_ml_license'; -import { useMlCapabilities } from '../../../../../common/components/ml/hooks/use_ml_capabilities'; +import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; +import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; +import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; export const useHasMlPermissions = () => { const mlCapabilities = useMlCapabilities(); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx new file mode 100644 index 0000000000000..6e0e2bb761007 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx @@ -0,0 +1,122 @@ +/* + * 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 { DefaultItemAction } from '@elastic/eui'; +import { EuiToolTip } from '@elastic/eui'; +import React from 'react'; +import { BulkAction } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions'; +import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; +import { useKibana } from '../../../../common/lib/kibana'; +import { canEditRuleWithActions } from '../../../../common/utils/privileges'; +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; +import type { Rule } from '../../../rule_management/logic'; +import { + downloadExportedRules, + useBulkExport, +} from '../../../rule_management/logic/bulk_actions/use_bulk_export'; +import { + goToRuleEditPage, + useExecuteBulkAction, +} from '../../../rule_management/logic/bulk_actions/use_execute_bulk_action'; +import { useRulesTableContext } from './rules_table/rules_table_context'; +import { useHasActionsPrivileges } from './use_has_actions_privileges'; + +export const useRulesTableActions = (): Array> => { + const { navigateToApp } = useKibana().services.application; + const hasActionsPrivileges = useHasActionsPrivileges(); + const toasts = useAppToasts(); + const { setLoadingRules } = useRulesTableContext().actions; + const { startTransaction } = useStartTransaction(); + const { executeBulkAction } = useExecuteBulkAction(); + const { bulkExport } = useBulkExport(); + + return [ + { + type: 'icon', + 'data-test-subj': 'editRuleAction', + description: i18n.EDIT_RULE_SETTINGS, + name: !hasActionsPrivileges ? ( + + <>{i18n.EDIT_RULE_SETTINGS} + + ) : ( + i18n.EDIT_RULE_SETTINGS + ), + icon: 'controlsHorizontal', + onClick: (rule: Rule) => goToRuleEditPage(rule.id, navigateToApp), + enabled: (rule: Rule) => canEditRuleWithActions(rule, hasActionsPrivileges), + }, + { + type: 'icon', + 'data-test-subj': 'duplicateRuleAction', + description: i18n.DUPLICATE_RULE, + icon: 'copy', + name: !hasActionsPrivileges ? ( + + <>{i18n.DUPLICATE_RULE} + + ) : ( + i18n.DUPLICATE_RULE + ), + enabled: (rule: Rule) => canEditRuleWithActions(rule, hasActionsPrivileges), + // TODO extract those handlers to hooks, like useDuplicateRule + onClick: async (rule: Rule) => { + startTransaction({ name: SINGLE_RULE_ACTIONS.DUPLICATE }); + const result = await executeBulkAction({ + action: BulkAction.duplicate, + setLoadingRules, + visibleRuleIds: [rule.id], + search: { ids: [rule.id] }, + }); + const createdRules = result?.attributes.results.created; + if (createdRules?.length) { + goToRuleEditPage(createdRules[0].id, navigateToApp); + } + }, + }, + { + type: 'icon', + 'data-test-subj': 'exportRuleAction', + description: i18n.EXPORT_RULE, + icon: 'exportAction', + name: i18n.EXPORT_RULE, + onClick: async (rule: Rule) => { + startTransaction({ name: SINGLE_RULE_ACTIONS.EXPORT }); + const response = await bulkExport({ + setLoadingRules, + visibleRuleIds: [rule.id], + search: { ids: [rule.id] }, + }); + if (response) { + await downloadExportedRules({ + response, + toasts, + }); + } + }, + enabled: (rule: Rule) => !rule.immutable, + }, + { + type: 'icon', + 'data-test-subj': 'deleteRuleAction', + description: i18n.DELETE_RULE, + icon: 'trash', + name: i18n.DELETE_RULE, + onClick: async (rule: Rule) => { + startTransaction({ name: SINGLE_RULE_ACTIONS.DELETE }); + await executeBulkAction({ + action: BulkAction.delete, + setLoadingRules, + visibleRuleIds: [rule.id], + search: { ids: [rule.id] }, + }); + }, + }, + ]; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx new file mode 100644 index 0000000000000..194e16fdb8e4b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx @@ -0,0 +1,163 @@ +/* + * 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 React from 'react'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; + +import { APP_UI_ID } from '../../../../../common/constants'; +import { SecurityPageName } from '../../../../app/types'; +import { HeaderPage } from '../../../../common/components/header_page'; +import { ImportDataModal } from '../../../../common/components/import_data_modal'; +import { SecuritySolutionLinkButton } from '../../../../common/components/links'; +import { getDetectionEngineUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; +import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; +import { useBoolState } from '../../../../common/hooks/use_bool_state'; +import { useKibana } from '../../../../common/lib/kibana'; +import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; +import { SpyRoute } from '../../../../common/utils/route/spy_routes'; + +import { MissingPrivilegesCallOut } from '../../../../detections/components/callouts/missing_privileges_callout'; +import { MlJobCompatibilityCallout } from '../../../../detections/components/callouts/ml_job_compatibility_callout'; +import { NeedAdminForUpdateRulesCallOut } from '../../../../detections/components/callouts/need_admin_for_update_callout'; +import { LoadPrePackagedRules } from '../../../../detections/components/rules/pre_packaged_rules/load_prepackaged_rules'; +import { LoadPrePackagedRulesButton } from '../../../../detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button'; +import { UpdatePrePackagedRulesCallOut } from '../../../../detections/components/rules/pre_packaged_rules/update_callout'; +import { ValueListsFlyout } from '../../../../detections/components/value_lists_management_flyout'; +import { useUserData } from '../../../../detections/components/user_info'; +import { useListsConfig } from '../../../../detections/containers/detection_engine/lists/use_lists_config'; +import { redirectToDetections } from '../../../../detections/pages/detection_engine/rules/helpers'; + +import { useInvalidateFindRulesQuery } from '../../../rule_management/api/hooks/use_find_rules_query'; +import { importRules } from '../../../rule_management/logic'; +import { usePrePackagedRulesInstallationStatus } from '../../../rule_management/logic/use_pre_packaged_rules_installation_status'; +import { usePrePackagedTimelinesInstallationStatus } from '../../../rule_management/logic/use_pre_packaged_timelines_installation_status'; + +import { AllRules } from '../../components/rules_table'; +import { RulesTableContextProvider } from '../../components/rules_table/rules_table/rules_table_context'; + +import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; + +const RulesPageComponent: React.FC = () => { + const [isImportModalVisible, showImportModal, hideImportModal] = useBoolState(); + const [isValueListFlyoutVisible, showValueListFlyout, hideValueListFlyout] = useBoolState(); + const { navigateToApp } = useKibana().services.application; + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + + const [ + { + loading: userInfoLoading, + isSignalIndexExists, + isAuthenticated, + hasEncryptionKey, + canUserCRUD, + }, + ] = useUserData(); + const { + loading: listsConfigLoading, + canWriteIndex: canWriteListsIndex, + needsConfiguration: needsListsConfiguration, + } = useListsConfig(); + const loading = userInfoLoading || listsConfigLoading; + const prePackagedRuleStatus = usePrePackagedRulesInstallationStatus(); + const prePackagedTimelineStatus = usePrePackagedTimelinesInstallationStatus(); + + if ( + redirectToDetections( + isSignalIndexExists, + isAuthenticated, + hasEncryptionKey, + needsListsConfiguration + ) + ) { + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.alerts, + path: getDetectionEngineUrl(), + }); + return null; + } + + return ( + <> + + + + + + + + + + + + + {(renderProps) => } + + + + + + {i18n.IMPORT_VALUE_LISTS} + + + + + + {i18n.IMPORT_RULE} + + + + + {i18n.ADD_NEW_RULE} + + + + + {(prePackagedRuleStatus === 'ruleNeedUpdate' || + prePackagedTimelineStatus === 'timelineNeedUpdate') && ( + + )} + + + + + + + ); +}; + +export const RulesPage = React.memo(RulesPageComponent); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 14c55ef74d186..e6756cf599929 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -177,7 +177,7 @@ export const AlertsTableComponent: React.FC = ({ id: tableId, loadingText: i18n.LOADING_ALERTS, queryFields: requiredFieldsForActions, - title: '', + title: i18n.ALERTS_DOCUMENT_TYPE, showCheckboxes: true, }) ); 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 25853c932a185..842cdfe82fffb 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 @@ -11,7 +11,7 @@ import { EuiButtonIcon, EuiContextMenuPanel, EuiPopover, EuiToolTip } from '@ela import { indexOf } from 'lodash'; import type { ConnectedProps } from 'react-redux'; import { connect } from 'react-redux'; -import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; +import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { get } from 'lodash/fp'; import { DEFAULT_ACTION_BUTTON_WIDTH } from '@kbn/timelines-plugin/public'; import { isActiveTimeline } from '../../../../helpers'; @@ -42,6 +42,7 @@ import { ATTACH_ALERT_TO_CASE_FOR_ROW } from '../../../../timelines/components/t import { useEventFilterAction } from './use_event_filter_action'; import { useAddToCaseActions } from './use_add_to_case_actions'; import { isAlertFromEndpointAlert } from '../../../../common/utils/endpoint_alert_check'; +import type { Rule } from '../../../../detection_engine/rule_management/logic/types'; interface AlertContextMenuProps { ariaLabel?: string; @@ -100,7 +101,6 @@ const AlertContextMenuComponent: React.FC indexOf(ecsRowData.event?.kind, 'event') !== -1, [ecsRowData]); const isAgentEndpoint = useMemo(() => ecsRowData.agent?.type?.includes('endpoint'), [ecsRowData]); - const isEndpointEvent = useMemo(() => isEvent && isAgentEndpoint, [isEvent, isAgentEndpoint]); const scopeIdAllowsAddEndpointEventFilter = useMemo( () => scopeId === TableId.hostsPageEvents || scopeId === TableId.usersPageEvents, @@ -147,16 +147,19 @@ const AlertContextMenuComponent: React.FC { + (type?: ExceptionListTypeEnum) => { onAddExceptionTypeClick(type); closePopover(); }, @@ -251,22 +254,19 @@ const AlertContextMenuComponent: React.FC
    )} - {exceptionFlyoutType != null && - ruleId != null && - ruleName != null && - ecsRowData?._id != null && ( - - )} + {openAddExceptionFlyout && ruleId != null && ruleName != null && ecsRowData?._id != null && ( + + )} {isAddEventFilterModalOpen && ecsRowData != null && ( )} @@ -301,9 +301,19 @@ export const AlertContextMenu = connector(React.memo(AlertContextMenuComponent)) type AddExceptionFlyoutWrapperProps = Omit< AddExceptionFlyoutProps, - 'alertData' | 'isAlertDataLoading' + | 'alertData' + | 'isAlertDataLoading' + | 'isEndpointItem' + | 'rules' + | 'isBulkAction' + | 'showAlertCloseOptions' > & { eventId?: string; + ruleId: Rule['id']; + ruleIndices: Rule['index']; + ruleDataViewId: Rule['data_view_id']; + ruleName: Rule['name']; + exceptionListType: ExceptionListTypeEnum | null; }; /** @@ -312,15 +322,15 @@ type AddExceptionFlyoutWrapperProps = Omit< * we cannot use the fetch hook within the flyout component itself */ export const AddExceptionFlyoutWrapper: React.FC = ({ - ruleName, ruleId, ruleIndices, + ruleDataViewId, + ruleName, exceptionListType, eventId, onCancel, onConfirm, alertStatus, - onRuleChange, }) => { const { loading: isSignalIndexLoading, signalIndexName } = useSignalIndex(); @@ -354,8 +364,8 @@ export const AddExceptionFlyoutWrapper: React.FC ? enrichedAlert.signal.rule.index : [enrichedAlert.signal.rule.index]; } - return []; - }, [enrichedAlert]); + return ruleIndices; + }, [enrichedAlert, ruleIndices]); const memoDataViewId = useMemo(() => { if ( @@ -364,23 +374,51 @@ export const AddExceptionFlyoutWrapper: React.FC ) { return enrichedAlert['kibana.alert.rule.parameters'].data_view_id; } - }, [enrichedAlert]); - const isLoading = isLoadingAlertData && isSignalIndexLoading; + return ruleDataViewId; + }, [enrichedAlert, ruleDataViewId]); + + // TODO: Do we want to notify user when they are working off of an older version of a rule + // if they select to add an exception from an alert referencing an older rule version? + const memoRule = useMemo(() => { + if (enrichedAlert != null && enrichedAlert['kibana.alert.rule.parameters'] != null) { + return [ + { + ...enrichedAlert['kibana.alert.rule.parameters'], + id: ruleId, + name: ruleName, + index: memoRuleIndices, + data_view_id: memoDataViewId, + }, + ] as Rule[]; + } + + return [ + { + id: ruleId, + name: ruleName, + index: memoRuleIndices, + data_view_id: memoDataViewId, + }, + ] as Rule[]; + }, [enrichedAlert, memoDataViewId, memoRuleIndices, ruleId, ruleName]); + + const isLoading = + (isLoadingAlertData && isSignalIndexLoading) || + enrichedAlert == null || + memoRuleIndices == null; return ( ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx index e0a09be0873d6..e63cbcc4c22d8 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx @@ -7,14 +7,14 @@ import React, { useCallback, useMemo } from 'react'; import { EuiContextMenuItem } from '@elastic/eui'; -import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; +import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { useUserData } from '../../user_info'; import { ACTION_ADD_ENDPOINT_EXCEPTION, ACTION_ADD_EXCEPTION } from '../translations'; interface UseExceptionActionProps { isEndpointAlert: boolean; - onAddExceptionTypeClick: (type: ExceptionListType) => void; + onAddExceptionTypeClick: (type?: ExceptionListTypeEnum) => void; } export const useExceptionActions = ({ @@ -24,11 +24,11 @@ export const useExceptionActions = ({ const [{ canUserCRUD, hasIndexWrite }] = useUserData(); const handleDetectionExceptionModal = useCallback(() => { - onAddExceptionTypeClick('detection'); + onAddExceptionTypeClick(); }, [onAddExceptionTypeClick]); const handleEndpointExceptionModal = useCallback(() => { - onAddExceptionTypeClick('endpoint'); + onAddExceptionTypeClick(ExceptionListTypeEnum.ENDPOINT); }, [onAddExceptionTypeClick]); const disabledAddEndpointException = !canUserCRUD || !hasIndexWrite || !isEndpointAlert; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_flyout.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_flyout.tsx index aff1c943110c0..85892f4ba5b53 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_flyout.tsx @@ -5,63 +5,66 @@ * 2.0. */ -import { useCallback, useMemo, useState } from 'react'; -import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; +import { useCallback, useState } from 'react'; +import type { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { DEFAULT_INDEX_PATTERN } from '../../../../../common/constants'; import type { inputsModel } from '../../../../common/store'; interface UseExceptionFlyoutProps { - ruleIndex: string[] | null | undefined; refetch?: inputsModel.Refetch; + onRuleChange?: () => void; isActiveTimelines: boolean; } interface UseExceptionFlyout { - exceptionFlyoutType: ExceptionListType | null; - onAddExceptionTypeClick: (type: ExceptionListType) => void; - onAddExceptionCancel: () => void; - onAddExceptionConfirm: (didCloseAlert: boolean, didBulkCloseAlert: boolean) => void; - ruleIndices: string[]; + exceptionFlyoutType: ExceptionListTypeEnum | null; + openAddExceptionFlyout: boolean; + onAddExceptionTypeClick: (type?: ExceptionListTypeEnum) => void; + onAddExceptionCancel: (didRuleChange: boolean) => void; + onAddExceptionConfirm: ( + didRuleChange: boolean, + didCloseAlert: boolean, + didBulkCloseAlert: boolean + ) => void; } export const useExceptionFlyout = ({ - ruleIndex, refetch, + onRuleChange, isActiveTimelines, }: UseExceptionFlyoutProps): UseExceptionFlyout => { - const [exceptionFlyoutType, setOpenAddExceptionFlyout] = useState(null); - - const ruleIndices = useMemo((): string[] => { - if (ruleIndex != null) { - return ruleIndex; - } else { - return DEFAULT_INDEX_PATTERN; - } - }, [ruleIndex]); + const [openAddExceptionFlyout, setOpenAddExceptionFlyout] = useState(false); + const [exceptionFlyoutType, setExceptionFlyoutType] = useState( + null + ); - const onAddExceptionTypeClick = useCallback((exceptionListType: ExceptionListType): void => { - setOpenAddExceptionFlyout(exceptionListType); + const onAddExceptionTypeClick = useCallback((exceptionListType?: ExceptionListTypeEnum): void => { + setExceptionFlyoutType(exceptionListType ?? null); + setOpenAddExceptionFlyout(true); }, []); const onAddExceptionCancel = useCallback(() => { - setOpenAddExceptionFlyout(null); + setExceptionFlyoutType(null); + setOpenAddExceptionFlyout(false); }, []); const onAddExceptionConfirm = useCallback( - (didCloseAlert: boolean, didBulkCloseAlert) => { + (didRuleChange: boolean, didCloseAlert: boolean, didBulkCloseAlert) => { if (refetch && (isActiveTimelines === false || didBulkCloseAlert)) { refetch(); } - setOpenAddExceptionFlyout(null); + if (onRuleChange != null && didRuleChange) { + onRuleChange(); + } + setOpenAddExceptionFlyout(false); }, - [refetch, isActiveTimelines] + [onRuleChange, refetch, isActiveTimelines] ); return { exceptionFlyoutType, + openAddExceptionFlyout, onAddExceptionTypeClick, onAddExceptionCancel, onAddExceptionConfirm, - ruleIndices, }; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx index 32f2d9d889945..c0c3b35a72ac6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx @@ -67,7 +67,6 @@ export const useAlertsActions = ({ setEventsDeleted, onUpdateSuccess: onStatusUpdate, onUpdateFailure: onStatusUpdate, - scopeId, }); return { 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 f084bb68311a3..cf9711c58f8cb 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 @@ -36,7 +36,8 @@ import * as i18nRiskScore from '../risk_score_mapping/translations'; import type { RequiredFieldArray, Threshold, -} from '../../../../../common/detection_engine/schemas/common'; +} from '../../../../../common/detection_engine/rule_schema'; + import * as i18n from './translations'; import type { BuildQueryBarDescription, BuildThreatDescription, ListItems } from './types'; import { SeverityBadge } from '../severity_badge'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.test.tsx index 63d2c52323583..aeba71acb6ab8 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.test.tsx @@ -21,7 +21,7 @@ import { FilterStateStore } from '@kbn/es-query'; import { mockAboutStepRule, mockDefineStepRule, -} from '../../../pages/detection_engine/rules/all/__mocks__/mock'; +} from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import { coreMock } from '@kbn/core/public/mocks'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; import * as i18n from './translations'; 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 ba0359c4fda3e..92879c56e9885 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 @@ -18,7 +18,7 @@ import { buildRelatedIntegrationsDescription } from '../related_integrations/int import type { RelatedIntegrationArray, RequiredFieldArray, -} from '../../../../../common/detection_engine/schemas/common'; +} from '../../../../../common/detection_engine/rule_schema'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; import type { EqlOptionsSelected } from '../../../../../common/search_strategy'; import { useKibana } from '../../../../common/lib/kibana'; @@ -48,7 +48,7 @@ import { buildMlJobsDescription } from './ml_job_description'; import { buildActionsDescription } from './actions_description'; import { buildThrottleDescription } from './throttle_description'; import { THREAT_QUERY_LABEL } from './translations'; -import { filterEmptyThreats } from '../../../pages/detection_engine/rules/create/helpers'; +import { filterEmptyThreats } from '../../../../detection_engine/rule_creation_ui/pages/rule_creation/helpers'; const DescriptionListContainer = styled(EuiDescriptionList)` &.euiDescriptionList--column .euiDescriptionList__title { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx index c9dcb19c64e81..b5342934302b3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx @@ -73,7 +73,7 @@ const Wrapper = styled.div` `; const MlJobDescriptionComponent: React.FC<{ jobId: string }> = ({ jobId }) => { - const { jobs } = useSecurityJobs(false); + const { jobs } = useSecurityJobs(); const { services: { http, ml }, } = useKibana(); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.test.tsx index f30fd074f0d45..51e1e0683d766 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { shallow, mount } from 'enzyme'; import { mockIndexPattern, TestProviders, useFormFieldMock } from '../../../../common/mock'; -import { mockQueryBar } from '../../../pages/detection_engine/rules/all/__mocks__/mock'; +import { mockQueryBar } from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import type { EqlQueryBarProps } from './eql_query_bar'; import { EqlQueryBar } from './eql_query_bar'; import { getEqlValidationError } from './validators.mock'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx index d77b52a227cdf..a067930ca78ed 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx @@ -67,7 +67,7 @@ const renderJobOption = (option: MlJobOption) => ( export const MlJobSelect: React.FC = ({ describedByIds = [], field }) => { const jobIds = field.value as string[]; const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - const { loading, jobs } = useSecurityJobs(false); + const { loading, jobs } = useSecurityJobs(); const mlUrl = useKibana().services.application.getUrlForApp('ml'); const handleJobSelect = useCallback( (selectedJobOptions: MlJobOption[]): void => { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.test.tsx index b33281a165b8d..bd1b951a7002f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.test.tsx @@ -13,7 +13,7 @@ import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; import { TestProviders } from '../../../../common/mock'; import '../../../../common/mock/match_media'; -import { getPrePackagedRulesStatus } from '../../../containers/detection_engine/rules/api'; +import { getPrePackagedRulesStatus } from '../../../../detection_engine/rule_management/api/api'; import { PrePackagedRulesPrompt } from './load_empty_prompt'; jest.mock('react-router-dom', () => { @@ -43,7 +43,7 @@ jest.mock('../../../../common/lib/kibana/kibana_react', () => { }; }); -jest.mock('../../../containers/detection_engine/rules/api', () => ({ +jest.mock('../../../../detection_engine/rule_management/api/api', () => ({ getPrePackagedRulesStatus: jest.fn().mockResolvedValue({ rules_not_installed: 0, rules_installed: 0, diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.tsx index 252787c9dd853..f44008622eb9e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_empty_prompt.tsx @@ -6,17 +6,15 @@ */ import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { memo, useCallback, useMemo, useState } from 'react'; +import React, { memo } from 'react'; import styled from 'styled-components'; -import { affectedJobIds } from '../../callouts/ml_job_compatibility_callout/affected_job_ids'; -import { MlJobUpgradeModal } from '../../modals/ml_job_upgrade_modal'; -import { useInstalledSecurityJobs } from '../../../../common/components/ml/hooks/use_installed_security_jobs'; - -import * as i18n from './translations'; -import { SecuritySolutionLinkButton } from '../../../../common/components/links'; import { SecurityPageName } from '../../../../app/types'; -import { usePrePackagedRules } from '../../../containers/detection_engine/rules'; +import { SecuritySolutionLinkButton } from '../../../../common/components/links'; +import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; import { useUserData } from '../../user_info'; +import { LoadPrePackagedRules } from './load_prepackaged_rules'; +import { LoadPrePackagedRulesButton } from './load_prepackaged_rules_button'; +import * as i18n from './translations'; const EmptyPrompt = styled(EuiEmptyPrompt)` align-self: center; /* Corrects horizontal centering in IE11 */ @@ -24,62 +22,9 @@ const EmptyPrompt = styled(EuiEmptyPrompt)` EmptyPrompt.displayName = 'EmptyPrompt'; -interface PrePackagedRulesPromptProps { - createPrePackagedRules: () => void; - loading: boolean; - userHasPermissions: boolean; -} - -const PrePackagedRulesPromptComponent: React.FC = ({ - createPrePackagedRules, - loading = false, - userHasPermissions = false, -}) => { - const [{ isSignalIndexExists, isAuthenticated, hasEncryptionKey, canUserCRUD, hasIndexWrite }] = - useUserData(); - - const { loading: loadingJobs, jobs } = useInstalledSecurityJobs(); - const legacyJobsInstalled = jobs.filter((job) => affectedJobIds.includes(job.id)); - const [isUpgradeModalVisible, setIsUpgradeModalVisible] = useState(false); - - const { getLoadPrebuiltRulesAndTemplatesButton } = usePrePackagedRules({ - canUserCRUD, - hasIndexWrite, - isSignalIndexExists, - isAuthenticated, - hasEncryptionKey, - }); - - // Wrapper to add confirmation modal for users who may be running older ML Jobs that would - // be overridden by updating their rules. For details, see: https://github.com/elastic/kibana/issues/128121 - const mlJobUpgradeModalConfirm = useCallback(() => { - setIsUpgradeModalVisible(false); - createPrePackagedRules(); - }, [createPrePackagedRules, setIsUpgradeModalVisible]); - - const loadPrebuiltRulesAndTemplatesButton = useMemo( - () => - getLoadPrebuiltRulesAndTemplatesButton({ - isDisabled: !userHasPermissions || loading || loadingJobs, - onClick: () => { - if (legacyJobsInstalled.length > 0) { - setIsUpgradeModalVisible(true); - } else { - createPrePackagedRules(); - } - }, - fill: true, - 'data-test-subj': 'load-prebuilt-rules', - }), - [ - getLoadPrebuiltRulesAndTemplatesButton, - userHasPermissions, - loading, - loadingJobs, - legacyJobsInstalled, - createPrePackagedRules, - ] - ); +const PrePackagedRulesPromptComponent = () => { + const [{ canUserCRUD }] = useUserData(); + const hasPermissions = hasUserCRUDPermission(canUserCRUD); return ( = ( body={

    {i18n.PRE_BUILT_MSG}

    } actions={ - {loadPrebuiltRulesAndTemplatesButton} + + + {(renderProps) => ( + + )} + + {i18n.CREATE_RULE_ACTION} - {isUpgradeModalVisible && ( - setIsUpgradeModalVisible(false)} - onConfirm={mlJobUpgradeModalConfirm} - /> - )} } /> diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules.tsx new file mode 100644 index 0000000000000..e5d05d7e7fbb0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules.tsx @@ -0,0 +1,79 @@ +/* + * 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 React, { useCallback } from 'react'; +import { useInstalledSecurityJobs } from '../../../../common/components/ml/hooks/use_installed_security_jobs'; +import { useBoolState } from '../../../../common/hooks/use_bool_state'; +import { RULES_TABLE_ACTIONS } from '../../../../common/lib/apm/user_actions'; +import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; +import { useCreatePrePackagedRules } from '../../../../detection_engine/rule_management/logic/use_create_pre_packaged_rules'; +import { usePrePackagedRulesStatus } from '../../../../detection_engine/rule_management/logic/use_pre_packaged_rules_status'; +import { affectedJobIds } from '../../callouts/ml_job_compatibility_callout/affected_job_ids'; +import { MlJobUpgradeModal } from '../../modals/ml_job_upgrade_modal'; + +interface LoadPrePackagedRulesRenderProps { + isLoading: boolean; + isDisabled: boolean; + onClick: () => Promise; +} + +interface LoadPrePackagedRulesProps { + children: (renderProps: LoadPrePackagedRulesRenderProps) => React.ReactNode; +} + +export const LoadPrePackagedRules = ({ children }: LoadPrePackagedRulesProps) => { + const { isFetching: isFetchingPrepackagedStatus } = usePrePackagedRulesStatus(); + const { + createPrePackagedRules, + canCreatePrePackagedRules, + isLoading: loadingCreatePrePackagedRules, + } = useCreatePrePackagedRules(); + + const { startTransaction } = useStartTransaction(); + const handleCreatePrePackagedRules = useCallback(async () => { + startTransaction({ name: RULES_TABLE_ACTIONS.LOAD_PREBUILT }); + await createPrePackagedRules(); + }, [createPrePackagedRules, startTransaction]); + + const [isUpgradeModalVisible, showUpgradeModal, hideUpgradeModal] = useBoolState(false); + const { loading: loadingJobs, jobs } = useInstalledSecurityJobs(); + const legacyJobsInstalled = jobs.filter((job) => affectedJobIds.includes(job.id)); + + const handleInstallPrePackagedRules = useCallback(async () => { + if (legacyJobsInstalled.length > 0) { + showUpgradeModal(); + } else { + await handleCreatePrePackagedRules(); + } + }, [handleCreatePrePackagedRules, legacyJobsInstalled.length, showUpgradeModal]); + + // Wrapper to add confirmation modal for users who may be running older ML Jobs that would + // be overridden by updating their rules. For details, see: https://github.com/elastic/kibana/issues/128121 + const mlJobUpgradeModalConfirm = useCallback(() => { + hideUpgradeModal(); + handleCreatePrePackagedRules(); + }, [handleCreatePrePackagedRules, hideUpgradeModal]); + + const isDisabled = !canCreatePrePackagedRules || isFetchingPrepackagedStatus || loadingJobs; + + return ( + <> + {children({ + isLoading: loadingCreatePrePackagedRules, + isDisabled, + onClick: handleInstallPrePackagedRules, + })} + {isUpgradeModalVisible && ( + hideUpgradeModal()} + onConfirm={mlJobUpgradeModalConfirm} + /> + )} + + ); +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button.tsx new file mode 100644 index 0000000000000..996bbc386be37 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button.tsx @@ -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 { EuiButton } from '@elastic/eui'; +import React from 'react'; +import { usePrePackagedRulesInstallationStatus } from '../../../../detection_engine/rule_management/logic/use_pre_packaged_rules_installation_status'; +import { usePrePackagedRulesStatus } from '../../../../detection_engine/rule_management/logic/use_pre_packaged_rules_status'; +import { usePrePackagedTimelinesInstallationStatus } from '../../../../detection_engine/rule_management/logic/use_pre_packaged_timelines_installation_status'; +import type { + PrePackagedRuleInstallationStatus, + PrePackagedTimelineInstallationStatus, +} from '../../../pages/detection_engine/rules/helpers'; +import * as i18n from './translations'; + +const getLoadRulesOrTimelinesButtonTitle = ( + rulesStatus: PrePackagedRuleInstallationStatus, + timelineStatus: PrePackagedTimelineInstallationStatus +) => { + if (rulesStatus === 'ruleNotInstalled' && timelineStatus === 'timelinesNotInstalled') + return i18n.LOAD_PREPACKAGED_RULES_AND_TEMPLATES; + else if (rulesStatus === 'ruleNotInstalled' && timelineStatus !== 'timelinesNotInstalled') + return i18n.LOAD_PREPACKAGED_RULES; + else if (rulesStatus !== 'ruleNotInstalled' && timelineStatus === 'timelinesNotInstalled') + return i18n.LOAD_PREPACKAGED_TIMELINE_TEMPLATES; +}; + +const getMissingRulesOrTimelinesButtonTitle = (missingRules: number, missingTimelines: number) => { + if (missingRules > 0 && missingTimelines === 0) + return i18n.RELOAD_MISSING_PREPACKAGED_RULES(missingRules); + else if (missingRules === 0 && missingTimelines > 0) + return i18n.RELOAD_MISSING_PREPACKAGED_TIMELINES(missingTimelines); + else if (missingRules > 0 && missingTimelines > 0) + return i18n.RELOAD_MISSING_PREPACKAGED_RULES_AND_TIMELINES(missingRules, missingTimelines); +}; + +interface LoadPrePackagedRulesButtonProps { + fill?: boolean; + 'data-test-subj'?: string; + isLoading: boolean; + isDisabled: boolean; + onClick: () => Promise; +} + +export const LoadPrePackagedRulesButton = ({ + fill, + 'data-test-subj': dataTestSubj = 'loadPrebuiltRulesBtn', + isLoading, + isDisabled, + onClick, +}: LoadPrePackagedRulesButtonProps) => { + const { data: prePackagedRulesStatus } = usePrePackagedRulesStatus(); + const prePackagedAssetsStatus = usePrePackagedRulesInstallationStatus(); + const prePackagedTimelineStatus = usePrePackagedTimelinesInstallationStatus(); + + const showInstallButton = + (prePackagedAssetsStatus === 'ruleNotInstalled' || + prePackagedTimelineStatus === 'timelinesNotInstalled') && + prePackagedAssetsStatus !== 'someRuleUninstall'; + + if (showInstallButton) { + return ( + + {getLoadRulesOrTimelinesButtonTitle(prePackagedAssetsStatus, prePackagedTimelineStatus)} + + ); + } + + const showUpdateButton = + prePackagedAssetsStatus === 'someRuleUninstall' || + prePackagedTimelineStatus === 'someTimelineUninstall'; + + if (showUpdateButton) { + return ( + + {getMissingRulesOrTimelinesButtonTitle( + prePackagedRulesStatus?.rules_not_installed ?? 0, + prePackagedRulesStatus?.timelines_not_installed ?? 0 + )} + + ); + } + + return null; +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/translations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/translations.ts index 5b66b4611c03d..b1207b59faf8b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/translations.ts @@ -96,3 +96,57 @@ export const RELEASE_NOTES_HELP = i18n.translate( defaultMessage: 'Release notes', } ); + +export const LOAD_PREPACKAGED_RULES = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.loadPrePackagedRulesButton', + { + defaultMessage: 'Load Elastic prebuilt rules', + } +); + +export const LOAD_PREPACKAGED_TIMELINE_TEMPLATES = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.loadPrePackagedTimelineTemplatesButton', + { + defaultMessage: 'Load Elastic prebuilt timeline templates', + } +); + +export const LOAD_PREPACKAGED_RULES_AND_TEMPLATES = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.loadPrePackagedRulesAndTemplatesButton', + { + defaultMessage: 'Load Elastic prebuilt rules and timeline templates', + } +); + +export const RELOAD_MISSING_PREPACKAGED_RULES = (missingRules: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesButton', + { + values: { missingRules }, + defaultMessage: + 'Install {missingRules} Elastic prebuilt {missingRules, plural, =1 {rule} other {rules}} ', + } + ); + +export const RELOAD_MISSING_PREPACKAGED_TIMELINES = (missingTimelines: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedTimelinesButton', + { + values: { missingTimelines }, + defaultMessage: + 'Install {missingTimelines} Elastic prebuilt {missingTimelines, plural, =1 {timeline} other {timelines}} ', + } + ); + +export const RELOAD_MISSING_PREPACKAGED_RULES_AND_TIMELINES = ( + missingRules: number, + missingTimelines: number +) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton', + { + values: { missingRules, missingTimelines }, + defaultMessage: + 'Install {missingRules} Elastic prebuilt {missingRules, plural, =1 {rule} other {rules}} and {missingTimelines} Elastic prebuilt {missingTimelines, plural, =1 {timeline} other {timelines}} ', + } + ); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.test.tsx index 70b98eb22fd89..6d882fe2930a3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.test.tsx @@ -5,13 +5,18 @@ * 2.0. */ +import { render } from '@testing-library/react'; import React from 'react'; -import { shallow } from 'enzyme'; - -import { UpdatePrePackagedRulesCallOut } from './update_callout'; import { useKibana } from '../../../../common/lib/kibana'; +import { TestProviders } from '../../../../common/mock'; +import { useFetchPrebuiltRulesStatusQuery } from '../../../../detection_engine/rule_management/api/hooks/use_fetch_prebuilt_rules_status_query'; +import { mockReactQueryResponse } from '../../../../detection_engine/rule_management/api/hooks/__mocks__/mock_react_query_response'; +import { UpdatePrePackagedRulesCallOut } from './update_callout'; jest.mock('../../../../common/lib/kibana'); +jest.mock( + '../../../../detection_engine/rule_management/api/hooks/use_fetch_prebuilt_rules_status_query' +); describe('UpdatePrePackagedRulesCallOut', () => { beforeAll(() => { @@ -28,105 +33,134 @@ describe('UpdatePrePackagedRulesCallOut', () => { }); }); - it('renders correctly', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('EuiCallOut')).toHaveLength(1); - }); - it('renders callOutMessage correctly: numberOfUpdatedRules > 0 and numberOfUpdatedTimelines = 0', () => { - const wrapper = shallow( - + (useFetchPrebuiltRulesStatusQuery as jest.Mock).mockReturnValue( + mockReactQueryResponse({ + data: { + rules_custom_installed: 0, + rules_installed: 0, + rules_not_installed: 0, + rules_not_updated: 1, + timelines_updated: 0, + timelines_not_installed: 0, + timelines_not_updated: 0, + }, + }) ); - expect(wrapper.find('[data-test-subj="update-callout"]').find('p').text()).toEqual( + const { getByTestId } = render(, { wrapper: TestProviders }); + + expect(getByTestId('update-callout')).toHaveTextContent( 'You can update 1 Elastic prebuilt ruleRelease notes' ); }); it('renders buttonTitle correctly: numberOfUpdatedRules > 0 and numberOfUpdatedTimelines = 0', () => { - const wrapper = shallow( - + (useFetchPrebuiltRulesStatusQuery as jest.Mock).mockReturnValue( + mockReactQueryResponse({ + data: { + rules_custom_installed: 0, + rules_installed: 0, + rules_not_installed: 0, + rules_not_updated: 1, + timelines_updated: 0, + timelines_not_installed: 0, + timelines_not_updated: 0, + }, + }) ); - expect(wrapper.find('[data-test-subj="update-callout-button"]').prop('children')).toEqual( + const { getByTestId } = render(, { wrapper: TestProviders }); + + expect(getByTestId('update-callout-button')).toHaveTextContent( 'Update 1 Elastic prebuilt rule' ); }); it('renders callOutMessage correctly: numberOfUpdatedRules = 0 and numberOfUpdatedTimelines > 0', () => { - const wrapper = shallow( - + (useFetchPrebuiltRulesStatusQuery as jest.Mock).mockReturnValue( + mockReactQueryResponse({ + data: { + rules_custom_installed: 0, + rules_installed: 0, + rules_not_installed: 0, + rules_not_updated: 0, + timelines_updated: 0, + timelines_not_installed: 0, + timelines_not_updated: 1, + }, + }) ); - expect(wrapper.find('[data-test-subj="update-callout"]').find('p').text()).toEqual( + const { getByTestId } = render(, { wrapper: TestProviders }); + + expect(getByTestId('update-callout')).toHaveTextContent( 'You can update 1 Elastic prebuilt timelineRelease notes' ); }); it('renders buttonTitle correctly: numberOfUpdatedRules = 0 and numberOfUpdatedTimelines > 0', () => { - const wrapper = shallow( - + (useFetchPrebuiltRulesStatusQuery as jest.Mock).mockReturnValue( + mockReactQueryResponse({ + data: { + rules_custom_installed: 0, + rules_installed: 0, + rules_not_installed: 0, + rules_not_updated: 0, + timelines_updated: 0, + timelines_not_installed: 0, + timelines_not_updated: 1, + }, + }) ); - expect(wrapper.find('[data-test-subj="update-callout-button"]').prop('children')).toEqual( + const { getByTestId } = render(, { wrapper: TestProviders }); + + expect(getByTestId('update-callout-button')).toHaveTextContent( 'Update 1 Elastic prebuilt timeline' ); }); it('renders callOutMessage correctly: numberOfUpdatedRules > 0 and numberOfUpdatedTimelines > 0', () => { - const wrapper = shallow( - + (useFetchPrebuiltRulesStatusQuery as jest.Mock).mockReturnValue( + mockReactQueryResponse({ + data: { + rules_custom_installed: 0, + rules_installed: 0, + rules_not_installed: 0, + rules_not_updated: 1, + timelines_updated: 0, + timelines_not_installed: 0, + timelines_not_updated: 1, + }, + }) ); - expect(wrapper.find('[data-test-subj="update-callout"]').find('p').text()).toEqual( + const { getByTestId } = render(, { wrapper: TestProviders }); + + expect(getByTestId('update-callout')).toHaveTextContent( 'You can update 1 Elastic prebuilt rule and 1 Elastic prebuilt timeline. Note that this will reload deleted Elastic prebuilt rules.Release notes' ); }); it('renders buttonTitle correctly: numberOfUpdatedRules > 0 and numberOfUpdatedTimelines > 0', () => { - const wrapper = shallow( - + (useFetchPrebuiltRulesStatusQuery as jest.Mock).mockReturnValue( + mockReactQueryResponse({ + data: { + rules_custom_installed: 0, + rules_installed: 0, + rules_not_installed: 0, + rules_not_updated: 1, + timelines_updated: 0, + timelines_not_installed: 0, + timelines_not_updated: 1, + }, + }) ); - expect(wrapper.find('[data-test-subj="update-callout-button"]').prop('children')).toEqual( + const { getByTestId } = render(, { wrapper: TestProviders }); + + expect(getByTestId('update-callout-button')).toHaveTextContent( 'Update 1 Elastic prebuilt rule and 1 Elastic prebuilt timeline' ); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.tsx index 9d67a1e6b9ae8..1526c211990e3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/update_callout.tsx @@ -5,51 +5,42 @@ * 2.0. */ +import { EuiButton, EuiCallOut, EuiLink } from '@elastic/eui'; import React, { memo, useMemo } from 'react'; - -import { EuiCallOut, EuiButton, EuiLink } from '@elastic/eui'; - import { useKibana } from '../../../../common/lib/kibana'; +import { usePrePackagedRulesStatus } from '../../../../detection_engine/rule_management/logic/use_pre_packaged_rules_status'; +import { LoadPrePackagedRules } from './load_prepackaged_rules'; import * as i18n from './translations'; -interface UpdatePrePackagedRulesCallOutProps { - loading: boolean; - numberOfUpdatedRules: number; - numberOfUpdatedTimelines: number; - updateRules: () => void; -} - -const UpdatePrePackagedRulesCallOutComponent: React.FC = ({ - loading, - numberOfUpdatedRules, - numberOfUpdatedTimelines, - updateRules, -}) => { +const UpdatePrePackagedRulesCallOutComponent = () => { const { services } = useKibana(); + const { data: prePackagedRulesStatus } = usePrePackagedRulesStatus(); + const rulesNotUpdated = prePackagedRulesStatus?.rules_not_updated ?? 0; + const timelinesNotUpdated = prePackagedRulesStatus?.timelines_not_updated ?? 0; const prepackagedRulesOrTimelines = useMemo(() => { - if (numberOfUpdatedRules > 0 && numberOfUpdatedTimelines === 0) { + if (rulesNotUpdated > 0 && timelinesNotUpdated === 0) { return { - callOutMessage: i18n.UPDATE_PREPACKAGED_RULES_MSG(numberOfUpdatedRules), - buttonTitle: i18n.UPDATE_PREPACKAGED_RULES(numberOfUpdatedRules), + callOutMessage: i18n.UPDATE_PREPACKAGED_RULES_MSG(rulesNotUpdated), + buttonTitle: i18n.UPDATE_PREPACKAGED_RULES(rulesNotUpdated), }; - } else if (numberOfUpdatedRules === 0 && numberOfUpdatedTimelines > 0) { + } else if (rulesNotUpdated === 0 && timelinesNotUpdated > 0) { return { - callOutMessage: i18n.UPDATE_PREPACKAGED_TIMELINES_MSG(numberOfUpdatedTimelines), - buttonTitle: i18n.UPDATE_PREPACKAGED_TIMELINES(numberOfUpdatedTimelines), + callOutMessage: i18n.UPDATE_PREPACKAGED_TIMELINES_MSG(timelinesNotUpdated), + buttonTitle: i18n.UPDATE_PREPACKAGED_TIMELINES(timelinesNotUpdated), }; - } else if (numberOfUpdatedRules > 0 && numberOfUpdatedTimelines > 0) + } else if (rulesNotUpdated > 0 && timelinesNotUpdated > 0) return { callOutMessage: i18n.UPDATE_PREPACKAGED_RULES_AND_TIMELINES_MSG( - numberOfUpdatedRules, - numberOfUpdatedTimelines + rulesNotUpdated, + timelinesNotUpdated ), buttonTitle: i18n.UPDATE_PREPACKAGED_RULES_AND_TIMELINES( - numberOfUpdatedRules, - numberOfUpdatedTimelines + rulesNotUpdated, + timelinesNotUpdated ), }; - }, [numberOfUpdatedRules, numberOfUpdatedTimelines]); + }, [rulesNotUpdated, timelinesNotUpdated]); return ( @@ -60,14 +51,13 @@ const UpdatePrePackagedRulesCallOutComponent: React.FC

    - - {prepackagedRulesOrTimelines?.buttonTitle} - + + {(renderProps) => ( + + {prepackagedRulesOrTimelines?.buttonTitle} + + )} +
    ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts index b8475f7a0e9af..361e542fa3f0f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts @@ -7,12 +7,15 @@ import { capitalize } from 'lodash'; import semver from 'semver'; + import type { InstalledIntegration, InstalledIntegrationArray, +} from '../../../../../common/detection_engine/fleet_integrations'; +import type { RelatedIntegration, RelatedIntegrationArray, -} from '../../../../../common/detection_engine/schemas/common'; +} from '../../../../../common/detection_engine/rule_schema'; export interface IntegrationDetails { packageName: string; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_description/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_description/index.tsx index 5932faf1de6f0..5640abea69cc3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_description/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_description/index.tsx @@ -8,7 +8,7 @@ import React from 'react'; import styled from 'styled-components'; -import type { RelatedIntegrationArray } from '../../../../../../common/detection_engine/schemas/common'; +import type { RelatedIntegrationArray } from '../../../../../../common/detection_engine/rule_schema'; import type { ListItems } from '../../description_step/types'; import type { IntegrationDetails } from '../integration_details'; import { useRelatedIntegrations } from '../use_related_integrations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx index 6c17b182381ca..36fc206aa92ea 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx @@ -16,7 +16,7 @@ import { EuiSpacer, } from '@elastic/eui'; -import type { RelatedIntegrationArray } from '../../../../../../common/detection_engine/schemas/common'; +import type { RelatedIntegrationArray } from '../../../../../../common/detection_engine/rule_schema'; import { IntegrationDescription } from '../integrations_description'; import { useRelatedIntegrations } from '../use_related_integrations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/mock.ts b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/mock.ts index 786e33ad69293..43a0c8a0602ef 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/mock.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RelatedIntegrationArray } from '../../../../../common/detection_engine/schemas/common'; +import type { RelatedIntegrationArray } from '../../../../../common/detection_engine/rule_schema'; export const relatedIntegrations: RelatedIntegrationArray = [ { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx index 705c7f5f3fbd3..d1322fd76a91f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx @@ -5,18 +5,18 @@ * 2.0. */ -jest.mock('../../../containers/detection_engine/rules/api'); -jest.mock('../../../../common/lib/kibana'); - import React from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { renderHook, cleanup } from '@testing-library/react-hooks'; import { useInstalledIntegrations } from './use_installed_integrations'; -import * as api from '../../../containers/detection_engine/rules/api'; +import { fleetIntegrationsApi } from '../../../../detection_engine/fleet_integrations/api'; import { useToasts } from '../../../../common/lib/kibana'; +jest.mock('../../../../detection_engine/fleet_integrations/api'); +jest.mock('../../../../common/lib/kibana'); + describe('useInstalledIntegrations', () => { beforeEach(() => { jest.clearAllMocks(); @@ -53,7 +53,10 @@ describe('useInstalledIntegrations', () => { ); it('calls the API via fetchInstalledIntegrations', async () => { - const fetchInstalledIntegrations = jest.spyOn(api, 'fetchInstalledIntegrations'); + const fetchInstalledIntegrations = jest.spyOn( + fleetIntegrationsApi, + 'fetchInstalledIntegrations' + ); const { waitForNextUpdate } = render(); @@ -101,7 +104,7 @@ describe('useInstalledIntegrations', () => { // Skipping until we re-enable errors it.skip('handles exceptions from the API', async () => { const exception = new Error('Boom!'); - jest.spyOn(api, 'fetchInstalledIntegrations').mockRejectedValue(exception); + jest.spyOn(fleetIntegrationsApi, 'fetchInstalledIntegrations').mockRejectedValue(exception); const { result, waitForNextUpdate } = render(); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx index 734ef6e628214..c94404bb5cdc7 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx @@ -6,8 +6,9 @@ */ import { useQuery } from '@tanstack/react-query'; -import type { InstalledIntegrationArray } from '../../../../../common/detection_engine/schemas/common'; -import { fetchInstalledIntegrations } from '../../../containers/detection_engine/rules/api'; + +import type { InstalledIntegrationArray } from '../../../../../common/detection_engine/fleet_integrations'; +import { fleetIntegrationsApi } from '../../../../detection_engine/fleet_integrations'; // import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; // import * as i18n from './translations'; @@ -28,7 +29,7 @@ export const useInstalledIntegrations = ({ packages }: UseInstalledIntegrationsA }, ], async ({ signal }) => { - const integrations = await fetchInstalledIntegrations({ + const integrations = await fleetIntegrationsApi.fetchInstalledIntegrations({ packages, signal, }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts index 3363abf2fe3c7..19e662746638a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts @@ -7,7 +7,7 @@ import { useMemo } from 'react'; -import type { RelatedIntegrationArray } from '../../../../../common/detection_engine/schemas/common'; +import type { RelatedIntegrationArray } from '../../../../../common/detection_engine/rule_schema'; import type { IntegrationDetails } from './integration_details'; import { calculateIntegrationDetails } from './integration_details'; import { useInstalledIntegrations } from './use_installed_integrations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/risk_score_mapping/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/risk_score_mapping/index.tsx index ea5aac0bcae26..177fd2e97e6cd 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/risk_score_mapping/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/risk_score_mapping/index.tsx @@ -5,6 +5,9 @@ * 2.0. */ +import React, { useCallback, useMemo } from 'react'; +import styled from 'styled-components'; +import { noop } from 'lodash/fp'; import { EuiFormRow, EuiCheckbox, @@ -16,15 +19,14 @@ import { EuiSpacer, EuiRange, } from '@elastic/eui'; -import React, { useCallback, useMemo } from 'react'; -import styled from 'styled-components'; -import { noop } from 'lodash/fp'; -import type { RiskScoreMapping } from '@kbn/securitysolution-io-ts-alerting-types'; -import { FieldComponent } from '@kbn/securitysolution-autocomplete'; + import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import * as i18n from './translations'; +import { FieldComponent } from '@kbn/securitysolution-autocomplete'; +import type { RiskScoreMapping } from '@kbn/securitysolution-io-ts-alerting-types'; + import type { AboutStepRiskScore } from '../../../pages/detection_engine/rules/types'; +import * as i18n from './translations'; const NestedContent = styled.div` margin-left: 24px; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 2cbd090e87733..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,74 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RuleActionsOverflow snapshots renders correctly against snapshot 1`] = ` - - - - - } - closePopover={[Function]} - data-test-subj="rules-details-popover" - display="inline-block" - hasArrow={true} - id="ruleActionsOverflow" - isOpen={false} - ownFocus={true} - panelPaddingSize="none" - repositionOnScroll={true} - > - - - - Duplicate rule - - - , - - Export rule - , - - Delete rule - , - ] - } - /> - - -`; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx index 8b736bad37b92..ce265ffb8382c 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx @@ -5,17 +5,20 @@ * 2.0. */ -import { shallow, mount } from 'enzyme'; +import { render, fireEvent } from '@testing-library/react'; import React from 'react'; -import { - goToRuleEditPage, - executeRulesBulkAction, - bulkExportRules, -} from '../../../pages/detection_engine/rules/all/actions'; +import { useBulkExport } from '../../../../detection_engine/rule_management/logic/bulk_actions/use_bulk_export'; +import { useExecuteBulkAction } from '../../../../detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action'; + import { RuleActionsOverflow } from '.'; -import { mockRule } from '../../../pages/detection_engine/rules/all/__mocks__/mock'; +import { mockRule } from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; +import { TestProviders } from '../../../../common/mock'; +jest.mock( + '../../../../detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action' +); +jest.mock('../../../../detection_engine/rule_management/logic/bulk_actions/use_bulk_export'); jest.mock('../../../../common/lib/apm/use_start_transaction'); jest.mock('../../../../common/hooks/use_app_toasts'); jest.mock('../../../../common/lib/kibana', () => { @@ -31,12 +34,9 @@ jest.mock('../../../../common/lib/kibana', () => { }), }; }); -jest.mock('../../../pages/detection_engine/rules/all/actions'); - -const executeRulesBulkActionMock = executeRulesBulkAction as jest.Mock; -const bulkExportRulesMock = bulkExportRules as jest.Mock; -const flushPromises = () => new Promise(setImmediate); +const useExecuteBulkActionMock = useExecuteBulkAction as jest.Mock; +const useBulkExportMock = useBulkExport as jest.Mock; describe('RuleActionsOverflow', () => { afterEach(() => { @@ -46,328 +46,189 @@ describe('RuleActionsOverflow', () => { jest.resetAllMocks(); }); - describe('snapshots', () => { - test('renders correctly against snapshot', () => { - const wrapper = shallow( - - ); - expect(wrapper).toMatchSnapshot(); - }); - }); - describe('rules details menu panel', () => { - test('there is at least one item when there is a rule within the rules-details-menu-panel', () => { - const wrapper = mount( + test('menu items rendered when a rule is passed to the component', () => { + const { getByTestId } = render( + />, + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - const items: unknown[] = wrapper - .find('[data-test-subj="rules-details-menu-panel"]') - .first() - .prop('items'); - - expect(items.length).toBeGreaterThan(0); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + expect(getByTestId('rules-details-menu-panel')).toHaveTextContent('Duplicate rule'); + expect(getByTestId('rules-details-menu-panel')).toHaveTextContent('Export rule'); + expect(getByTestId('rules-details-menu-panel')).toHaveTextContent('Delete rule'); }); - test('items are empty when there is a null rule within the rules-details-menu-panel', () => { - const wrapper = mount( - + test('menu is empty when no rule is passed to the component', () => { + const { getByTestId } = render( + , + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-menu-panel"]').first().prop('items') - ).toEqual([]); - }); - - test('items are empty when there is an undefined rule within the rules-details-menu-panel', () => { - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-menu-panel"]').first().prop('items') - ).toEqual([]); - }); - - test('it opens the popover when rules-details-popover-button-icon is clicked', () => { - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-popover"]').first().prop('isOpen') - ).toEqual(true); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + expect(getByTestId('rules-details-menu-panel')).not.toHaveTextContent(/.+/); }); }); describe('rules details pop over button icon', () => { test('it does not open the popover when rules-details-popover-button-icon is clicked when the user does not have permission', () => { - const wrapper = mount( + const { getByTestId } = render( + />, + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-popover"]').first().prop('isOpen') - ).toEqual(false); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + + expect(getByTestId('rules-details-popover')).not.toHaveTextContent(/.+/); }); }); describe('rules details duplicate rule', () => { - test('it does not open the popover when rules-details-popover-button-icon is clicked and the user does not have permission', () => { - const rule = mockRule('id'); - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect(wrapper.find('[data-test-subj="rules-details-delete-rule"] button').exists()).toEqual( - false - ); - }); - - test('it opens the popover when rules-details-popover-button-icon is clicked', () => { - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-popover"]').first().prop('isOpen') - ).toEqual(true); - }); - test('it closes the popover when rules-details-duplicate-rule is clicked', () => { - const wrapper = mount( + const { getByTestId } = render( + />, + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-duplicate-rule"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-popover"]').first().prop('isOpen') - ).toEqual(false); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-duplicate-rule')); + + expect(getByTestId('rules-details-popover')).not.toHaveTextContent(/.+/); }); test('it calls duplicate action when rules-details-duplicate-rule is clicked', () => { - const wrapper = mount( + const executeBulkAction = jest.fn(); + useExecuteBulkActionMock.mockReturnValue({ executeBulkAction }); + + const { getByTestId } = render( + />, + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-duplicate-rule"] button').simulate('click'); - wrapper.update(); - expect(executeRulesBulkAction).toHaveBeenCalledWith( + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-duplicate-rule')); + + expect(executeBulkAction).toHaveBeenCalledWith( expect.objectContaining({ action: 'duplicate' }) ); }); test('it calls duplicate action with the rule and rule.id when rules-details-duplicate-rule is clicked', () => { - const rule = mockRule('id'); - const wrapper = mount( - + const executeBulkAction = jest.fn(); + useExecuteBulkActionMock.mockReturnValue({ executeBulkAction }); + + const { getByTestId } = render( + , + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-duplicate-rule"] button').simulate('click'); - wrapper.update(); - expect(executeRulesBulkAction).toHaveBeenCalledWith( + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-duplicate-rule')); + + expect(executeBulkAction).toHaveBeenCalledWith( expect.objectContaining({ action: 'duplicate', search: { ids: ['id'] } }) ); }); }); - test('it navigates to edit page after the rule is duplicated', async () => { - const rule = mockRule('id'); - const ruleDuplicate = mockRule('newRule'); - executeRulesBulkActionMock.mockImplementation(() => - Promise.resolve({ attributes: { results: { created: [ruleDuplicate] } } }) - ); - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-duplicate-rule"] button').simulate('click'); - wrapper.update(); - await flushPromises(); - - expect(executeRulesBulkAction).toHaveBeenCalledWith( - expect.objectContaining({ action: 'duplicate' }) - ); - expect(goToRuleEditPage).toHaveBeenCalledWith(ruleDuplicate.id, expect.anything()); - }); - describe('rules details export rule', () => { test('should call export actions and display toast when export option is clicked', async () => { - bulkExportRulesMock.mockImplementation(() => Promise.resolve({})); - const wrapper = mount( + const bulkExport = jest.fn(); + useBulkExportMock.mockReturnValue({ bulkExport }); + + const { getByTestId } = render( + />, + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-export-rule"] button').simulate('click'); - wrapper.update(); - await flushPromises(); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-export-rule')); - expect(bulkExportRulesMock).toHaveBeenCalledWith( - expect.objectContaining({ action: 'export' }) - ); - expect(bulkExportRulesMock).toHaveBeenCalledWith( - expect.not.objectContaining({ onSuccess: expect.any }) - ); - }); - test('it does not open the popover when rules-details-popover-button-icon is clicked and the user does not have permission', () => { - const rule = mockRule('id'); - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect(wrapper.find('[data-test-subj="rules-details-export-rule"] button').exists()).toEqual( - false - ); + expect(bulkExport).toHaveBeenCalled(); }); test('it closes the popover when rules-details-export-rule is clicked', () => { - const wrapper = mount( + const { getByTestId } = render( + />, + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-export-rule"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-popover"]').first().prop('isOpen') - ).toEqual(false); - }); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-export-rule')); - test('it does not close the pop over on rules-details-export-rule when the rule is an immutable rule and the user does a click', () => { - const rule = mockRule('id'); - rule.immutable = true; - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-export-rule"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-popover"]').first().prop('isOpen') - ).toEqual(true); + // Popover is not shown + expect(getByTestId('rules-details-popover')).not.toHaveTextContent(/.+/); }); }); describe('rules details delete rule', () => { - test('it does not open the popover when rules-details-popover-button-icon is clicked and the user does not have permission', () => { - const rule = mockRule('id'); - const wrapper = mount( - - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - expect(wrapper.find('[data-test-subj="rules-details-delete-rule"] button').exists()).toEqual( - false - ); - }); - test('it closes the popover when rules-details-delete-rule is clicked', () => { - const wrapper = mount( + const { getByTestId } = render( + />, + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-delete-rule"] button').simulate('click'); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="rules-details-popover"]').first().prop('isOpen') - ).toEqual(false); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-delete-rule')); + + // Popover is not shown + expect(getByTestId('rules-details-popover')).not.toHaveTextContent(/.+/); }); test('it calls deleteRulesAction when rules-details-delete-rule is clicked', () => { - const wrapper = mount( + const executeBulkAction = jest.fn(); + useExecuteBulkActionMock.mockReturnValue({ executeBulkAction }); + + const { getByTestId } = render( - ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-delete-rule"] button').simulate('click'); - wrapper.update(); - expect(executeRulesBulkAction).toHaveBeenCalledWith( - expect.objectContaining({ action: 'delete' }) + />, + { wrapper: TestProviders } ); + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-delete-rule')); + + expect(executeBulkAction).toHaveBeenCalledWith(expect.objectContaining({ action: 'delete' })); }); test('it calls deleteRulesAction with the rule.id when rules-details-delete-rule is clicked', () => { + const executeBulkAction = jest.fn(); + useExecuteBulkActionMock.mockReturnValue({ executeBulkAction }); + const rule = mockRule('id'); - const wrapper = mount( - + const { getByTestId } = render( + , + { wrapper: TestProviders } ); - wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); - wrapper.update(); - wrapper.find('[data-test-subj="rules-details-delete-rule"] button').simulate('click'); - wrapper.update(); - expect(executeRulesBulkAction).toHaveBeenCalledWith( + fireEvent.click(getByTestId('rules-details-popover-button-icon')); + fireEvent.click(getByTestId('rules-details-delete-rule')); + + expect(executeBulkAction).toHaveBeenCalledWith( expect.objectContaining({ action: 'delete', search: { ids: ['id'] } }) ); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index beb8e8365d74e..c2fc45d53e1d6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -16,20 +16,23 @@ import { noop } from 'lodash'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { APP_UI_ID, SecurityPageName } from '../../../../../common/constants'; -import { BulkAction } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { BulkAction } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { getRulesUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useBoolState } from '../../../../common/hooks/use_bool_state'; import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; import { useKibana } from '../../../../common/lib/kibana'; -import { getToolTipContent } from '../../../../common/utils/privileges'; -import type { Rule } from '../../../containers/detection_engine/rules'; +import { canEditRuleWithActions } from '../../../../common/utils/privileges'; +import type { Rule } from '../../../../detection_engine/rule_management/logic'; +import { + downloadExportedRules, + useBulkExport, +} from '../../../../detection_engine/rule_management/logic/bulk_actions/use_bulk_export'; import { - executeRulesBulkAction, goToRuleEditPage, - bulkExportRules, -} from '../../../pages/detection_engine/rules/all/actions'; + useExecuteBulkAction, +} from '../../../../detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action'; import * as i18nActions from '../../../pages/detection_engine/rules/translations'; import * as i18n from './translations'; @@ -62,6 +65,8 @@ const RuleActionsOverflowComponent = ({ const { navigateToApp } = useKibana().services.application; const toasts = useAppToasts(); const { startTransaction } = useStartTransaction(); + const { executeBulkAction } = useExecuteBulkAction(); + const { bulkExport } = useBulkExport(); const onRuleDeletedCallback = useCallback(() => { navigateToApp(APP_UI_ID, { @@ -82,11 +87,10 @@ const RuleActionsOverflowComponent = ({ onClick={async () => { startTransaction({ name: SINGLE_RULE_ACTIONS.DUPLICATE }); closePopover(); - const result = await executeRulesBulkAction({ + const result = await executeBulkAction({ action: BulkAction.duplicate, onSuccess: noop, search: { ids: [rule.id] }, - toasts, }); const createdRules = result?.attributes.results.created; if (createdRules?.length) { @@ -96,7 +100,11 @@ const RuleActionsOverflowComponent = ({ > <>{i18nActions.DUPLICATE_RULE} @@ -109,11 +117,13 @@ const RuleActionsOverflowComponent = ({ onClick={async () => { startTransaction({ name: SINGLE_RULE_ACTIONS.EXPORT }); closePopover(); - await bulkExportRules({ - action: BulkAction.export, - search: { ids: [rule.id] }, - toasts, - }); + const response = await bulkExport({ search: { ids: [rule.id] } }); + if (response) { + await downloadExportedRules({ + response, + toasts, + }); + } }} > {i18nActions.EXPORT_RULE} @@ -126,11 +136,10 @@ const RuleActionsOverflowComponent = ({ onClick={async () => { startTransaction({ name: SINGLE_RULE_ACTIONS.DELETE }); closePopover(); - await executeRulesBulkAction({ + await executeBulkAction({ action: BulkAction.delete, onSuccess: onRuleDeletedCallback, search: { ids: [rule.id] }, - toasts, }); }} > @@ -139,8 +148,10 @@ const RuleActionsOverflowComponent = ({ ] : [], [ + bulkExport, canDuplicateRuleWithActions, closePopover, + executeBulkAction, navigateToApp, onRuleDeletedCallback, rule, diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_logs.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_logs.tsx index 8249f60f20869..3d72986a100dd 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_logs.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_logs.tsx @@ -7,7 +7,7 @@ import React, { Fragment, useMemo } from 'react'; import { EuiCallOut, EuiText, EuiSpacer, EuiAccordion } from '@elastic/eui'; -import type { RulePreviewLogs } from '../../../../../common/detection_engine/schemas/request'; +import type { RulePreviewLogs } from '../../../../../common/detection_engine/rule_schema'; import * as i18n from './translations'; interface PreviewLogsComponentProps { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_invocation_count.ts b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_invocation_count.ts index fa6cb82980832..ef61f7dd37c13 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_invocation_count.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_invocation_count.ts @@ -8,7 +8,7 @@ import moment from 'moment'; import type { TimeframePreviewOptions } from '../../../pages/detection_engine/rules/types'; -import { getTimeTypeValue } from '../../../pages/detection_engine/rules/create/helpers'; +import { getTimeTypeValue } from '../../../../detection_engine/rule_creation_ui/pages/rule_creation/helpers'; export const usePreviewInvocationCount = ({ timeframeOptions, diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx index f6dbe68f07882..a1ccd3472bb75 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_route.tsx @@ -8,8 +8,8 @@ import { useEffect, useState, useCallback } from 'react'; import type { List } from '@kbn/securitysolution-io-ts-list-types'; import { usePreviewRule } from './use_preview_rule'; -import { formatPreviewRule } from '../../../pages/detection_engine/rules/create/helpers'; -import type { RulePreviewLogs } from '../../../../../common/detection_engine/schemas/request'; +import { formatPreviewRule } from '../../../../detection_engine/rule_creation_ui/pages/rule_creation/helpers'; +import type { RulePreviewLogs } from '../../../../../common/detection_engine/rule_schema'; import type { AboutStepRule, DefineStepRule, diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_rule.ts b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_rule.ts index 349eaa8c5dd80..17d47008e77bc 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_rule.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_rule.ts @@ -10,11 +10,11 @@ import { useEffect, useMemo, useState } from 'react'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import type { PreviewResponse, - CreateRulesSchema, -} from '../../../../../common/detection_engine/schemas/request'; + RuleCreateProps, +} from '../../../../../common/detection_engine/rule_schema'; -import { previewRule } from '../../../containers/detection_engine/rules/api'; -import * as i18n from '../../../containers/detection_engine/rules/translations'; +import { previewRule } from '../../../../detection_engine/rule_management/api/api'; +import * as i18n from '../../../../detection_engine/rule_management/logic/translations'; import { transformOutput } from '../../../containers/detection_engine/rules/transforms'; import type { TimeframePreviewOptions } from '../../../pages/detection_engine/rules/types'; import { usePreviewInvocationCount } from './use_preview_invocation_count'; @@ -30,7 +30,7 @@ export const usePreviewRule = ({ }: { timeframeOptions: TimeframePreviewOptions; }) => { - const [rule, setRule] = useState(null); + const [rule, setRule] = useState(null); const [response, setResponse] = useState(emptyPreviewRule); const [isLoading, setIsLoading] = useState(false); const { addError } = useAppToasts(); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx index 6580d8955ae2f..9989cd76b09c9 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx @@ -9,18 +9,20 @@ import { mount } from 'enzyme'; import React from 'react'; import { waitFor } from '@testing-library/react'; -import { performBulkAction } from '../../../containers/detection_engine/rules'; +import { performBulkAction } from '../../../../detection_engine/rule_management/api/api'; import { RuleSwitchComponent } from '.'; -import { getRulesSchemaMock } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import { useRulesTableContextOptional } from '../../../pages/detection_engine/rules/all/rules_table/rules_table_context'; -import { useRulesTableContextMock } from '../../../pages/detection_engine/rules/all/rules_table/__mocks__/rules_table_context'; +import { getRulesSchemaMock } from '../../../../../common/detection_engine/rule_schema/mocks'; +import { useRulesTableContextOptional } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context'; +import { useRulesTableContextMock } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table/__mocks__/rules_table_context'; import { TestProviders } from '../../../../common/mock'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; jest.mock('../../../../common/hooks/use_app_toasts'); -jest.mock('../../../containers/detection_engine/rules'); -jest.mock('../../../pages/detection_engine/rules/all/rules_table/rules_table_context'); +jest.mock('../../../../detection_engine/rule_management/api/api'); +jest.mock( + '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context' +); jest.mock('../../../../common/lib/apm/use_start_transaction'); const useAppToastsValueMock = useAppToastsMock.create(); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx index 6c924a68da4a1..bcd0e74d6ef9f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx @@ -10,13 +10,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSwitch } from '@elasti import { noop } from 'lodash'; import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; -import { BulkAction } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { BulkAction } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; -import { useUpdateRulesCache } from '../../../containers/detection_engine/rules/use_find_rules_query'; -import { executeRulesBulkAction } from '../../../pages/detection_engine/rules/all/actions'; -import { useRulesTableContextOptional } from '../../../pages/detection_engine/rules/all/rules_table/rules_table_context'; +import { useExecuteBulkAction } from '../../../../detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action'; +import { useRulesTableContextOptional } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context'; const StaticSwitch = styled(EuiSwitch)` .euiSwitch__thumb, @@ -47,9 +45,8 @@ export const RuleSwitchComponent = ({ }: RuleSwitchProps) => { const [myIsLoading, setMyIsLoading] = useState(false); const rulesTableContext = useRulesTableContextOptional(); - const updateRulesCache = useUpdateRulesCache(); - const toasts = useAppToasts(); const { startTransaction } = useStartTransaction(); + const { executeBulkAction } = useExecuteBulkAction(); const onRuleStateChange = useCallback( async (event: EuiSwitchEvent) => { @@ -57,9 +54,8 @@ export const RuleSwitchComponent = ({ startTransaction({ name: enabled ? SINGLE_RULE_ACTIONS.DISABLE : SINGLE_RULE_ACTIONS.ENABLE, }); - const bulkActionResponse = await executeRulesBulkAction({ + const bulkActionResponse = await executeBulkAction({ setLoadingRules: rulesTableContext?.actions.setLoadingRules, - toasts, onSuccess: rulesTableContext ? undefined : noop, action: event.target.checked ? BulkAction.enable : BulkAction.disable, search: { ids: [id] }, @@ -67,12 +63,11 @@ export const RuleSwitchComponent = ({ }); if (bulkActionResponse?.attributes.results.updated.length) { // The rule was successfully updated - updateRulesCache(bulkActionResponse.attributes.results.updated); onChange?.(bulkActionResponse.attributes.results.updated[0].enabled); } setMyIsLoading(false); }, - [enabled, id, onChange, rulesTableContext, startTransaction, toasts, updateRulesCache] + [enabled, executeBulkAction, id, onChange, rulesTableContext, startTransaction] ); const showLoader = useMemo((): boolean => { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx index af746d158e2a7..9f3e6c927de83 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import { upperFirst } from 'lodash/fp'; import React from 'react'; +import { upperFirst } from 'lodash/fp'; import { euiLightVars } from '@kbn/ui-theme'; import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; + import { HealthTruncateText } from '../../../../common/components/health_truncate_text'; const { euiColorVis0, euiColorVis5, euiColorVis7, euiColorVis9 } = euiLightVars; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx index 961620d1521c4..aeefb4091307e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx @@ -19,22 +19,23 @@ import { import { noop } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; + +import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; +import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { + FieldComponent, + AutocompleteFieldMatchComponent, +} from '@kbn/securitysolution-autocomplete'; import type { Severity, SeverityMapping, SeverityMappingItem, } from '@kbn/securitysolution-io-ts-alerting-types'; -import { - FieldComponent, - AutocompleteFieldMatchComponent, -} from '@kbn/securitysolution-autocomplete'; -import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; -import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import * as i18n from './translations'; import type { SeverityOptionItem } from '../step_about_rule/data'; import type { AboutStepSeverity } from '../../../pages/detection_engine/rules/types'; import { useKibana } from '../../../../common/lib/kibana'; +import * as i18n from './translations'; const NestedContent = styled.div` margin-left: 24px; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx index d0d471e3a727b..bab334b1c7f1f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx @@ -5,11 +5,10 @@ * 2.0. */ +import React from 'react'; import styled from 'styled-components'; import { EuiHealth } from '@elastic/eui'; import { euiLightVars } from '@kbn/ui-theme'; -import React from 'react'; - import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; import * as I18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx index 4c3f635069c0f..5c5554b72ad8a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx @@ -13,7 +13,7 @@ import { stubIndexPattern } from '@kbn/data-plugin/common/stubs'; import { StepAboutRule } from '.'; import { useFetchIndex } from '../../../../common/containers/source'; import { useGetInstalledJob } from '../../../../common/components/ml/hooks/use_get_jobs'; -import { mockAboutStepRule } from '../../../pages/detection_engine/rules/all/__mocks__/mock'; +import { mockAboutStepRule } from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import { StepRuleDescription } from '../description_step'; import { stepAboutDefaultValue } from './default_value'; import type { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.tsx index 34303c00e5153..22c9670e3bed8 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.tsx @@ -44,7 +44,7 @@ import { AutocompleteField } from '../autocomplete_field'; import { useFetchIndex } from '../../../../common/containers/source'; import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../common/constants'; import { useKibana } from '../../../../common/lib/kibana'; -import { useRuleIndices } from '../../../containers/detection_engine/rules/use_rule_indices'; +import { useRuleIndices } from '../../../../detection_engine/rule_management/logic/use_rule_indices'; const CommonUseField = getUseField({ component: Field }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx index cafbc1f173f0b..ae46ccef9e859 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx @@ -11,7 +11,7 @@ import { EuiProgress, EuiButtonGroup } from '@elastic/eui'; import { ThemeProvider } from 'styled-components'; import { StepAboutRuleToggleDetails } from '.'; -import { mockAboutStepRule } from '../../../pages/detection_engine/rules/all/__mocks__/mock'; +import { mockAboutStepRule } from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import { HeaderSection } from '../../../../common/components/header_section'; import { StepAboutRule } from '../step_about_rule'; import type { AboutStepRule } from '../../../pages/detection_engine/rules/types'; 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 1dd2a2d1de798..dc926fd4f74e2 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 @@ -36,7 +36,7 @@ import type { EqlOptionsSelected, FieldsEqlOptions } from '../../../../../common import { filterRuleFieldsForType, getStepDataDataSource, -} from '../../../pages/detection_engine/rules/create/helpers'; +} from '../../../../detection_engine/rule_creation_ui/pages/rule_creation/helpers'; import type { DefineStepRule, RuleStepProps } from '../../../pages/detection_engine/rules/types'; import { RuleStep, DataSourceType } from '../../../pages/detection_engine/rules/types'; import { StepRuleDescription } from '../description_step'; diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx index ba641875b2500..f4364443a6dfa 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { EuiButton, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; -import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; +import type { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { isActiveTimeline } from '../../../helpers'; import { TableId } from '../../../../common/types'; import { useResponderActionItem } from '../endpoint_responder'; @@ -45,7 +45,7 @@ export interface TakeActionDropdownProps { isHostIsolationPanelOpen: boolean; loadingEventDetails: boolean; onAddEventFilterClick: () => void; - onAddExceptionTypeClick: (type: ExceptionListType) => void; + onAddExceptionTypeClick: (type?: ExceptionListTypeEnum) => void; onAddIsolationStatusClick: (action: 'isolateHost' | 'unisolateHost') => void; refetch: (() => void) | undefined; refetchFlyoutData: () => Promise; @@ -144,7 +144,7 @@ export const TakeActionDropdown = React.memo( ); const handleOnAddExceptionTypeClick = useCallback( - (type: ExceptionListType) => { + (type?: ExceptionListTypeEnum) => { onAddExceptionTypeClick(type); setIsPopoverOpen(false); }, diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts index bab81d4625f0c..060f36f5bb5c8 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/exceptions/get_es_query_filter.ts @@ -6,24 +6,25 @@ */ import type { Language } from '@kbn/securitysolution-io-ts-alerting-types'; -import type { - ExceptionListItemSchema, - CreateExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; import type { Filter, EsQueryConfig, DataViewBase } from '@kbn/es-query'; import { getExceptionFilterFromExceptions } from '@kbn/securitysolution-list-api'; import { buildEsQuery } from '@kbn/es-query'; + +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { KibanaServices } from '../../../../common/lib/kibana'; -import type { Query, Index } from '../../../../../common/detection_engine/schemas/common'; +import type { + IndexPatternArray, + RuleQuery, +} from '../../../../../common/detection_engine/rule_schema'; import type { ESBoolQuery } from '../../../../../common/typed_json'; export const getEsQueryFilter = async ( - query: Query, + query: RuleQuery, language: Language, filters: unknown, - index: Index, - lists: Array, + index: IndexPatternArray, + lists: ExceptionListItemSchema[], excludeExceptions: boolean = true ): Promise => { const indexPattern: DataViewBase = { 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 ab4d1eedbd2ae..a78191913562a 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 @@ -8,10 +8,10 @@ import { flow } from 'fp-ts/lib/function'; import { addIdToItem, removeIdFromItem } from '@kbn/securitysolution-utils'; import type { - CreateRulesSchema, - UpdateRulesSchema, -} from '../../../../../common/detection_engine/schemas/request'; -import type { Rule } from './types'; + RuleCreateProps, + RuleUpdateProps, +} from '../../../../../common/detection_engine/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 @@ -31,8 +31,8 @@ import type { Rule } from './types'; * @returns The rule transformed from the output */ export const transformOutput = ( - rule: CreateRulesSchema | UpdateRulesSchema -): CreateRulesSchema | UpdateRulesSchema => flow(removeIdFromThreatMatchArray)(rule); + rule: RuleCreateProps | RuleUpdateProps +): RuleCreateProps | RuleUpdateProps => flow(removeIdFromThreatMatchArray)(rule); /** * Transforms the output of rules to compensate for technical debt or UI concerns such as @@ -84,8 +84,8 @@ export const addIdToThreatMatchArray = (rule: Rule): Rule => { * @returns rule The rule but with id removed from the threat array and entries */ export const removeIdFromThreatMatchArray = ( - rule: CreateRulesSchema | UpdateRulesSchema -): CreateRulesSchema | UpdateRulesSchema => { + rule: RuleCreateProps | RuleUpdateProps +): RuleCreateProps | RuleUpdateProps => { if (rule.type === 'threat_match' && rule.threat_mapping != null) { const threatMapWithoutId = rule.threat_mapping.map((mapping) => { const newEntries = mapping.entries.map((entry) => removeIdFromItem(entry)); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/translations.ts deleted file mode 100644 index c1161db6db26f..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/translations.ts +++ /dev/null @@ -1,111 +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 { i18n } from '@kbn/i18n'; - -export const RULE_AND_TIMELINE_FETCH_FAILURE = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.rulesAndTimelines', - { - defaultMessage: 'Failed to fetch Rules and Timelines', - } -); - -export const RULE_ADD_FAILURE = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.addRuleFailDescription', - { - defaultMessage: 'Failed to add Rule', - } -); - -export const RULE_AND_TIMELINE_PREPACKAGED_FAILURE = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleAndTimelineFailDescription', - { - defaultMessage: 'Failed to installed pre-packaged rules and timelines from elastic', - } -); - -export const RULE_AND_TIMELINE_PREPACKAGED_SUCCESS = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleAndTimelineSuccesDescription', - { - defaultMessage: 'Installed pre-packaged rules and timeline templates from elastic', - } -); - -export const RULE_PREPACKAGED_SUCCESS = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleSuccesDescription', - { - defaultMessage: 'Installed pre-packaged rules from elastic', - } -); - -export const TIMELINE_PREPACKAGED_SUCCESS = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription', - { - defaultMessage: 'Installed pre-packaged timeline templates from elastic', - } -); - -export const TAG_FETCH_FAILURE = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription', - { - defaultMessage: 'Failed to fetch Tags', - } -); - -export const LOAD_PREPACKAGED_RULES = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.loadPrePackagedRulesButton', - { - defaultMessage: 'Load Elastic prebuilt rules', - } -); - -export const LOAD_PREPACKAGED_TIMELINE_TEMPLATES = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.loadPrePackagedTimelineTemplatesButton', - { - defaultMessage: 'Load Elastic prebuilt timeline templates', - } -); - -export const LOAD_PREPACKAGED_RULES_AND_TEMPLATES = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.loadPrePackagedRulesAndTemplatesButton', - { - defaultMessage: 'Load Elastic prebuilt rules and timeline templates', - } -); - -export const RELOAD_MISSING_PREPACKAGED_RULES = (missingRules: number) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesButton', - { - values: { missingRules }, - defaultMessage: - 'Install {missingRules} Elastic prebuilt {missingRules, plural, =1 {rule} other {rules}} ', - } - ); - -export const RELOAD_MISSING_PREPACKAGED_TIMELINES = (missingTimelines: number) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedTimelinesButton', - { - values: { missingTimelines }, - defaultMessage: - 'Install {missingTimelines} Elastic prebuilt {missingTimelines, plural, =1 {timeline} other {timelines}} ', - } - ); - -export const RELOAD_MISSING_PREPACKAGED_RULES_AND_TIMELINES = ( - missingRules: number, - missingTimelines: number -) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton', - { - values: { missingRules, missingTimelines }, - defaultMessage: - 'Install {missingRules} Elastic prebuilt {missingRules, plural, =1 {rule} other {rules}} and {missingTimelines} Elastic prebuilt {missingTimelines, plural, =1 {timeline} other {timelines}} ', - } - ); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_create_rule.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_create_rule.test.tsx deleted file mode 100644 index 71d8aacff4280..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_create_rule.test.tsx +++ /dev/null @@ -1,68 +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 { renderHook, act } from '@testing-library/react-hooks'; - -import type { ReturnCreateRule } from './use_create_rule'; -import { useCreateRule } from './use_create_rule'; -import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { getRulesSchemaMock } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; -import { TestProviders } from '../../../../common/mock'; - -jest.mock('./api'); -jest.mock('../../../../common/hooks/use_app_toasts'); - -describe('useCreateRule', () => { - (useAppToasts as jest.Mock).mockReturnValue(useAppToastsMock.create()); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('init', async () => { - const { result } = renderHook(() => useCreateRule(), { - wrapper: TestProviders, - }); - - expect(result.current).toEqual([{ isLoading: false, ruleId: null }, result.current[1]]); - }); - - test('saving rule with isLoading === true', async () => { - await act(async () => { - const { result, rerender, waitForNextUpdate } = renderHook( - () => useCreateRule(), - { - wrapper: TestProviders, - } - ); - await waitForNextUpdate(); - result.current[1](getCreateRulesSchemaMock()); - rerender(); - expect(result.current).toEqual([{ isLoading: true, ruleId: null }, result.current[1]]); - }); - }); - - test('updates ruleId after the rule has been saved', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => useCreateRule(), - { - wrapper: TestProviders, - } - ); - await waitForNextUpdate(); - result.current[1](getCreateRulesSchemaMock()); - await waitForNextUpdate(); - expect(result.current).toEqual([ - { isLoading: false, ruleId: getRulesSchemaMock().id }, - result.current[1], - ]); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_create_rule.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_create_rule.tsx deleted file mode 100644 index f2b76c306dc5f..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_create_rule.tsx +++ /dev/null @@ -1,71 +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 { Dispatch } from 'react'; -import { useEffect, useState } from 'react'; - -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import type { CreateRulesSchema } from '../../../../../common/detection_engine/schemas/request'; - -import { createRule } from './api'; -import * as i18n from './translations'; -import { transformOutput } from './transforms'; -import { useInvalidateRules } from './use_find_rules_query'; -import { useInvalidatePrePackagedRulesStatus } from './use_pre_packaged_rules_status'; - -interface CreateRuleReturn { - isLoading: boolean; - ruleId: string | null; -} - -export type ReturnCreateRule = [CreateRuleReturn, Dispatch]; - -export const useCreateRule = (): ReturnCreateRule => { - const [rule, setRule] = useState(null); - const [ruleId, setRuleId] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const { addError } = useAppToasts(); - const invalidateRules = useInvalidateRules(); - const invalidatePrePackagedRulesStatus = useInvalidatePrePackagedRulesStatus(); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - setRuleId(null); - const saveRule = async () => { - if (rule != null) { - try { - setIsLoading(true); - const createRuleResponse = await createRule({ - rule: transformOutput(rule), - signal: abortCtrl.signal, - }); - invalidateRules(); - invalidatePrePackagedRulesStatus(); - if (isSubscribed) { - setRuleId(createRuleResponse.id); - } - } catch (error) { - if (isSubscribed) { - addError(error, { title: i18n.RULE_ADD_FAILURE }); - } - } - if (isSubscribed) { - setIsLoading(false); - } - } - }; - - saveRule(); - return () => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [rule, addError, invalidateRules, invalidatePrePackagedRulesStatus]); - - return [{ isLoading, ruleId }, setRule]; -}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.test.tsx deleted file mode 100644 index 5cddbeef63028..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.test.tsx +++ /dev/null @@ -1,540 +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 { act, renderHook } from '@testing-library/react-hooks'; -import { shallow } from 'enzyme'; -import type { ReactElement } from 'react'; -import { useToasts } from '../../../../common/lib/kibana'; -import { TestProviders } from '../../../../common/mock'; -import * as api from './api'; -import * as i18n from './translations'; -import type { ReturnPrePackagedRulesAndTimelines } from './use_pre_packaged_rules'; -import { usePrePackagedRules } from './use_pre_packaged_rules'; - -jest.mock('../../../../common/lib/kibana', () => ({ - useKibana: jest.fn(), - useToasts: jest.fn().mockReturnValue({ - addError: jest.fn(), - addSuccess: jest.fn(), - addWarning: jest.fn(), - remove: jest.fn(), - }), -})); - -jest.mock('./api', () => ({ - getPrePackagedRulesStatus: jest.fn(), - createPrepackagedRules: jest.fn(), -})); - -describe('usePrePackagedRules', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('initial state', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: null, - hasIndexWrite: null, - isAuthenticated: null, - hasEncryptionKey: null, - isSignalIndexExists: null, - }), - { wrapper: TestProviders } - ); - - await waitForNextUpdate(); - - expect(result.current).toEqual({ - getLoadPrebuiltRulesAndTemplatesButton: expect.any(Function), - getReloadPrebuiltRulesAndTemplatesButton: expect.any(Function), - createPrePackagedRules: expect.any(Function), - loading: true, - loadingCreatePrePackagedRules: false, - }); - }); - }); - - test('fetch getPrePackagedRulesStatus', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 33, - rules_installed: 12, - rules_not_installed: 0, - rules_not_updated: 0, - timelines_installed: 0, - timelines_not_installed: 0, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: null, - hasIndexWrite: null, - isAuthenticated: null, - hasEncryptionKey: null, - isSignalIndexExists: null, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - getLoadPrebuiltRulesAndTemplatesButton: - result.current.getLoadPrebuiltRulesAndTemplatesButton, - getReloadPrebuiltRulesAndTemplatesButton: - result.current.getReloadPrebuiltRulesAndTemplatesButton, - createPrePackagedRules: result.current.createPrePackagedRules, - loading: false, - loadingCreatePrePackagedRules: false, - rulesCustomInstalled: 33, - rulesInstalled: 12, - rulesNotInstalled: 0, - rulesNotUpdated: 0, - timelinesInstalled: 0, - timelinesNotInstalled: 0, - timelinesNotUpdated: 0, - }); - }); - }); - - test('happy path to createPrePackagedRules', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 33, - rules_installed: 12, - rules_not_installed: 0, - rules_not_updated: 0, - timelines_installed: 0, - timelines_not_installed: 0, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - result.current.createPrePackagedRules(); - await waitForNextUpdate(); - expect(api.createPrepackagedRules).toHaveBeenCalled(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - getLoadPrebuiltRulesAndTemplatesButton: - result.current.getLoadPrebuiltRulesAndTemplatesButton, - getReloadPrebuiltRulesAndTemplatesButton: - result.current.getReloadPrebuiltRulesAndTemplatesButton, - createPrePackagedRules: result.current.createPrePackagedRules, - loading: false, - loadingCreatePrePackagedRules: false, - rulesCustomInstalled: 33, - rulesInstalled: 12, - rulesNotInstalled: 0, - rulesNotUpdated: 0, - timelinesInstalled: 0, - timelinesNotInstalled: 0, - timelinesNotUpdated: 0, - }); - }); - }); - - test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_RULES', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 0, - rules_installed: 0, - rules_not_installed: 1, - rules_not_updated: 0, - timelines_installed: 0, - timelines_not_installed: 0, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({ - isDisabled: false, - onClick: jest.fn(), - 'data-test-subj': 'button', - }); - const wrapper = shallow(button as ReactElement); - expect(wrapper.find('[data-test-subj="button"]').text()).toEqual(i18n.LOAD_PREPACKAGED_RULES); - }); - }); - - test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_TIMELINE_TEMPLATES', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 0, - rules_installed: 0, - rules_not_installed: 0, - rules_not_updated: 0, - timelines_installed: 0, - timelines_not_installed: 1, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({ - isDisabled: false, - onClick: jest.fn(), - 'data-test-subj': 'button', - }); - const wrapper = shallow(button as ReactElement); - expect(wrapper.find('[data-test-subj="button"]').text()).toEqual( - i18n.LOAD_PREPACKAGED_TIMELINE_TEMPLATES - ); - }); - }); - - test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_RULES_AND_TEMPLATES', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 0, - rules_installed: 0, - rules_not_installed: 1, - rules_not_updated: 0, - timelines_installed: 0, - timelines_not_installed: 1, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({ - isDisabled: false, - onClick: jest.fn(), - 'data-test-subj': 'button', - }); - const wrapper = shallow(button as ReactElement); - expect(wrapper.find('[data-test-subj="button"]').text()).toEqual( - i18n.LOAD_PREPACKAGED_RULES_AND_TEMPLATES - ); - }); - }); - - test('getReloadPrebuiltRulesAndTemplatesButton - missing rules and templates', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 0, - rules_installed: 1, - rules_not_installed: 1, - rules_not_updated: 0, - timelines_installed: 0, - timelines_not_installed: 1, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({ - isDisabled: false, - onClick: jest.fn(), - }); - const wrapper = shallow(button as ReactElement); - expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual( - 'Install 1 Elastic prebuilt rule and 1 Elastic prebuilt timeline ' - ); - }); - }); - - test('getReloadPrebuiltRulesAndTemplatesButton - missing rules', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 0, - rules_installed: 1, - rules_not_installed: 1, - rules_not_updated: 0, - timelines_installed: 0, - timelines_not_installed: 0, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({ - isDisabled: false, - onClick: jest.fn(), - }); - const wrapper = shallow(button as ReactElement); - expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual( - 'Install 1 Elastic prebuilt rule ' - ); - }); - }); - - test('getReloadPrebuiltRulesAndTemplatesButton - missing templates', async () => { - (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({ - rules_custom_installed: 0, - rules_installed: 1, - rules_not_installed: 0, - rules_not_updated: 0, - timelines_installed: 1, - timelines_not_installed: 1, - timelines_not_updated: 0, - }); - (api.createPrepackagedRules as jest.Mock).mockResolvedValue({ - rules_installed: 0, - rules_updated: 0, - timelines_installed: 0, - timelines_updated: 0, - }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({ - isDisabled: false, - onClick: jest.fn(), - }); - const wrapper = shallow(button as ReactElement); - expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual( - 'Install 1 Elastic prebuilt timeline ' - ); - }); - }); - - test('unhappy path to createPrePackagedRules', async () => { - (api.createPrepackagedRules as jest.Mock).mockRejectedValue(new Error('Something went wrong')); - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - result.current.createPrePackagedRules(); - await waitForNextUpdate(); - expect(api.createPrepackagedRules).toHaveBeenCalled(); - expect(useToasts().addError).toHaveBeenCalled(); - }); - }); - - test('can NOT createPrePackagedRules because canUserCrud === false', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: false, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - result.current.createPrePackagedRules(); - await waitForNextUpdate(); - expect(api.createPrepackagedRules).not.toHaveBeenCalled(); - }); - }); - - test('can NOT createPrePackagedRules because hasIndexWrite === false', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: false, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - result.current.createPrePackagedRules(); - await waitForNextUpdate(); - expect(api.createPrepackagedRules).not.toHaveBeenCalled(); - }); - }); - - test('can NOT createPrePackagedRules because isAuthenticated === false', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: false, - hasEncryptionKey: true, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - result.current.createPrePackagedRules(); - await waitForNextUpdate(); - expect(api.createPrepackagedRules).not.toHaveBeenCalled(); - }); - }); - - test('can NOT createPrePackagedRules because hasEncryptionKey === false', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: false, - isSignalIndexExists: true, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - result.current.createPrePackagedRules(); - await waitForNextUpdate(); - expect(api.createPrepackagedRules).not.toHaveBeenCalled(); - }); - }); - - test('can NOT createPrePackagedRules because isSignalIndexExists === false', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => - usePrePackagedRules({ - canUserCRUD: true, - hasIndexWrite: true, - isAuthenticated: true, - hasEncryptionKey: true, - isSignalIndexExists: false, - }), - { wrapper: TestProviders } - ); - await waitForNextUpdate(); - result.current.createPrePackagedRules(); - await waitForNextUpdate(); - expect(api.createPrepackagedRules).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx deleted file mode 100644 index 88bfe5c618c01..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx +++ /dev/null @@ -1,200 +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 { EuiButton } from '@elastic/eui'; -import React, { useCallback, useMemo } from 'react'; -import { - getPrePackagedRuleStatus, - getPrePackagedTimelineStatus, -} from '../../../pages/detection_engine/rules/helpers'; -import * as i18n from './translations'; -import { useInstallPrePackagedRules } from './use_install_pre_packaged_rules'; -import type { PrePackagedRulesStatusResponse } from './use_pre_packaged_rules_status'; -import { usePrePackagedRulesStatus } from './use_pre_packaged_rules_status'; - -type GetLoadPrebuiltRulesAndTemplatesButton = (args: { - isDisabled: boolean; - onClick: () => void; - fill?: boolean; - 'data-test-subj'?: string; -}) => React.ReactNode | null; - -type GetReloadPrebuiltRulesAndTemplatesButton = ({ - isDisabled, - onClick, - fill, -}: { - isDisabled: boolean; - onClick: () => void; - fill?: boolean; -}) => React.ReactNode | null; - -interface ReturnPrePackagedRules { - createPrePackagedRules: () => void; - loading: boolean; - loadingCreatePrePackagedRules: boolean; - getLoadPrebuiltRulesAndTemplatesButton: GetLoadPrebuiltRulesAndTemplatesButton; - getReloadPrebuiltRulesAndTemplatesButton: GetReloadPrebuiltRulesAndTemplatesButton; -} - -export type ReturnPrePackagedRulesAndTimelines = ReturnPrePackagedRules & - Partial; - -interface UsePrePackagedRuleProps { - canUserCRUD: boolean | null; - hasIndexWrite: boolean | null; - isAuthenticated: boolean | null; - hasEncryptionKey: boolean | null; - isSignalIndexExists: boolean | null; -} - -/** - * Hook for using to get status about pre-packaged Rules from the Detection Engine API - * - * @param hasIndexWrite boolean - * @param isAuthenticated boolean - * @param hasEncryptionKey boolean - * @param isSignalIndexExists boolean - * - */ -export const usePrePackagedRules = ({ - canUserCRUD, - hasIndexWrite, - isAuthenticated, - hasEncryptionKey, - isSignalIndexExists, -}: UsePrePackagedRuleProps): ReturnPrePackagedRulesAndTimelines => { - const { data: prePackagedRulesStatus, isFetching } = usePrePackagedRulesStatus(); - const { mutate: installPrePackagedRules, isLoading: loadingCreatePrePackagedRules } = - useInstallPrePackagedRules(); - - const createPrePackagedRules = useCallback(() => { - if ( - canUserCRUD && - hasIndexWrite && - isAuthenticated && - hasEncryptionKey && - isSignalIndexExists - ) { - installPrePackagedRules(); - } - }, [ - canUserCRUD, - hasEncryptionKey, - hasIndexWrite, - installPrePackagedRules, - isAuthenticated, - isSignalIndexExists, - ]); - - const prePackagedAssetsStatus = useMemo( - () => - getPrePackagedRuleStatus( - prePackagedRulesStatus?.rulesInstalled, - prePackagedRulesStatus?.rulesNotInstalled, - prePackagedRulesStatus?.rulesNotUpdated - ), - [ - prePackagedRulesStatus?.rulesInstalled, - prePackagedRulesStatus?.rulesNotInstalled, - prePackagedRulesStatus?.rulesNotUpdated, - ] - ); - - const prePackagedTimelineStatus = useMemo( - () => - getPrePackagedTimelineStatus( - prePackagedRulesStatus?.timelinesInstalled, - prePackagedRulesStatus?.timelinesNotInstalled, - prePackagedRulesStatus?.timelinesNotUpdated - ), - [ - prePackagedRulesStatus?.timelinesInstalled, - prePackagedRulesStatus?.timelinesNotInstalled, - prePackagedRulesStatus?.timelinesNotUpdated, - ] - ); - const getLoadPrebuiltRulesAndTemplatesButton = useCallback( - ({ isDisabled, onClick, fill, 'data-test-subj': dataTestSubj = 'loadPrebuiltRulesBtn' }) => { - return (prePackagedAssetsStatus === 'ruleNotInstalled' || - prePackagedTimelineStatus === 'timelinesNotInstalled') && - prePackagedAssetsStatus !== 'someRuleUninstall' ? ( - - {prePackagedAssetsStatus === 'ruleNotInstalled' && - prePackagedTimelineStatus === 'timelinesNotInstalled' && - i18n.LOAD_PREPACKAGED_RULES_AND_TEMPLATES} - - {prePackagedAssetsStatus === 'ruleNotInstalled' && - prePackagedTimelineStatus !== 'timelinesNotInstalled' && - i18n.LOAD_PREPACKAGED_RULES} - - {prePackagedAssetsStatus !== 'ruleNotInstalled' && - prePackagedTimelineStatus === 'timelinesNotInstalled' && - i18n.LOAD_PREPACKAGED_TIMELINE_TEMPLATES} - - ) : null; - }, - [loadingCreatePrePackagedRules, prePackagedAssetsStatus, prePackagedTimelineStatus] - ); - - const getMissingRulesOrTimelinesButtonTitle = useCallback( - (missingRules: number, missingTimelines: number) => { - if (missingRules > 0 && missingTimelines === 0) - return i18n.RELOAD_MISSING_PREPACKAGED_RULES(missingRules); - else if (missingRules === 0 && missingTimelines > 0) - return i18n.RELOAD_MISSING_PREPACKAGED_TIMELINES(missingTimelines); - else if (missingRules > 0 && missingTimelines > 0) - return i18n.RELOAD_MISSING_PREPACKAGED_RULES_AND_TIMELINES(missingRules, missingTimelines); - }, - [] - ); - - const getReloadPrebuiltRulesAndTemplatesButton = useCallback( - ({ isDisabled, onClick, fill = false }) => { - return prePackagedAssetsStatus === 'someRuleUninstall' || - prePackagedTimelineStatus === 'someTimelineUninstall' ? ( - - {getMissingRulesOrTimelinesButtonTitle( - prePackagedRulesStatus?.rulesNotInstalled ?? 0, - prePackagedRulesStatus?.timelinesNotInstalled ?? 0 - )} - - ) : null; - }, - [ - getMissingRulesOrTimelinesButtonTitle, - loadingCreatePrePackagedRules, - prePackagedAssetsStatus, - prePackagedRulesStatus?.rulesNotInstalled, - prePackagedRulesStatus?.timelinesNotInstalled, - prePackagedTimelineStatus, - ] - ); - - return { - loading: isFetching, - loadingCreatePrePackagedRules, - createPrePackagedRules, - getLoadPrebuiltRulesAndTemplatesButton, - getReloadPrebuiltRulesAndTemplatesButton, - ...prePackagedRulesStatus, - }; -}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules_status.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules_status.ts deleted file mode 100644 index c01bce4fe8bc2..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules_status.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 { useCallback } from 'react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { getPrePackagedRulesStatus } from './api'; -import * as i18n from './translations'; - -const ONE_MINUTE = 60000; - -export interface PrePackagedRulesStatusResponse { - rulesCustomInstalled: number; - rulesInstalled: number; - rulesNotInstalled: number; - rulesNotUpdated: number; - timelinesInstalled: number; - timelinesNotInstalled: number; - timelinesNotUpdated: number; -} - -export const PRE_PACKAGED_RULES_STATUS_QUERY_KEY = 'prePackagedRulesStatus'; - -export const usePrePackagedRulesStatus = () => { - const { addError } = useAppToasts(); - - return useQuery( - [PRE_PACKAGED_RULES_STATUS_QUERY_KEY], - async ({ signal }) => { - const response = await getPrePackagedRulesStatus({ signal }); - - return { - rulesCustomInstalled: response.rules_custom_installed, - rulesInstalled: response.rules_installed, - rulesNotInstalled: response.rules_not_installed, - rulesNotUpdated: response.rules_not_updated, - timelinesInstalled: response.timelines_installed, - timelinesNotInstalled: response.timelines_not_installed, - timelinesNotUpdated: response.timelines_not_updated, - }; - }, - { - staleTime: ONE_MINUTE * 5, - onError: (err) => { - addError(err, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }); - }, - } - ); -}; - -/** - * We should use this hook to invalidate the prepackaged rules cache. For - * example, rule mutations that affect rule set size, like creation or deletion, - * should lead to cache invalidation. - * - * @returns A rules cache invalidation callback - */ -export const useInvalidatePrePackagedRulesStatus = () => { - const queryClient = useQueryClient(); - - return useCallback(() => { - queryClient.invalidateQueries([PRE_PACKAGED_RULES_STATUS_QUERY_KEY], { - refetchType: 'active', - }); - }, [queryClient]); -}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule.test.tsx deleted file mode 100644 index 89e32793b9e9a..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule.test.tsx +++ /dev/null @@ -1,104 +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 { renderHook, act } from '@testing-library/react-hooks'; -import type { ReturnRule } from './use_rule'; -import { useRule } from './use_rule'; -import * as api from './api'; -import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; - -jest.mock('./api'); -jest.mock('../../../../common/hooks/use_app_toasts'); - -describe('useRule', () => { - (useAppToasts as jest.Mock).mockReturnValue(useAppToastsMock.create()); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useRule('myOwnRuleID') - ); - await waitForNextUpdate(); - expect(result.current).toEqual([true, null]); - }); - }); - - test('fetch rule', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useRule('myOwnRuleID') - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual([ - false, - { - actions: [], - author: [], - created_at: 'mm/dd/yyyyTHH:MM:sssz', - created_by: 'mockUser', - description: 'some desc', - enabled: true, - false_positives: [], - filters: [], - from: 'now-360s', - id: '12345678987654321', - immutable: false, - index: [ - 'apm-*-transaction*', - 'traces-apm*', - 'auditbeat-*', - 'endgame-*', - 'filebeat-*', - 'packetbeat-*', - 'winlogbeat-*', - ], - interval: '5m', - language: 'kuery', - name: 'Test rule', - max_signals: 100, - query: "user.email: 'root@elastic.co'", - references: [], - related_integrations: [], - required_fields: [], - risk_score: 75, - risk_score_mapping: [], - rule_id: 'bbd3106e-b4b5-4d7c-a1a2-47531d6a2baf', - setup: '', - severity: 'high', - severity_mapping: [], - tags: ['APM'], - threat: [], - throttle: null, - to: 'now', - type: 'query', - updated_at: 'mm/dd/yyyyTHH:MM:sssz', - updated_by: 'mockUser', - }, - ]); - }); - }); - - test('fetch a new rule', async () => { - const spyOnfetchRuleById = jest.spyOn(api, 'fetchRuleById'); - await act(async () => { - const { rerender, waitForNextUpdate } = renderHook((id) => useRule(id), { - initialProps: 'myOwnRuleID', - }); - await waitForNextUpdate(); - await waitForNextUpdate(); - rerender('newRuleId'); - await waitForNextUpdate(); - expect(spyOnfetchRuleById).toHaveBeenCalledTimes(2); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule.tsx deleted file mode 100644 index bef089555128d..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule.tsx +++ /dev/null @@ -1,65 +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 { useEffect, useState } from 'react'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; - -import { fetchRuleById } from './api'; -import { transformInput } from './transforms'; -import * as i18n from './translations'; -import type { Rule } from './types'; - -export type ReturnRule = [boolean, Rule | null]; - -/** - * Hook for using to get a Rule from the Detection Engine API - * - * @param id desired Rule ID's (not rule_id) - * - */ -export const useRule = (id: string | undefined): ReturnRule => { - const [rule, setRule] = useState(null); - const [loading, setLoading] = useState(true); - const { addError } = useAppToasts(); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - - const fetchData = async (idToFetch: string) => { - try { - setLoading(true); - const ruleResponse = transformInput( - await fetchRuleById({ - id: idToFetch, - signal: abortCtrl.signal, - }) - ); - if (isSubscribed) { - setRule(ruleResponse); - } - } catch (error) { - if (isSubscribed) { - setRule(null); - addError(error, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }); - } - } - if (isSubscribed) { - setLoading(false); - } - }; - if (id != null) { - fetchData(id); - } - return () => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [id, addError]); - - return [loading, rule]; -}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_async.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_async.tsx deleted file mode 100644 index ab93a50f12829..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_async.tsx +++ /dev/null @@ -1,55 +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 { useEffect, useCallback } from 'react'; - -import { flow } from 'fp-ts/lib/function'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; -import { useHttp } from '../../../../common/lib/kibana'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { pureFetchRuleById } from './api'; -import type { Rule } from './types'; -import * as i18n from './translations'; -import { transformInput } from './transforms'; - -export interface UseRuleAsync { - error: unknown; - loading: boolean; - refresh: () => void; - rule: Rule | null; -} - -const _fetchRule = flow(withOptionalSignal(pureFetchRuleById), async (rule: Promise) => - transformInput(await rule) -); - -/** This does not use "_useRuleAsyncInternal" as that would deactivate the useHooks linter rule, so instead it has the word "Internal" post-pended */ -const useRuleAsyncInternal = () => useAsync(_fetchRule); - -export const useRuleAsync = (ruleId: string): UseRuleAsync => { - const { start, loading, result, error } = useRuleAsyncInternal(); - const http = useHttp(); - const { addError } = useAppToasts(); - - const fetch = useCallback(() => { - start({ id: ruleId, http }); - }, [http, ruleId, start]); - - // initial fetch - useEffect(() => { - fetch(); - }, [fetch]); - - // toast on error - useEffect(() => { - if (error != null) { - addError(error, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }); - } - }, [addError, error]); - - return { error, loading, refresh: fetch, rule: result ?? null }; -}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_with_fallback.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_with_fallback.test.tsx deleted file mode 100644 index c8e2bc3e98279..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_with_fallback.test.tsx +++ /dev/null @@ -1,378 +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 { renderHook, act } from '@testing-library/react-hooks'; -import type { SecurityAppError } from '@kbn/securitysolution-t-grid'; -import { alertsMock8x, alertMockEmptyResults } from '../alerts/mock'; -import type { AlertSearchResponse } from '../alerts/types'; -import { useRuleWithFallback } from './use_rule_with_fallback'; -import * as api from './api'; -import * as alertsAPI from '../alerts/api'; -import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; - -jest.mock('./api'); -jest.mock('../alerts/api'); -jest.mock('../../../../common/hooks/use_app_toasts'); -jest.mock('../../../../common/lib/kibana'); - -const mockNotFoundErrorForRule = () => { - (api.fetchRuleById as jest.Mock).mockImplementation(async () => { - const err = new Error('Not found') as SecurityAppError; - err.body = { status_code: 404, message: 'Rule Not found' }; - throw err; - }); -}; - -describe('useRuleWithFallback', () => { - (useAppToasts as jest.Mock).mockReturnValue(useAppToastsMock.create()); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should return initial state on mount', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => useRuleWithFallback('testRuleId')); - await waitForNextUpdate(); - expect(result.current).toEqual({ - error: undefined, - isExistingRule: true, - loading: false, - refresh: expect.any(Function), - rule: null, - }); - }); - }); - - it('should return the rule if it exists', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => useRuleWithFallback('testRuleId')); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toMatchInlineSnapshot(` - Object { - "error": undefined, - "isExistingRule": true, - "loading": false, - "refresh": [Function], - "rule": Object { - "actions": Array [], - "author": Array [], - "created_at": "mm/dd/yyyyTHH:MM:sssz", - "created_by": "mockUser", - "description": "some desc", - "enabled": true, - "false_positives": Array [], - "filters": Array [], - "from": "now-360s", - "id": "12345678987654321", - "immutable": false, - "index": Array [ - "apm-*-transaction*", - "traces-apm*", - "auditbeat-*", - "endgame-*", - "filebeat-*", - "packetbeat-*", - "winlogbeat-*", - ], - "interval": "5m", - "language": "kuery", - "max_signals": 100, - "name": "Test rule", - "query": "user.email: 'root@elastic.co'", - "references": Array [], - "related_integrations": Array [], - "required_fields": Array [], - "risk_score": 75, - "risk_score_mapping": Array [], - "rule_id": "bbd3106e-b4b5-4d7c-a1a2-47531d6a2baf", - "setup": "", - "severity": "high", - "severity_mapping": Array [], - "tags": Array [ - "APM", - ], - "threat": Array [], - "throttle": null, - "to": "now", - "type": "query", - "updated_at": "mm/dd/yyyyTHH:MM:sssz", - "updated_by": "mockUser", - }, - } - `); - }); - }); - - it("should fallback to fetching rule data from a 7.x signal if the rule doesn't exist", async () => { - mockNotFoundErrorForRule(); - await act(async () => { - const { result, waitForNextUpdate } = renderHook((id) => useRuleWithFallback(id), { - initialProps: 'testRuleId', - }); - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toMatchInlineSnapshot(` - Object { - "error": [Error: Not found], - "isExistingRule": false, - "loading": false, - "refresh": [Function], - "rule": Object { - "created_at": "2020-02-12T19:49:29.417Z", - "created_by": "elastic", - "description": "matches most events", - "enabled": true, - "false_positives": Array [], - "filters": Array [], - "from": "now-360s", - "id": "2df3a613-f5a8-4b55-bf6a-487fc820b842", - "immutable": false, - "index": Array [ - "apm-*-transaction*", - "traces-apm*", - "auditbeat-*", - "endgame-*", - "filebeat-*", - "packetbeat-*", - "winlogbeat-*", - ], - "interval": "5m", - "language": "kuery", - "max_signals": 100, - "meta": Object { - "from": "1m", - }, - "name": "matches host.name exists", - "output_index": ".siem-signals-default", - "query": "host.name : *", - "references": Array [ - "https://google.com", - ], - "risk_score": 79, - "rule_id": "82b2b065-a2ee-49fc-9d6d-781a75c3d280", - "severity": "high", - "tags": Array [ - "host.name exists", - "for testing", - ], - "threat": Array [ - Object { - "framework": "MITRE ATT&CK", - "tactic": Object { - "id": "TA0006", - "name": "Credential Access", - "reference": "https://attack.mitre.org/tactics/TA0006", - }, - "technique": Array [ - Object { - "id": "T1110", - "name": "Brute Force", - "reference": "https://attack.mitre.org/techniques/T1110", - }, - Object { - "id": "T1098", - "name": "Account Manipulation", - "reference": "https://attack.mitre.org/techniques/T1098", - }, - Object { - "id": "T1081", - "name": "Credentials in Files", - "reference": "https://attack.mitre.org/techniques/T1081", - }, - ], - }, - Object { - "framework": "MITRE ATT&CK", - "tactic": Object { - "id": "TA0009", - "name": "Collection", - "reference": "https://attack.mitre.org/tactics/TA0009", - }, - "technique": Array [ - Object { - "id": "T1530", - "name": "Data from Cloud Storage Object", - "reference": "https://attack.mitre.org/techniques/T1530", - }, - ], - }, - ], - "to": "now", - "type": "query", - "updated_at": "2020-02-14T23:15:06.186Z", - "updated_by": "elastic", - "version": 1, - }, - } - `); - }); - }); - - it("should fallback to fetching rule data from an 8.0 alert if the rule doesn't exist", async () => { - // Override default mock coming from ../alerts/__mocks__/api.ts - const spy = jest.spyOn(alertsAPI, 'fetchQueryAlerts').mockImplementation(async () => { - return alertsMock8x as AlertSearchResponse; - }); - - mockNotFoundErrorForRule(); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook((id) => useRuleWithFallback(id), { - initialProps: 'testRuleId', - }); - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toMatchInlineSnapshot(` - Object { - "error": [Error: Not found], - "isExistingRule": false, - "loading": false, - "refresh": [Function], - "rule": Object { - "actions": Array [], - "author": Array [ - "author", - ], - "category": "Custom Query Rule", - "consumer": "siem", - "created_at": "2022-01-11T23:22:47.678Z", - "created_by": "elastic", - "description": "8.1: To Be Deleted", - "enabled": true, - "exceptions_list": Array [], - "false_positives": Array [ - "fp", - ], - "filters": Array [], - "from": "now-360s", - "immutable": false, - "index": Array [ - "apm-*-transaction*", - "traces-apm*", - "auditbeat-*", - "endgame-*", - "filebeat-*", - "logs-*", - "packetbeat-*", - "winlogbeat-*", - ], - "interval": "5m", - "language": "kuery", - "license": "license", - "max_signals": 100, - "meta": Object { - "from": "1m", - "kibana_siem_app_url": "http://localhost:5601/kbn/app/security", - }, - "name": "944edf04-ea2d-44f9-b89a-574e9a9301da", - "note": "Investigation guuuide", - "producer": "siem", - "query": "host.name:*", - "references": Array [ - "http://www.example.com/1", - ], - "risk_score": 37, - "risk_score_mapping": Array [ - Object { - "field": "Responses.process.pid", - "operator": "equals", - "value": "", - }, - ], - "rule_id": "a2490dbb-33f6-4b03-88d8-b7d009ef58db", - "rule_name_override": "host.id", - "rule_type_id": "siem.queryRule", - "severity": "low", - "severity_mapping": Array [ - Object { - "field": "host.name", - "operator": "equals", - "severity": "low", - "value": "", - }, - ], - "tags": Array [ - "8.0-tag", - ], - "threat": Array [ - Object { - "framework": "MITRE ATT&CK", - "tactic": Object { - "id": "TA0007", - "name": "Discovery", - "reference": "https://attack.mitre.org/tactics/TA0007", - }, - "technique": Array [ - Object { - "id": "T1217", - "name": "Browser Bookmark Discovery", - "reference": "https://attack.mitre.org/techniques/T1217", - "subtechnique": Array [], - }, - Object { - "id": "T1580", - "name": "Cloud Infrastructure Discovery", - "reference": "https://attack.mitre.org/techniques/T1580", - "subtechnique": Array [], - }, - Object { - "id": "T1033", - "name": "System Owner/User Discovery", - "reference": "https://attack.mitre.org/techniques/T1033", - "subtechnique": Array [], - }, - ], - }, - Object { - "framework": "MITRE ATT&CK", - "tactic": Object { - "id": "TA0007", - "name": "Discovery", - "reference": "https://attack.mitre.org/tactics/TA0007", - }, - "technique": Array [], - }, - ], - "to": "now", - "type": "query", - "updated_at": "2022-01-11T23:22:47.678Z", - "updated_by": "elastic", - "uuid": "63136880-7335-11ec-9f1b-9db9315083e9", - "version": 1, - }, - } - `); - }); - // Reset back to default mock coming from ../alerts/__mocks__/api.ts - spy.mockRestore(); - }); - - it('should return rule as null if fallback fetching from 8.0 alert returns empty results', async () => { - // Override default mock coming from ../alerts/__mocks__/api.ts - const spy = jest.spyOn(alertsAPI, 'fetchQueryAlerts').mockImplementation(async () => { - return alertMockEmptyResults; - }); - - mockNotFoundErrorForRule(); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook((id) => useRuleWithFallback(id), { - initialProps: 'testRuleId', - }); - await waitForNextUpdate(); - - expect(result.current.rule).toBeNull(); - }); - // Reset back to default mock coming from ../alerts/__mocks__/api.ts - spy.mockRestore(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_tags.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_tags.test.tsx deleted file mode 100644 index 52b37d6c3d4bf..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_tags.test.tsx +++ /dev/null @@ -1,44 +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 { renderHook, act } from '@testing-library/react-hooks'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; -import type { ReturnTags } from './use_tags'; -import { useTags } from './use_tags'; - -jest.mock('./api'); -jest.mock('../../../../common/hooks/use_app_toasts'); - -describe('useTags', () => { - (useAppToasts as jest.Mock).mockReturnValue(useAppToastsMock.create()); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => useTags()); - await waitForNextUpdate(); - expect(result.current).toEqual([true, [], result.current[2]]); - }); - }); - - test('fetch tags', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => useTags()); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual([ - false, - ['elastic', 'love', 'quality', 'code'], - result.current[2], - ]); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_tags.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_tags.tsx deleted file mode 100644 index 5f16cb593a516..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_tags.tsx +++ /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 { noop } from 'lodash/fp'; -import { useEffect, useState, useRef } from 'react'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { fetchTags } from './api'; -import * as i18n from './translations'; - -export type ReturnTags = [boolean, string[], () => void]; - -/** - * Hook for using the list of Tags from the Detection Engine API - * - */ -export const useTags = (): ReturnTags => { - const [tags, setTags] = useState([]); - const [loading, setLoading] = useState(true); - const reFetchTags = useRef<() => void>(noop); - const { addError } = useAppToasts(); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - - const fetchData = async () => { - setLoading(true); - try { - const fetchTagsResult = await fetchTags({ - signal: abortCtrl.signal, - }); - - if (isSubscribed) { - setTags(fetchTagsResult); - } - } catch (error) { - if (isSubscribed) { - addError(error, { title: i18n.TAG_FETCH_FAILURE }); - } - } - if (isSubscribed) { - setLoading(false); - } - }; - - fetchData(); - reFetchTags.current = fetchData; - - return () => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [addError]); - - return [loading, tags, reFetchTags.current]; -}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_update_rule.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_update_rule.test.tsx deleted file mode 100644 index c25242e03126e..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_update_rule.test.tsx +++ /dev/null @@ -1,64 +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 { renderHook, act } from '@testing-library/react-hooks'; - -import type { ReturnUpdateRule } from './use_update_rule'; -import { useUpdateRule } from './use_update_rule'; -import { getUpdateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { TestProviders } from '../../../../common/mock'; - -jest.mock('./api'); -jest.mock('../../../../common/hooks/use_app_toasts'); - -describe('useUpdateRule', () => { - (useAppToasts as jest.Mock).mockReturnValue(useAppToastsMock.create()); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('init', async () => { - const { result } = renderHook(() => useUpdateRule(), { - wrapper: TestProviders, - }); - - expect(result.current).toEqual([{ isLoading: false, isSaved: false }, result.current[1]]); - }); - - test('saving rule with isLoading === true', async () => { - await act(async () => { - const { result, rerender, waitForNextUpdate } = renderHook( - () => useUpdateRule(), - { - wrapper: TestProviders, - } - ); - await waitForNextUpdate(); - result.current[1](getUpdateRulesSchemaMock()); - rerender(); - expect(result.current).toEqual([{ isLoading: true, isSaved: false }, result.current[1]]); - }); - }); - - test('saved rule with isSaved === true', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook( - () => useUpdateRule(), - { - wrapper: TestProviders, - } - ); - await waitForNextUpdate(); - result.current[1](getUpdateRulesSchemaMock()); - await waitForNextUpdate(); - expect(result.current).toEqual([{ isLoading: false, isSaved: true }, result.current[1]]); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_update_rule.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_update_rule.tsx deleted file mode 100644 index e0144ff8e88eb..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_update_rule.tsx +++ /dev/null @@ -1,66 +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 { Dispatch } from 'react'; -import { useEffect, useState } from 'react'; - -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import type { UpdateRulesSchema } from '../../../../../common/detection_engine/schemas/request'; - -import { transformOutput } from './transforms'; - -import { updateRule } from './api'; -import * as i18n from './translations'; -import { useInvalidateRules } from './use_find_rules_query'; - -interface UpdateRuleReturn { - isLoading: boolean; - isSaved: boolean; -} - -export type ReturnUpdateRule = [UpdateRuleReturn, Dispatch]; - -export const useUpdateRule = (): ReturnUpdateRule => { - const [rule, setRule] = useState(null); - const [isSaved, setIsSaved] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const { addError } = useAppToasts(); - const invalidateRules = useInvalidateRules(); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - setIsSaved(false); - const saveRule = async () => { - if (rule != null) { - try { - setIsLoading(true); - await updateRule({ rule: transformOutput(rule), signal: abortCtrl.signal }); - invalidateRules(); - if (isSubscribed) { - setIsSaved(true); - } - } catch (error) { - if (isSubscribed) { - addError(error, { title: i18n.RULE_ADD_FAILURE }); - } - } - if (isSubscribed) { - setIsLoading(false); - } - } - }; - - saveRule(); - return () => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [rule, addError, invalidateRules]); - - return [{ isLoading, isSaved }, setRule]; -}; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts deleted file mode 100644 index d80835209010f..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts +++ /dev/null @@ -1,260 +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 { NavigateToAppOptions } from '@kbn/core/public'; -import { APP_UI_ID } from '../../../../../../common/constants'; -import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkAction } from '../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { HTTPError } from '../../../../../../common/detection_engine/types'; -import { SecurityPageName } from '../../../../../app/types'; -import { getEditRuleUrl } from '../../../../../common/components/link_to/redirect_to_detection_engine'; -import type { UseAppToasts } from '../../../../../common/hooks/use_app_toasts'; -import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../../../common/lib/telemetry'; -import { downloadBlob } from '../../../../../common/utils/download_blob'; -import type { - BulkActionSummary, - BulkActionResponse, -} from '../../../../containers/detection_engine/rules'; -import { performBulkAction } from '../../../../containers/detection_engine/rules'; -import * as i18n from '../translations'; -import { getExportedRulesCounts } from './helpers'; -import type { RulesTableActions } from './rules_table/rules_table_context'; - -export const goToRuleEditPage = ( - ruleId: string, - navigateToApp: (appId: string, options?: NavigateToAppOptions | undefined) => Promise -) => { - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.rules, - path: getEditRuleUrl(ruleId ?? ''), - }); -}; - -type OnActionSuccessCallback = ( - toasts: UseAppToasts, - action: BulkAction, - summary: BulkActionSummary -) => void; - -type OnActionErrorCallback = (toasts: UseAppToasts, action: BulkAction, error: HTTPError) => void; - -interface BaseRulesBulkActionArgs { - visibleRuleIds?: string[]; - toasts: UseAppToasts; - search: { query: string } | { ids: string[] }; - payload?: { edit?: BulkActionEditPayload[] }; - onError?: OnActionErrorCallback; - onFinish?: () => void; - onSuccess?: OnActionSuccessCallback; - setLoadingRules?: RulesTableActions['setLoadingRules']; -} - -interface RulesBulkActionArgs extends BaseRulesBulkActionArgs { - action: Exclude; -} -interface ExportRulesBulkActionArgs extends BaseRulesBulkActionArgs { - action: BulkAction.export; -} - -// export bulk actions API returns blob, the rest of actions returns BulkActionResponse object -// hence method overloading to make type safe calls -export async function executeRulesBulkAction(args: ExportRulesBulkActionArgs): Promise; -export async function executeRulesBulkAction( - args: RulesBulkActionArgs -): Promise; -export async function executeRulesBulkAction({ - visibleRuleIds = [], - action, - setLoadingRules, - toasts, - search, - payload, - onSuccess = defaultSuccessHandler, - onError = defaultErrorHandler, - onFinish, -}: RulesBulkActionArgs | ExportRulesBulkActionArgs) { - let response: Blob | BulkActionResponse | null = null; - try { - setLoadingRules?.({ ids: visibleRuleIds, action }); - - if (action === BulkAction.export) { - // on successToast for export handles separately outside of action execution method - response = await performBulkAction({ ...search, action }); - } else { - response = await performBulkAction({ ...search, action, edit: payload?.edit }); - sendTelemetry(action, response); - onSuccess(toasts, action, response.attributes.summary); - } - } catch (error) { - onError(toasts, action, error); - } finally { - setLoadingRules?.({ ids: [], action: null }); - onFinish?.(); - } - return response; -} - -/** - * downloads exported rules, received from export action - * @param params.response - Blob results with exported rules - * @param params.toasts - {@link UseAppToasts} toasts service - * @param params.onSuccess - {@link OnActionSuccessCallback} optional toast to display when action successful - * @param params.onError - {@link OnActionErrorCallback} optional toast to display when action failed - */ -export async function downloadExportedRules({ - response, - toasts, - onSuccess = defaultSuccessHandler, - onError = defaultErrorHandler, -}: { - response: Blob; - toasts: UseAppToasts; - onSuccess?: OnActionSuccessCallback; - onError?: OnActionErrorCallback; -}) { - try { - downloadBlob(response, `${i18n.EXPORT_FILENAME}.ndjson`); - onSuccess(toasts, BulkAction.export, await getExportedRulesCounts(response)); - } catch (error) { - onError(toasts, BulkAction.export, error); - } -} - -/** - * executes bulk export action and downloads exported rules - * @param params - {@link ExportRulesBulkActionArgs} - */ -export async function bulkExportRules(params: ExportRulesBulkActionArgs) { - const response = await executeRulesBulkAction(params); - - // if response null, likely network error happened and export rules haven't been received - if (response) { - await downloadExportedRules({ response, toasts: params.toasts, onSuccess: params.onSuccess }); - } -} - -function defaultErrorHandler(toasts: UseAppToasts, action: BulkAction, error: HTTPError) { - // if response doesn't have number of failed rules, it means the whole bulk action failed - // and general error toast will be shown. Otherwise - error toast for partial failure - const summary = (error?.body as BulkActionResponse)?.attributes?.summary; - error.stack = JSON.stringify(error.body, null, 2); - - let title: string; - let toastMessage: string | undefined; - - switch (action) { - case BulkAction.export: - title = i18n.RULES_BULK_EXPORT_FAILURE; - if (summary) { - toastMessage = i18n.RULES_BULK_EXPORT_FAILURE_DESCRIPTION(summary.failed); - } - break; - case BulkAction.duplicate: - title = i18n.RULES_BULK_DUPLICATE_FAILURE; - if (summary) { - toastMessage = i18n.RULES_BULK_DUPLICATE_FAILURE_DESCRIPTION(summary.failed); - } - break; - case BulkAction.delete: - title = i18n.RULES_BULK_DELETE_FAILURE; - if (summary) { - toastMessage = i18n.RULES_BULK_DELETE_FAILURE_DESCRIPTION(summary.failed); - } - break; - case BulkAction.enable: - title = i18n.RULES_BULK_ENABLE_FAILURE; - if (summary) { - toastMessage = i18n.RULES_BULK_ENABLE_FAILURE_DESCRIPTION(summary.failed); - } - break; - case BulkAction.disable: - title = i18n.RULES_BULK_DISABLE_FAILURE; - if (summary) { - toastMessage = i18n.RULES_BULK_DISABLE_FAILURE_DESCRIPTION(summary.failed); - } - break; - case BulkAction.edit: - title = i18n.RULES_BULK_EDIT_FAILURE; - if (summary) { - toastMessage = i18n.RULES_BULK_EDIT_FAILURE_DESCRIPTION(summary.failed); - } - break; - } - - toasts.addError(error, { title, toastMessage }); -} - -const getExportSuccessToastMessage = (succeeded: number, total: number) => { - const message = [i18n.RULES_BULK_EXPORT_SUCCESS_DESCRIPTION(succeeded, total)]; - - // if not all rules are successfully exported it means there included prebuilt rules - // display message to users that prebuilt rules were excluded - if (total > succeeded) { - message.push(i18n.RULES_BULK_EXPORT_PREBUILT_RULES_EXCLUDED_DESCRIPTION); - } - - return message.join(' '); -}; - -async function defaultSuccessHandler( - toasts: UseAppToasts, - action: BulkAction, - summary: BulkActionSummary -) { - let title: string; - let text: string | undefined; - - switch (action) { - case BulkAction.export: - title = i18n.RULES_BULK_EXPORT_SUCCESS; - text = getExportSuccessToastMessage(summary.succeeded, summary.total); - break; - case BulkAction.duplicate: - title = i18n.RULES_BULK_DUPLICATE_SUCCESS; - text = i18n.RULES_BULK_DUPLICATE_SUCCESS_DESCRIPTION(summary.succeeded); - break; - case BulkAction.delete: - title = i18n.RULES_BULK_DELETE_SUCCESS; - text = i18n.RULES_BULK_DELETE_SUCCESS_DESCRIPTION(summary.succeeded); - break; - case BulkAction.enable: - title = i18n.RULES_BULK_ENABLE_SUCCESS; - text = i18n.RULES_BULK_ENABLE_SUCCESS_DESCRIPTION(summary.succeeded); - break; - case BulkAction.disable: - title = i18n.RULES_BULK_DISABLE_SUCCESS; - text = i18n.RULES_BULK_DISABLE_SUCCESS_DESCRIPTION(summary.succeeded); - break; - case BulkAction.edit: - title = i18n.RULES_BULK_EDIT_SUCCESS; - text = i18n.RULES_BULK_EDIT_SUCCESS_DESCRIPTION(summary.succeeded); - break; - } - - toasts.addSuccess({ title, text }); -} - -function sendTelemetry(action: BulkAction, response: BulkActionResponse) { - if (action === BulkAction.disable || action === BulkAction.enable) { - if (response.attributes.results.updated.some((rule) => rule.immutable)) { - track( - METRIC_TYPE.COUNT, - action === BulkAction.enable - ? TELEMETRY_EVENT.SIEM_RULE_ENABLED - : TELEMETRY_EVENT.SIEM_RULE_DISABLED - ); - } - if (response.attributes.results.updated.some((rule) => !rule.immutable)) { - track( - METRIC_TYPE.COUNT, - action === BulkAction.disable - ? TELEMETRY_EVENT.CUSTOM_RULE_ENABLED - : TELEMETRY_EVENT.CUSTOM_RULE_DISABLED - ); - } - } -} diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.test.tsx deleted file mode 100644 index 826cdca510a62..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.test.tsx +++ /dev/null @@ -1,102 +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 { waitFor } from '@testing-library/react'; -import { mount, shallow } from 'enzyme'; -import React from 'react'; -import { useKibana } from '../../../../../common/lib/kibana'; -import { TestProviders } from '../../../../../common/mock'; -import '../../../../../common/mock/formatted_relative'; -import '../../../../../common/mock/match_media'; -import { AllRules } from '.'; - -jest.mock('../../../../../common/components/link_to'); -jest.mock('../../../../../common/lib/kibana'); -jest.mock('../../../../containers/detection_engine/rules'); -jest.mock('./rules_table/rules_table_context'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('AllRules', () => { - beforeEach(() => { - useKibanaMock().services.application.capabilities = { - navLinks: {}, - management: {}, - catalogue: {}, - actions: { show: true }, - }; - }); - - afterEach(() => { - jest.clearAllTimers(); - jest.clearAllMocks(); - }); - - it('renders correctly', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('RulesTables')).toHaveLength(1); - }); - - describe('tabs', () => { - it('renders all rules tab by default', async () => { - const wrapper = mount( - - - - ); - - await waitFor(() => { - expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeFalsy(); - expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeTruthy(); - }); - }); - }); - - it('renders monitoring tab when monitoring tab clicked', async () => { - const wrapper = mount( - - - - ); - - await waitFor(() => { - const monitoringTab = wrapper.find('[data-test-subj="allRulesTableTab-monitoring"] button'); - monitoringTab.simulate('click'); - - wrapper.update(); - expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeTruthy(); - expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeFalsy(); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx deleted file mode 100644 index bcdcc4dac263e..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx +++ /dev/null @@ -1,62 +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 { EuiSpacer } from '@elastic/eui'; -import React, { useState } from 'react'; -import { RulesTables } from './rules_tables'; -import { AllRulesTabs, RulesTableToolbar } from './rules_table_toolbar'; - -interface AllRulesProps { - createPrePackagedRules: () => void; - hasPermissions: boolean; - loadingCreatePrePackagedRules: boolean; - rulesCustomInstalled?: number; - rulesInstalled?: number; - rulesNotInstalled?: number; - rulesNotUpdated?: number; -} - -/** - * Table Component for displaying all Rules for a given cluster. Provides the ability to filter - * by name, sort by enabled, and perform the following actions: - * * Enable/Disable - * * Duplicate - * * Delete - * * Import/Export - */ -export const AllRules = React.memo( - ({ - createPrePackagedRules, - hasPermissions, - loadingCreatePrePackagedRules, - rulesCustomInstalled, - rulesInstalled, - rulesNotInstalled, - rulesNotUpdated, - }) => { - const [activeTab, setActiveTab] = useState(AllRulesTabs.rules); - - return ( - <> - - - - - ); - } -); - -AllRules.displayName = 'AllRules'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.test.tsx deleted file mode 100644 index 30c8ba7008367..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.test.tsx +++ /dev/null @@ -1,83 +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 uuid from 'uuid'; -import { useAppToastsMock } from '../../../../../common/hooks/use_app_toasts.mock'; -import '../../../../../common/mock/match_media'; -import { goToRuleEditPage, executeRulesBulkAction } from './actions'; -import { getRulesTableActions } from './rules_table_actions'; -import { mockRule } from './__mocks__/mock'; - -jest.mock('./actions'); - -const executeRulesBulkActionMock = executeRulesBulkAction as jest.Mock; -const goToRuleEditPageMock = goToRuleEditPage as jest.Mock; - -describe('getRulesTableActions', () => { - const rule = mockRule(uuid.v4()); - const toasts = useAppToastsMock.create(); - const invalidateRules = jest.fn(); - const invalidatePrePackagedRulesStatus = jest.fn(); - const setLoadingRules = jest.fn(); - const startTransaction = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('duplicate rule onClick should call rule edit after the rule is duplicated', async () => { - const ruleDuplicate = mockRule('newRule'); - const navigateToApp = jest.fn(); - executeRulesBulkActionMock.mockImplementation(() => - Promise.resolve({ attributes: { results: { created: [ruleDuplicate] } } }) - ); - - const duplicateRulesActionObject = getRulesTableActions({ - toasts, - navigateToApp, - invalidateRules, - invalidatePrePackagedRulesStatus, - actionsPrivileges: true, - setLoadingRules, - startTransaction, - })[1]; - const duplicateRulesActionHandler = duplicateRulesActionObject.onClick; - expect(duplicateRulesActionHandler).toBeDefined(); - - await duplicateRulesActionHandler!(rule); - expect(executeRulesBulkAction).toHaveBeenCalledWith( - expect.objectContaining({ action: 'duplicate' }) - ); - expect(goToRuleEditPageMock).toHaveBeenCalledWith(ruleDuplicate.id, navigateToApp); - }); - - test('delete rule onClick should call refetch after the rule is deleted', async () => { - const navigateToApp = jest.fn(); - - const deleteRulesActionObject = getRulesTableActions({ - toasts, - navigateToApp, - invalidateRules, - invalidatePrePackagedRulesStatus, - actionsPrivileges: true, - setLoadingRules, - startTransaction, - })[3]; - const deleteRuleActionHandler = deleteRulesActionObject.onClick; - expect(deleteRuleActionHandler).toBeDefined(); - - await deleteRuleActionHandler!(rule); - expect(executeRulesBulkAction).toHaveBeenCalledTimes(1); - expect(executeRulesBulkAction).toHaveBeenCalledWith( - expect.objectContaining({ action: 'delete' }) - ); - expect(invalidateRules).toHaveBeenCalledTimes(1); - expect(executeRulesBulkActionMock.mock.invocationCallOrder[0]).toBeLessThan( - invalidateRules.mock.invocationCallOrder[0] - ); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx deleted file mode 100644 index cfd83c3ab408f..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx +++ /dev/null @@ -1,123 +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 { DefaultItemAction } from '@elastic/eui'; -import { EuiToolTip } from '@elastic/eui'; -import React from 'react'; -import type { NavigateToAppOptions } from '@kbn/core/public'; -import { BulkAction } from '../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { UseAppToasts } from '../../../../../common/hooks/use_app_toasts'; -import { canEditRuleWithActions } from '../../../../../common/utils/privileges'; -import type { Rule } from '../../../../containers/detection_engine/rules'; -import * as i18n from '../translations'; -import { executeRulesBulkAction, goToRuleEditPage, bulkExportRules } from './actions'; -import type { RulesTableActions } from './rules_table/rules_table_context'; -import type { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; -import { SINGLE_RULE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; - -type NavigateToApp = (appId: string, options?: NavigateToAppOptions | undefined) => Promise; - -export const getRulesTableActions = ({ - toasts, - navigateToApp, - invalidateRules, - invalidatePrePackagedRulesStatus, - actionsPrivileges, - setLoadingRules, - startTransaction, -}: { - toasts: UseAppToasts; - navigateToApp: NavigateToApp; - invalidateRules: () => void; - invalidatePrePackagedRulesStatus: () => void; - actionsPrivileges: boolean; - setLoadingRules: RulesTableActions['setLoadingRules']; - startTransaction: ReturnType['startTransaction']; -}): Array> => [ - { - type: 'icon', - 'data-test-subj': 'editRuleAction', - description: i18n.EDIT_RULE_SETTINGS, - name: !actionsPrivileges ? ( - - <>{i18n.EDIT_RULE_SETTINGS} - - ) : ( - i18n.EDIT_RULE_SETTINGS - ), - icon: 'controlsHorizontal', - onClick: (rule: Rule) => goToRuleEditPage(rule.id, navigateToApp), - enabled: (rule: Rule) => canEditRuleWithActions(rule, actionsPrivileges), - }, - { - type: 'icon', - 'data-test-subj': 'duplicateRuleAction', - description: i18n.DUPLICATE_RULE, - icon: 'copy', - name: !actionsPrivileges ? ( - - <>{i18n.DUPLICATE_RULE} - - ) : ( - i18n.DUPLICATE_RULE - ), - enabled: (rule: Rule) => canEditRuleWithActions(rule, actionsPrivileges), - onClick: async (rule: Rule) => { - startTransaction({ name: SINGLE_RULE_ACTIONS.DUPLICATE }); - const result = await executeRulesBulkAction({ - action: BulkAction.duplicate, - setLoadingRules, - visibleRuleIds: [rule.id], - toasts, - search: { ids: [rule.id] }, - }); - invalidateRules(); - invalidatePrePackagedRulesStatus(); - const createdRules = result?.attributes.results.created; - if (createdRules?.length) { - goToRuleEditPage(createdRules[0].id, navigateToApp); - } - }, - }, - { - type: 'icon', - 'data-test-subj': 'exportRuleAction', - description: i18n.EXPORT_RULE, - icon: 'exportAction', - name: i18n.EXPORT_RULE, - onClick: async (rule: Rule) => { - startTransaction({ name: SINGLE_RULE_ACTIONS.EXPORT }); - await bulkExportRules({ - action: BulkAction.export, - setLoadingRules, - visibleRuleIds: [rule.id], - toasts, - search: { ids: [rule.id] }, - }); - }, - enabled: (rule: Rule) => !rule.immutable, - }, - { - type: 'icon', - 'data-test-subj': 'deleteRuleAction', - description: i18n.DELETE_RULE, - icon: 'trash', - name: i18n.DELETE_RULE, - onClick: async (rule: Rule) => { - startTransaction({ name: SINGLE_RULE_ACTIONS.DELETE }); - await executeRulesBulkAction({ - action: BulkAction.delete, - setLoadingRules, - visibleRuleIds: [rule.id], - toasts, - search: { ids: [rule.id] }, - }); - invalidateRules(); - invalidatePrePackagedRulesStatus(); - }, - }, -]; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.test.tsx deleted file mode 100644 index 2ad9de45346c4..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.test.tsx +++ /dev/null @@ -1,41 +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 React from 'react'; -import { mount } from 'enzyme'; - -import { RulesTableFilters } from './rules_table_filters'; -import { TestProviders } from '../../../../../../common/mock'; - -jest.mock('../rules_table/rules_table_context'); - -describe('RulesTableFilters', () => { - it('renders no numbers next to rule type button filter if none exist', async () => { - const wrapper = mount(, { wrappingComponent: TestProviders }); - - expect(wrapper.find('[data-test-subj="showElasticRulesFilterButton"]').at(0).text()).toEqual( - 'Elastic rules' - ); - expect(wrapper.find('[data-test-subj="showCustomRulesFilterButton"]').at(0).text()).toEqual( - 'Custom rules' - ); - }); - - it('renders number of custom and prepackaged rules', async () => { - const wrapper = mount( - , - { wrappingComponent: TestProviders } - ); - - expect(wrapper.find('[data-test-subj="showElasticRulesFilterButton"]').at(0).text()).toEqual( - 'Elastic rules (9)' - ); - expect(wrapper.find('[data-test-subj="showCustomRulesFilterButton"]').at(0).text()).toEqual( - 'Custom rules (10)' - ); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx deleted file mode 100644 index 9165bdea5c533..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx +++ /dev/null @@ -1,379 +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 { - EuiBasicTable, - EuiConfirmModal, - EuiEmptyPrompt, - EuiLoadingContent, - EuiProgress, -} from '@elastic/eui'; -import React, { useCallback, useEffect, useMemo, useRef } from 'react'; -import { AllRulesTabs } from './rules_table_toolbar'; -import { RULES_TABLE_PAGE_SIZE_OPTIONS } from '../../../../../../common/constants'; -import { Loader } from '../../../../../common/components/loader'; -import { useBoolState } from '../../../../../common/hooks/use_bool_state'; -import { useValueChanged } from '../../../../../common/hooks/use_value_changed'; -import { RULES_TABLE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; -import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; -import { PrePackagedRulesPrompt } from '../../../../components/rules/pre_packaged_rules/load_empty_prompt'; -import type { Rule, RulesSortingFields } from '../../../../containers/detection_engine/rules'; -import { useTags } from '../../../../containers/detection_engine/rules/use_tags'; -import { getPrePackagedRuleStatus } from '../helpers'; -import * as i18n from '../translations'; -import type { EuiBasicTableOnChange } from '../types'; -import { useMonitoringColumns, useRulesColumns } from './use_columns'; -import { showRulesTable } from './helpers'; -import { useRulesTableContext } from './rules_table/rules_table_context'; -import { useAsyncConfirmation } from './rules_table/use_async_confirmation'; -import { RulesTableFilters } from './rules_table_filters/rules_table_filters'; -import { RulesTableUtilityBar } from './rules_table_utility_bar'; -import { useBulkActionsDryRun } from './bulk_actions/use_bulk_actions_dry_run'; -import { useBulkActionsConfirmation } from './bulk_actions/use_bulk_actions_confirmation'; -import { useBulkEditFormFlyout } from './bulk_actions/use_bulk_edit_form_flyout'; -import { BulkActionDryRunConfirmation } from './bulk_actions/bulk_action_dry_run_confirmation'; -import { BulkEditFlyout } from './bulk_actions/bulk_edit_flyout'; -import { useBulkActions } from './bulk_actions/use_bulk_actions'; - -const INITIAL_SORT_FIELD = 'enabled'; - -interface RulesTableProps { - createPrePackagedRules: () => void; - hasPermissions: boolean; - loadingCreatePrePackagedRules: boolean; - rulesCustomInstalled?: number; - rulesInstalled?: number; - rulesNotInstalled?: number; - rulesNotUpdated?: number; - selectedTab: AllRulesTabs; -} - -const NO_ITEMS_MESSAGE = ( - {i18n.NO_RULES}} titleSize="xs" body={i18n.NO_RULES_BODY} /> -); - -/** - * Table Component for displaying all Rules for a given cluster. Provides the ability to filter - * by name, sort by enabled, and perform the following actions: - * * Enable/Disable - * * Duplicate - * * Delete - * * Import/Export - */ -export const RulesTables = React.memo( - ({ - createPrePackagedRules, - hasPermissions, - loadingCreatePrePackagedRules, - rulesCustomInstalled, - rulesInstalled, - rulesNotInstalled, - rulesNotUpdated, - selectedTab, - }) => { - const { startTransaction } = useStartTransaction(); - const tableRef = useRef(null); - const rulesTableContext = useRulesTableContext(); - - const { - state: { - rules, - filterOptions, - isActionInProgress, - isAllSelected, - isFetched, - isLoading, - isRefetching, - isRefreshOn, - loadingRuleIds, - loadingRulesAction, - pagination, - selectedRuleIds, - sortingOptions, - }, - actions: { - reFetchRules, - setIsAllSelected, - setIsRefreshOn, - setPage, - setPerPage, - setSelectedRuleIds, - setSortingOptions, - }, - } = rulesTableContext; - - const prePackagedRuleStatus = getPrePackagedRuleStatus( - rulesInstalled, - rulesNotInstalled, - rulesNotUpdated - ); - - const [, allTags, reFetchTags] = useTags(); - - useEffect(() => { - reFetchTags(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [rulesCustomInstalled, rulesInstalled]); - - const [isDeleteConfirmationVisible, showDeleteConfirmation, hideDeleteConfirmation] = - useBoolState(); - - const [confirmDeletion, handleDeletionConfirm, handleDeletionCancel] = useAsyncConfirmation({ - onInit: showDeleteConfirmation, - onFinish: hideDeleteConfirmation, - }); - - const { - bulkActionsDryRunResult, - bulkAction, - isBulkActionConfirmationVisible, - showBulkActionConfirmation, - cancelBulkActionConfirmation, - approveBulkActionConfirmation, - } = useBulkActionsConfirmation(); - - const { - bulkEditActionType, - isBulkEditFlyoutVisible, - handleBulkEditFormConfirm, - handleBulkEditFormCancel, - completeBulkEditForm, - } = useBulkEditFormFlyout(); - - const selectedItemsCount = isAllSelected ? pagination.total : selectedRuleIds.length; - - const { isBulkActionsDryRunLoading, executeBulkActionsDryRun } = useBulkActionsDryRun(); - - const getBulkItemsPopoverContent = useBulkActions({ - filterOptions, - confirmDeletion, - showBulkActionConfirmation, - completeBulkEditForm, - reFetchTags, - executeBulkActionsDryRun, - }); - - const paginationMemo = useMemo( - () => ({ - pageIndex: pagination.page - 1, - pageSize: pagination.perPage, - totalItemCount: pagination.total, - pageSizeOptions: RULES_TABLE_PAGE_SIZE_OPTIONS, - }), - [pagination] - ); - - const tableOnChangeCallback = useCallback( - ({ page, sort }: EuiBasicTableOnChange) => { - setSortingOptions({ - field: (sort?.field as RulesSortingFields) ?? INITIAL_SORT_FIELD, // Narrowing EuiBasicTable sorting types - order: sort?.direction ?? 'desc', - }); - setPage(page.index + 1); - setPerPage(page.size); - }, - [setPage, setPerPage, setSortingOptions] - ); - - const rulesColumns = useRulesColumns({ hasPermissions }); - const monitoringColumns = useMonitoringColumns({ hasPermissions }); - - const handleCreatePrePackagedRules = useCallback(async () => { - if (createPrePackagedRules != null) { - startTransaction({ name: RULES_TABLE_ACTIONS.LOAD_PREBUILT }); - await createPrePackagedRules(); - await reFetchRules(); - } - }, [createPrePackagedRules, reFetchRules, startTransaction]); - - const handleRefreshRules = useCallback(() => { - startTransaction({ name: RULES_TABLE_ACTIONS.REFRESH }); - reFetchRules(); - }, [reFetchRules, startTransaction]); - - const isSelectAllCalled = useRef(false); - - // Synchronize selectedRuleIds with EuiBasicTable's selected rows - useValueChanged((ruleIds) => { - if (tableRef.current != null) { - tableRef.current.setSelection(rules.filter((rule) => ruleIds.includes(rule.id))); - } - }, selectedRuleIds); - - const euiBasicTableSelectionProps = useMemo( - () => ({ - selectable: (item: Rule) => !loadingRuleIds.includes(item.id), - onSelectionChange: (selected: Rule[]) => { - /** - * EuiBasicTable doesn't provide declarative API to control selected rows. - * This limitation requires us to synchronize selection state manually using setSelection(). - * But it creates a chain reaction when the user clicks Select All: - * selectAll() -> setSelection() -> onSelectionChange() -> setSelection(). - * To break the chain we should check whether the onSelectionChange was triggered - * by the Select All action or not. - * - */ - if (isSelectAllCalled.current) { - isSelectAllCalled.current = false; - // Handle special case of unselecting all rules via checkbox - // after all rules were selected via Bulk select. - if (selected.length === 0) { - setIsAllSelected(false); - setSelectedRuleIds([]); - } - } else { - setSelectedRuleIds(selected.map(({ id }) => id)); - setIsAllSelected(false); - } - }, - }), - [loadingRuleIds, setIsAllSelected, setSelectedRuleIds] - ); - - const toggleSelectAll = useCallback(() => { - isSelectAllCalled.current = true; - setIsAllSelected(!isAllSelected); - setSelectedRuleIds(!isAllSelected ? rules.map(({ id }) => id) : []); - }, [rules, isAllSelected, setIsAllSelected, setSelectedRuleIds]); - - const handleAutoRefreshSwitch = useCallback( - (refreshOn: boolean) => { - if (refreshOn) { - reFetchRules(); - } - setIsRefreshOn(refreshOn); - }, - [setIsRefreshOn, reFetchRules] - ); - - const shouldShowRulesTable = useMemo( - (): boolean => showRulesTable({ rulesCustomInstalled, rulesInstalled }) && !isLoading, - [isLoading, rulesCustomInstalled, rulesInstalled] - ); - - const shouldShowPrepackagedRulesPrompt = useMemo( - (): boolean => - rulesCustomInstalled != null && - rulesCustomInstalled === 0 && - prePackagedRuleStatus === 'ruleNotInstalled' && - !isLoading, - [isLoading, prePackagedRuleStatus, rulesCustomInstalled] - ); - - const tableProps = - selectedTab === AllRulesTabs.rules - ? { - 'data-test-subj': 'rules-table', - columns: rulesColumns, - } - : { 'data-test-subj': 'monitoring-table', columns: monitoringColumns }; - - const shouldShowLinearProgress = isFetched && isRefetching; - const shouldShowLoadingOverlay = (!isFetched && isRefetching) || isActionInProgress; - - return ( - <> - {shouldShowLinearProgress && ( - - )} - {shouldShowLoadingOverlay && ( - - )} - {shouldShowRulesTable && ( - - )} - {shouldShowPrepackagedRulesPrompt && ( - - )} - {isLoading && ( - - )} - {isDeleteConfirmationVisible && ( - -

    {i18n.DELETE_CONFIRMATION_BODY}

    -
    - )} - {isBulkActionConfirmationVisible && bulkAction && ( - - )} - {isBulkEditFlyoutVisible && bulkEditActionType !== undefined && ( - - )} - {shouldShowRulesTable && ( - <> - - - - )} - - ); - } -); - -RulesTables.displayName = 'RulesTables'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link.tsx new file mode 100644 index 0000000000000..6ef7ebb0cae4c --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link.tsx @@ -0,0 +1,56 @@ +/* + * 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 React, { useCallback } from 'react'; +import { EuiToolTip } from '@elastic/eui'; +import { useKibana } from '../../../../../../common/lib/kibana'; +import { SecuritySolutionLinkButton } from '../../../../../../common/components/links'; +import { APP_UI_ID } from '../../../../../../../common/constants'; +import { SecurityPageName } from '../../../../../../app/types'; +import { getEditRuleUrl } from '../../../../../../common/components/link_to/redirect_to_detection_engine'; +import * as ruleI18n from '../../translations'; + +interface EditRuleSettingButtonLinkProps { + ruleId: string; + disabled: boolean; + disabledReason?: string; +} + +export function EditRuleSettingButtonLink({ + ruleId, + disabled = false, + disabledReason, +}: EditRuleSettingButtonLinkProps): JSX.Element { + const { + application: { navigateToApp }, + } = useKibana().services; + const goToEditRule = useCallback( + (ev) => { + ev.preventDefault(); + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.rules, + path: getEditRuleUrl(ruleId), + }); + }, + [navigateToApp, ruleId] + ); + + return ( + + + {ruleI18n.EDIT_RULE_SETTINGS} + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.test.tsx deleted file mode 100644 index d283879045165..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.test.tsx +++ /dev/null @@ -1,54 +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 React from 'react'; -import { shallow } from 'enzyme'; - -import '../../../../../common/mock/match_media'; -import { TestProviders } from '../../../../../common/mock'; -import { EditRulePage } from '.'; -import { useUserData } from '../../../../components/user_info'; -import { useParams } from 'react-router-dom'; -import { useAppToastsMock } from '../../../../../common/hooks/use_app_toasts.mock'; -import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; - -jest.mock('../../../../../common/lib/kibana'); -jest.mock('../../../../containers/detection_engine/lists/use_lists_config'); -jest.mock('../../../../containers/detection_engine/rules/use_find_rules_query'); -jest.mock('../../../../../common/components/link_to'); -jest.mock('../../../../components/user_info'); -jest.mock('react-router-dom', () => { - const originalModule = jest.requireActual('react-router-dom'); - - return { - ...originalModule, - useHistory: jest.fn(), - useParams: jest.fn(), - }; -}); -jest.mock('../../../../../common/hooks/use_app_toasts'); -jest.mock('../use_get_saved_query', () => ({ - __esModule: true, - useGetSavedQuery: jest.fn().mockReturnValue({}), -})); - -describe('EditRulePage', () => { - let appToastsMock: jest.Mocked>; - - beforeEach(() => { - appToastsMock = useAppToastsMock.create(); - (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); - }); - - it('renders correctly', () => { - (useUserData as jest.Mock).mockReturnValue([{}]); - (useParams as jest.Mock).mockReturnValue({}); - const wrapper = shallow(, { wrappingComponent: TestProviders }); - - expect(wrapper.find('[title="Edit rule settings"]')).toHaveLength(1); - }); -}); 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 4392be5cdc409..82934d0cccac2 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 @@ -15,16 +15,18 @@ import { getActionsStepsData, getHumanizedDuration, getModifiedAboutDetailsData, - getPrePackagedRuleStatus, - getPrePackagedTimelineStatus, + getPrePackagedRuleInstallationStatus, + getPrePackagedTimelineInstallationStatus, determineDetailsValue, - userHasPermissions, fillEmptySeverityMappings, } from './helpers'; -import { mockRuleWithEverything, mockRule } from './all/__mocks__/mock'; +import { + mockRuleWithEverything, + mockRule, +} from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import { FilterStateStore } from '@kbn/es-query'; -import type { Rule } from '../../../containers/detection_engine/rules'; +import type { Rule } from '../../../../detection_engine/rule_management/logic'; import type { AboutStepRule, AboutStepRuleDetails, @@ -448,35 +450,12 @@ describe('rule helpers', () => { }); }); - describe('userHasPermissions', () => { - test("returns true when user's CRUD operations are null", () => { - const result: boolean = userHasPermissions(null); - const userHasPermissionsExpectedResult = true; - - expect(result).toEqual(userHasPermissionsExpectedResult); - }); - - test('returns false when user cannot CRUD', () => { - const result: boolean = userHasPermissions(false); - const userHasPermissionsExpectedResult = false; - - expect(result).toEqual(userHasPermissionsExpectedResult); - }); - - test('returns true when user can CRUD', () => { - const result: boolean = userHasPermissions(true); - const userHasPermissionsExpectedResult = true; - - expect(result).toEqual(userHasPermissionsExpectedResult); - }); - }); - describe('getPrePackagedRuleStatus', () => { test('ruleNotInstalled', () => { const rulesInstalled = 0; const rulesNotInstalled = 1; const rulesNotUpdated = 0; - const result: string = getPrePackagedRuleStatus( + const result: string = getPrePackagedRuleInstallationStatus( rulesInstalled, rulesNotInstalled, rulesNotUpdated @@ -489,7 +468,7 @@ describe('rule helpers', () => { const rulesInstalled = 1; const rulesNotInstalled = 0; const rulesNotUpdated = 0; - const result: string = getPrePackagedRuleStatus( + const result: string = getPrePackagedRuleInstallationStatus( rulesInstalled, rulesNotInstalled, rulesNotUpdated @@ -502,7 +481,7 @@ describe('rule helpers', () => { const rulesInstalled = 1; const rulesNotInstalled = 1; const rulesNotUpdated = 0; - const result: string = getPrePackagedRuleStatus( + const result: string = getPrePackagedRuleInstallationStatus( rulesInstalled, rulesNotInstalled, rulesNotUpdated @@ -515,7 +494,7 @@ describe('rule helpers', () => { const rulesInstalled = 1; const rulesNotInstalled = 0; const rulesNotUpdated = 1; - const result: string = getPrePackagedRuleStatus( + const result: string = getPrePackagedRuleInstallationStatus( rulesInstalled, rulesNotInstalled, rulesNotUpdated @@ -528,7 +507,7 @@ describe('rule helpers', () => { const rulesInstalled = undefined; const rulesNotInstalled = undefined; const rulesNotUpdated = undefined; - const result: string = getPrePackagedRuleStatus( + const result: string = getPrePackagedRuleInstallationStatus( rulesInstalled, rulesNotInstalled, rulesNotUpdated @@ -543,7 +522,7 @@ describe('rule helpers', () => { const timelinesInstalled = 0; const timelinesNotInstalled = 1; const timelinesNotUpdated = 0; - const result: string = getPrePackagedTimelineStatus( + const result: string = getPrePackagedTimelineInstallationStatus( timelinesInstalled, timelinesNotInstalled, timelinesNotUpdated @@ -556,7 +535,7 @@ describe('rule helpers', () => { const timelinesInstalled = 1; const timelinesNotInstalled = 0; const timelinesNotUpdated = 0; - const result: string = getPrePackagedTimelineStatus( + const result: string = getPrePackagedTimelineInstallationStatus( timelinesInstalled, timelinesNotInstalled, timelinesNotUpdated @@ -569,7 +548,7 @@ describe('rule helpers', () => { const timelinesInstalled = 1; const timelinesNotInstalled = 1; const timelinesNotUpdated = 0; - const result: string = getPrePackagedTimelineStatus( + const result: string = getPrePackagedTimelineInstallationStatus( timelinesInstalled, timelinesNotInstalled, timelinesNotUpdated @@ -582,7 +561,7 @@ describe('rule helpers', () => { const timelinesInstalled = 1; const timelinesNotInstalled = 0; const timelinesNotUpdated = 1; - const result: string = getPrePackagedTimelineStatus( + const result: string = getPrePackagedTimelineInstallationStatus( timelinesInstalled, timelinesNotInstalled, timelinesNotUpdated @@ -595,7 +574,7 @@ describe('rule helpers', () => { const timelinesInstalled = undefined; const timelinesNotInstalled = undefined; const timelinesNotUpdated = undefined; - const result: string = getPrePackagedTimelineStatus( + const result: string = getPrePackagedTimelineInstallationStatus( timelinesInstalled, timelinesNotInstalled, timelinesNotUpdated 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 36e00aaccc1ef..216e202052ee7 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 @@ -13,10 +13,10 @@ import { useLocation } from 'react-router-dom'; import styled from 'styled-components'; import { EuiFlexItem } from '@elastic/eui'; import type { + Severity, + SeverityMapping, Threats, Type, - SeverityMapping, - Severity, } from '@kbn/securitysolution-io-ts-alerting-types'; import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import type { Filter } from '@kbn/es-query'; @@ -29,7 +29,7 @@ import { transformRuleToAlertAction, transformRuleToAlertResponseAction, } from '../../../../../common/detection_engine/transform_actions'; -import type { Rule } from '../../../containers/detection_engine/rules'; +import type { Rule } from '../../../../detection_engine/rule_management/logic'; import type { AboutStepRule, AboutStepRuleDetails, @@ -266,25 +266,25 @@ export const getModifiedAboutDetailsData = (rule: Rule): AboutStepRuleDetails => export const useQuery = () => new URLSearchParams(useLocation().search); -export type PrePackagedRuleStatus = +export type PrePackagedRuleInstallationStatus = | 'ruleInstalled' | 'ruleNotInstalled' | 'ruleNeedUpdate' | 'someRuleUninstall' | 'unknown'; -export type PrePackagedTimelineStatus = +export type PrePackagedTimelineInstallationStatus = | 'timelinesNotInstalled' | 'timelinesInstalled' | 'someTimelineUninstall' | 'timelineNeedUpdate' | 'unknown'; -export const getPrePackagedRuleStatus = ( +export const getPrePackagedRuleInstallationStatus = ( rulesInstalled?: number, rulesNotInstalled?: number, rulesNotUpdated?: number -): PrePackagedRuleStatus => { +): PrePackagedRuleInstallationStatus => { if ( rulesNotInstalled != null && rulesInstalled === 0 && @@ -319,11 +319,11 @@ export const getPrePackagedRuleStatus = ( } return 'unknown'; }; -export const getPrePackagedTimelineStatus = ( +export const getPrePackagedTimelineInstallationStatus = ( timelinesInstalled?: number, timelinesNotInstalled?: number, timelinesNotUpdated?: number -): PrePackagedTimelineStatus => { +): PrePackagedTimelineInstallationStatus => { if ( timelinesNotInstalled != null && timelinesInstalled === 0 && @@ -461,10 +461,6 @@ export const getActionMessageParams = memoizeOne((ruleType: Type | undefined): A export const getAllActionMessageParams = () => transformRuleKeysToActionVariables(getAllRuleParamsKeys()); -// typed as null not undefined as the initial state for this value is null. -export const userHasPermissions = (canUserCRUD: boolean | null): boolean => - canUserCRUD != null ? canUserCRUD : true; - export const MaxWidthEuiFlexItem = styled(EuiFlexItem)` max-width: 1000px; overflow: hidden; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx deleted file mode 100644 index 997f40e918cb2..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx +++ /dev/null @@ -1,274 +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 { EuiButton, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; -import React, { useCallback, useMemo, useState } from 'react'; -import { MlJobUpgradeModal } from '../../../components/modals/ml_job_upgrade_modal'; -import { affectedJobIds } from '../../../components/callouts/ml_job_compatibility_callout/affected_job_ids'; -import { useInstalledSecurityJobs } from '../../../../common/components/ml/hooks/use_installed_security_jobs'; - -import { usePrePackagedRules, importRules } from '../../../containers/detection_engine/rules'; -import { useListsConfig } from '../../../containers/detection_engine/lists/use_lists_config'; -import { getDetectionEngineUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; -import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; -import { SpyRoute } from '../../../../common/utils/route/spy_routes'; - -import { useUserData } from '../../../components/user_info'; -import { AllRules } from './all'; -import { ImportDataModal } from '../../../../common/components/import_data_modal'; -import { ValueListsFlyout } from '../../../components/value_lists_management_flyout'; -import { UpdatePrePackagedRulesCallOut } from '../../../components/rules/pre_packaged_rules/update_callout'; -import { - getPrePackagedRuleStatus, - getPrePackagedTimelineStatus, - redirectToDetections, - userHasPermissions, -} from './helpers'; -import * as i18n from './translations'; -import { SecurityPageName } from '../../../../app/types'; -import { SecuritySolutionLinkButton } from '../../../../common/components/links'; -import { NeedAdminForUpdateRulesCallOut } from '../../../components/callouts/need_admin_for_update_callout'; -import { MlJobCompatibilityCallout } from '../../../components/callouts/ml_job_compatibility_callout'; -import { MissingPrivilegesCallOut } from '../../../components/callouts/missing_privileges_callout'; -import { APP_UI_ID } from '../../../../../common/constants'; -import { useKibana } from '../../../../common/lib/kibana'; -import { HeaderPage } from '../../../../common/components/header_page'; -import { RulesTableContextProvider } from './all/rules_table/rules_table_context'; -import { useInvalidateRules } from '../../../containers/detection_engine/rules/use_find_rules_query'; -import { useBoolState } from '../../../../common/hooks/use_bool_state'; -import { RULES_TABLE_ACTIONS } from '../../../../common/lib/apm/user_actions'; -import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; - -const RulesPageComponent: React.FC = () => { - const [isImportModalVisible, showImportModal, hideImportModal] = useBoolState(); - const [isValueListFlyoutVisible, showValueListFlyout, hideValueListFlyout] = useBoolState(); - const { navigateToApp } = useKibana().services.application; - const { startTransaction } = useStartTransaction(); - const invalidateRules = useInvalidateRules(); - - const { loading: loadingJobs, jobs } = useInstalledSecurityJobs(); - const legacyJobsInstalled = jobs.filter((job) => affectedJobIds.includes(job.id)); - const [isUpgradeModalVisible, setIsUpgradeModalVisible] = useState(false); - - const [ - { - loading: userInfoLoading, - isSignalIndexExists, - isAuthenticated, - hasEncryptionKey, - canUserCRUD, - hasIndexWrite, - }, - ] = useUserData(); - const { - loading: listsConfigLoading, - canWriteIndex: canWriteListsIndex, - needsConfiguration: needsListsConfiguration, - } = useListsConfig(); - const loading = userInfoLoading || listsConfigLoading; - const { - createPrePackagedRules, - loadingCreatePrePackagedRules, - rulesCustomInstalled, - rulesInstalled, - rulesNotInstalled, - rulesNotUpdated, - timelinesInstalled, - timelinesNotInstalled, - timelinesNotUpdated, - getLoadPrebuiltRulesAndTemplatesButton, - getReloadPrebuiltRulesAndTemplatesButton, - } = usePrePackagedRules({ - canUserCRUD, - hasIndexWrite, - isSignalIndexExists, - isAuthenticated, - hasEncryptionKey, - }); - const prePackagedRuleStatus = getPrePackagedRuleStatus( - rulesInstalled, - rulesNotInstalled, - rulesNotUpdated - ); - - const prePackagedTimelineStatus = getPrePackagedTimelineStatus( - timelinesInstalled, - timelinesNotInstalled, - timelinesNotUpdated - ); - - const handleCreatePrePackagedRules = useCallback(async () => { - if (createPrePackagedRules != null) { - startTransaction({ name: RULES_TABLE_ACTIONS.LOAD_PREBUILT }); - await createPrePackagedRules(); - } - }, [createPrePackagedRules, startTransaction]); - - // Wrapper to add confirmation modal for users who may be running older ML Jobs that would - // be overridden by updating their rules. For details, see: https://github.com/elastic/kibana/issues/128121 - const mlJobUpgradeModalConfirm = useCallback(async () => { - setIsUpgradeModalVisible(false); - await handleCreatePrePackagedRules(); - }, [handleCreatePrePackagedRules, setIsUpgradeModalVisible]); - - const showMlJobUpgradeModal = useCallback(async () => { - if (legacyJobsInstalled.length > 0) { - setIsUpgradeModalVisible(true); - } else { - await handleCreatePrePackagedRules(); - } - }, [handleCreatePrePackagedRules, legacyJobsInstalled.length]); - - const loadPrebuiltRulesAndTemplatesButton = useMemo( - () => - getLoadPrebuiltRulesAndTemplatesButton({ - isDisabled: !userHasPermissions(canUserCRUD) || loading || loadingJobs, - onClick: showMlJobUpgradeModal, - }), - [ - canUserCRUD, - getLoadPrebuiltRulesAndTemplatesButton, - showMlJobUpgradeModal, - loading, - loadingJobs, - ] - ); - - const reloadPrebuiltRulesAndTemplatesButton = useMemo( - () => - getReloadPrebuiltRulesAndTemplatesButton({ - isDisabled: !userHasPermissions(canUserCRUD) || loading || loadingJobs, - onClick: showMlJobUpgradeModal, - }), - [ - canUserCRUD, - getReloadPrebuiltRulesAndTemplatesButton, - showMlJobUpgradeModal, - loading, - loadingJobs, - ] - ); - - if ( - redirectToDetections( - isSignalIndexExists, - isAuthenticated, - hasEncryptionKey, - needsListsConfiguration - ) - ) { - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.alerts, - path: getDetectionEngineUrl(), - }); - return null; - } - - return ( - <> - - - - {isUpgradeModalVisible && ( - setIsUpgradeModalVisible(false)} - onConfirm={mlJobUpgradeModalConfirm} - /> - )} - - - - - - - - {loadPrebuiltRulesAndTemplatesButton && ( - {loadPrebuiltRulesAndTemplatesButton} - )} - {reloadPrebuiltRulesAndTemplatesButton && ( - {reloadPrebuiltRulesAndTemplatesButton} - )} - - - - {i18n.IMPORT_VALUE_LISTS} - - - - - - {i18n.IMPORT_RULE} - - - - - {i18n.ADD_NEW_RULE} - - - - - {(prePackagedRuleStatus === 'ruleNeedUpdate' || - prePackagedTimelineStatus === 'timelineNeedUpdate') && ( - - )} - - - - - - - ); -}; - -export const RulesPage = React.memo(RulesPageComponent); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index 8b32821bc71f1..b9948ca90578b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -484,13 +484,20 @@ export const EDIT_RULE_SETTINGS = i18n.translate( } ); -export const EDIT_RULE_SETTINGS_TOOLTIP = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip', +export const LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges', { defaultMessage: 'You do not have Kibana Actions privileges', } ); +export const LACK_OF_KIBANA_SECURITY_PRIVILEGES = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaSecurityPrivileges', + { + defaultMessage: 'You do not have Kibana Security privileges', + } +); + export const DUPLICATE_RULE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription', { 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 950191acad3d9..81ebc4b24cf9c 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 @@ -9,12 +9,12 @@ import type { List } from '@kbn/securitysolution-io-ts-list-types'; import type { RiskScoreMapping, + Severity, + SeverityMapping, ThreatIndex, ThreatMapping, Threats, Type, - SeverityMapping, - Severity, } from '@kbn/securitysolution-io-ts-alerting-types'; import type { DataViewBase, Filter } from '@kbn/es-query'; import type { RuleAction } from '@kbn/alerting-plugin/common'; @@ -25,16 +25,16 @@ import type { FieldValueQueryBar } from '../../../components/rules/query_bar'; import type { FieldValueTimeline } from '../../../components/rules/pick_timeline'; import type { FieldValueThreshold } from '../../../components/rules/threshold_input'; import type { - Author, BuildingBlockType, - License, RelatedIntegrationArray, RequiredFieldArray, + RuleAuthorArray, + RuleLicense, RuleNameOverride, - SortOrder, SetupGuide, TimestampOverride, -} from '../../../../../common/detection_engine/schemas/common'; +} from '../../../../../common/detection_engine/rule_schema'; +import type { SortOrder } from '../../../../../common/detection_engine/schemas/common'; import type { EqlOptionsSelected } from '../../../../../common/search_strategy'; import type { RuleResponseAction, @@ -215,12 +215,12 @@ export interface DefineStepRuleJson { } export interface AboutStepRuleJson { - author: Author; + author: RuleAuthorArray; building_block_type?: BuildingBlockType; exceptions_list?: List[]; name: string; description: string; - license: License; + license: RuleLicense; severity: string; severity_mapping: SeverityMapping; risk_score: number; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/use_get_saved_query.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/use_get_saved_query.ts index 5cd530754d8ce..fe113defb4eac 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/use_get_saved_query.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/use_get_saved_query.ts @@ -36,7 +36,10 @@ export const useGetSavedQuery = ( const query = useQuery( ['detectionEngine', 'rule', 'savedQuery', savedQueryId], async () => { - if (!savedQueryId) { + // load saved query only if rule type === 'saved_query', as other rule types still can have saved_id property that is not used + // Rule schema allows to save any rule with saved_id property, but it only used for saved_query rule type + // In future we might look in possibility to restrict rule schema (breaking change!) and remove saved_id from the rest of rules through migration + if (!savedQueryId || ruleType !== 'saved_query') { return null; } @@ -44,10 +47,6 @@ export const useGetSavedQuery = ( }, { onError: onError ?? defaultErrorHandler, - // load saved query only if rule type === 'saved_query', as other rule types still can have saved_id property that is not used - // Rule schema allows to save any rule with saved_id property, but it only used for saved_query rule type - // In future we might look in possibility to restrict rule schema (breaking change!) and remove saved_id from the rest of rules through migration - enabled: Boolean(savedQueryId) && ruleType === 'saved_query', retry: false, } ); 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 26f23bba9591d..5c04e749e481d 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 @@ -20,7 +20,10 @@ import { DEFAULT_THREAT_MATCH_QUERY, RULES_PATH } from '../../../../../common/co import type { AboutStepRule, DefineStepRule, RuleStepsOrder, ScheduleStepRule } from './types'; import { DataSourceType, RuleStep } from './types'; import type { GetSecuritySolutionUrl } from '../../../../common/components/link_to'; -import { RuleDetailTabs, RULE_DETAILS_TAB_NAME } from './details'; +import { + RuleDetailTabs, + RULE_DETAILS_TAB_NAME, +} from '../../../../detection_engine/rule_details_ui/pages/rule_details'; import { fillEmptySeverityMappings } from './helpers'; export const ruleStepsOrder: RuleStepsOrder = [ diff --git a/x-pack/plugins/security_solution/public/exceptions/routes.tsx b/x-pack/plugins/security_solution/public/exceptions/routes.tsx index 512baa600e298..b977a98722444 100644 --- a/x-pack/plugins/security_solution/public/exceptions/routes.tsx +++ b/x-pack/plugins/security_solution/public/exceptions/routes.tsx @@ -11,7 +11,7 @@ import { Route } from '@kbn/kibana-react-plugin/public'; import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import * as i18n from './translations'; import { EXCEPTIONS_PATH, SecurityPageName } from '../../common/constants'; -import { ExceptionListsTable } from '../detections/pages/detection_engine/rules/all/exceptions/exceptions_table'; +import { ExceptionListsTable } from '../detection_engine/rule_exceptions_ui/pages/exceptions/exceptions_table'; import { SpyRoute } from '../common/utils/route/spy_routes'; import { NotFoundPage } from '../app/404'; import { useReadonlyHeader } from '../use_readonly_header'; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx index 27d8cc54fd0da..a3e062912070c 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx @@ -19,7 +19,6 @@ import { TestProviders, } from '../../../common/mock'; import { HostDetailsTabs } from './details_tabs'; -import type { HostDetailsTabsProps } from './types'; import { hostDetailsPagePath } from '../types'; import { type } from './utils'; import { useMountAppended } from '../../../common/utils/use_mount_appended'; @@ -114,10 +113,6 @@ describe('body', () => { }, }); - const componentProps: Record> = { - events: { pageFilters: mockHostDetailsPageFilters }, - alerts: { pageFilters: mockHostDetailsPageFilters }, - }; const mount = useMountAppended(); Object.entries(scenariosMap).forEach(([path, componentName]) => @@ -133,7 +128,7 @@ describe('body', () => { indexNames={[]} indexPattern={mockIndexPattern} type={type} - pageFilters={mockHostDetailsPageFilters} + hostDetailsFilter={mockHostDetailsPageFilters} filterQuery={filterQuery} from={'2020-07-07T08:20:18.966Z'} to={'2020-07-08T08:20:18.966Z'} @@ -181,7 +176,7 @@ describe('body', () => { title: 'filebeat-*,auditbeat-*,packetbeat-*', }, hostName: 'host-1', - ...(componentProps[path] != null ? componentProps[path] : []), + ...(path === 'events' && { additionalFilters: mockHostDetailsPageFilters }), }); }) ); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx index e970195b6ffe5..8837f28c08200 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; @@ -16,7 +16,6 @@ import { AnomaliesQueryTabBody } from '../../../common/containers/anomalies/anom import { useGlobalTime } from '../../../common/containers/use_global_time'; import { AnomaliesHostTable } from '../../../common/components/ml/tables/anomalies_host_table'; import { EventsQueryTabBody } from '../../../common/components/events_tab'; -import { hostNameExistsFilter } from '../../../common/components/visualization_actions/utils'; import type { HostDetailsTabsProps } from './types'; import { type } from './utils'; @@ -34,8 +33,8 @@ export const HostDetailsTabs = React.memo( filterQuery, indexNames, indexPattern, - pageFilters = [], hostDetailsPagePath, + hostDetailsFilter, }) => { const { from, to, isInitializing, deleteQuery, setQuery } = useGlobalTime(); @@ -52,11 +51,6 @@ export const HostDetailsTabs = React.memo( hostName: detailName, }; - const externalAlertPageFilters = useMemo( - () => [...hostNameExistsFilter, ...pageFilters], - [pageFilters] - ); - return ( @@ -71,10 +65,9 @@ export const HostDetailsTabs = React.memo( diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index a601e29951656..9d430654c7748 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -80,7 +80,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta ); const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); const query = useDeepEqualSelector(getGlobalQuerySelector); - const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const globalFilters = useDeepEqualSelector(getGlobalFiltersQuerySelector); const { to, from, deleteQuery, setQuery, isInitializing } = useGlobalTime(); const { globalFullScreen } = useGlobalFullScreen(); @@ -127,14 +127,14 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta buildEsQuery( indexPattern, [query], - [...hostDetailsPageFilters, ...filters], + [...hostDetailsPageFilters, ...globalFilters], getEsQueryConfig(uiSettings) ), ]; } catch (e) { return [undefined, e]; } - }, [filters, indexPattern, query, uiSettings, hostDetailsPageFilters]); + }, [globalFilters, indexPattern, query, uiSettings, hostDetailsPageFilters]); const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery); useInvalidFilterQuery({ @@ -255,7 +255,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta indexNames={selectedPatterns} isInitializing={isInitializing} deleteQuery={deleteQuery} - pageFilters={hostDetailsPageFilters} + hostDetailsFilter={hostDetailsPageFilters} to={to} from={from} detailName={detailName} diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts index 5299037a2eb3b..67129bb9fe430 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts @@ -38,7 +38,7 @@ export type HostDetailsNavTab = Record; export type HostDetailsTabsProps = HostBodyComponentDispatchProps & HostsQueryProps & { indexNames: string[]; - pageFilters?: Filter[]; + hostDetailsFilter: Filter[]; filterQuery?: string; indexPattern: DataViewBase; type: hostsModel.HostsType; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx index 432ebfdde99b8..b287c32147b54 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx @@ -81,7 +81,8 @@ const HostsComponent = () => { ); const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); const query = useDeepEqualSelector(getGlobalQuerySelector); - const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const globalFilters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const getHostRiskScoreFilterQuerySelector = useMemo( () => hostsSelectors.hostRiskScoreSeverityFilterSelector(), [] @@ -97,16 +98,17 @@ const HostsComponent = () => { const { tabName } = useParams<{ tabName: string }>(); const tabsFilters: Filter[] = React.useMemo(() => { if (tabName === HostsTableType.events) { - return filters.length > 0 ? [...filters, ...hostNameExistsFilter] : hostNameExistsFilter; + return [...globalFilters, ...hostNameExistsFilter]; } if (tabName === HostsTableType.risk) { const severityFilter = generateSeverityFilter(severitySelection, RiskScoreEntity.host); - - return [...severityFilter, ...hostNameExistsFilter, ...filters]; + return [...globalFilters, ...hostNameExistsFilter, ...severityFilter]; } - return filters; - }, [severitySelection, tabName, filters]); + + return globalFilters; + }, [globalFilters, severitySelection, tabName]); + const updateDateRange = useCallback( ({ x }) => { if (!x) { @@ -124,15 +126,15 @@ const HostsComponent = () => { [dispatch] ); const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); - const [filterQuery, kqlError] = useMemo( + const [globalFilterQuery, kqlError] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), indexPattern, queries: [query], - filters, + filters: globalFilters, }), - [filters, indexPattern, uiSettings, query] + [globalFilters, indexPattern, uiSettings, query] ); const [tabsFilterQuery] = useMemo( () => @@ -145,7 +147,14 @@ const HostsComponent = () => { [indexPattern, query, tabsFilters, uiSettings] ); - useInvalidFilterQuery({ id: ID, filterQuery, kqlError, query, startDate: from, endDate: to }); + useInvalidFilterQuery({ + id: ID, + filterQuery: globalFilterQuery, + kqlError, + query, + startDate: from, + endDate: to, + }); const isEnterprisePlus = useLicense().isEnterprise(); @@ -193,12 +202,12 @@ const HostsComponent = () => { /> @@ -218,13 +227,12 @@ const HostsComponent = () => { diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx index 208a5a062759a..18fd5628d2ebc 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, useMemo } from 'react'; +import React from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; @@ -25,18 +25,8 @@ import { import { TableId } from '../../../common/types'; import { hostNameExistsFilter } from '../../common/components/visualization_actions/utils'; -export const HostsTabs = memo( - ({ - deleteQuery, - filterQuery, - pageFilters = [], - from, - indexNames, - isInitializing, - setQuery, - to, - type, - }) => { +export const HostsTabs = React.memo( + ({ deleteQuery, filterQuery, from, indexNames, isInitializing, setQuery, to, type }) => { const tabProps = { deleteQuery, endDate: to, @@ -48,10 +38,6 @@ export const HostsTabs = memo( type, }; - const externalAlertPageFilters = useMemo( - () => [...hostNameExistsFilter, ...pageFilters], - [pageFilters] - ); return ( @@ -68,10 +54,9 @@ export const HostsTabs = memo( diff --git a/x-pack/plugins/security_solution/public/hosts/pages/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/types.ts index e16ccfa100fb4..e04e61ddeac90 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/types.ts @@ -5,7 +5,6 @@ * 2.0. */ -import type { Filter } from '@kbn/es-query'; import type { hostsModel } from '../store'; import type { GlobalTimeArgs } from '../../common/containers/use_global_time'; import { HOSTS_PATH } from '../../../common/constants'; @@ -13,8 +12,7 @@ import { HOSTS_PATH } from '../../../common/constants'; export const hostDetailsPagePath = `${HOSTS_PATH}/name/:detailName`; export type HostsTabsProps = GlobalTimeArgs & { - filterQuery: string; - pageFilters?: Filter[]; + filterQuery?: string; indexNames: string[]; type: hostsModel.HostsType; }; diff --git a/x-pack/plugins/security_solution/public/management/components/console/service/parse_command_input.test.ts b/x-pack/plugins/security_solution/public/management/components/console/service/parse_command_input.test.ts index 1d0917d1a0959..a4d3a983041fd 100644 --- a/x-pack/plugins/security_solution/public/management/components/console/service/parse_command_input.test.ts +++ b/x-pack/plugins/security_solution/public/management/components/console/service/parse_command_input.test.ts @@ -144,5 +144,25 @@ describe('when using parsed command input utils', () => { }) ); }); + + it.each([ + [String.raw`C:\Foo\Dir\whatever.jpg`, undefined], + [String.raw`C:\\abc`, undefined], + [String.raw`F:\foo\bar.docx`, undefined], + [String.raw`C:/foo/bar.docx`, undefined], + [String.raw`C:\\\//\/\\/\\\/abc/\/\/\///def.txt`, undefined], + [String.raw`C:\abc~!@#$%^&*()_'+`, undefined], + [String.raw`C:foobar`, undefined], + [String.raw`C:\dir with spaces\foo.txt`, undefined], + [String.raw`C:\dir\file with spaces.txt`, undefined], + [String.raw`/tmp/linux file with spaces "and quotes" omg.txt`, undefined], + ['c\\foo\\b\\-\\-ar.txt', String.raw`c\foo\b--ar.txt`], + ['c:\\foo\\b \\-\\-ar.txt', String.raw`c:\foo\b --ar.txt`], + ])('should preserve backslashes in argument values: %s', (path, expected) => { + const input = `foo --path "${path}"`; + const parsedCommand = parseCommandInput(input); + + expect(parsedCommand.args).toEqual({ path: [expected ?? path] }); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/components/console/service/parsed_command_input.ts b/x-pack/plugins/security_solution/public/management/components/console/service/parsed_command_input.ts index 76866f41955e3..78ab197ebd227 100644 --- a/x-pack/plugins/security_solution/public/management/components/console/service/parsed_command_input.ts +++ b/x-pack/plugins/security_solution/public/management/components/console/service/parsed_command_input.ts @@ -67,7 +67,7 @@ const parseInputString = (rawInput: string): ParsedCommandInput => { let newArgValue = argNameAndValueTrimmedString .substring(firstSpaceOrEqualSign.index + 1) .trim() - .replace(/\\/g, ''); + .replace(/\\-\\-/g, '--'); if (newArgValue.charAt(0) === '"') { newArgValue = newArgValue.substring(1); diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/endpoint_response_actions_console_commands.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/endpoint_response_actions_console_commands.ts index 0a5a32bbdfebc..5269306424a84 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/endpoint_response_actions_console_commands.ts +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/endpoint_response_actions_console_commands.ts @@ -379,9 +379,10 @@ export const getEndpointResponseActionsConsoleCommands = ({ capabilities: endpointCapabilities, privileges: endpointPrivileges, }, - exampleUsage: 'get-file path="/full/path/to/file.txt"', + exampleUsage: 'get-file path "/full/path/to/file.txt" --comment "Possible malware"', exampleInstruction: ENTER_OR_ADD_COMMENT_ARG_INSTRUCTION, validate: capabilitiesAndPrivilegesValidator, + mustHaveArgs: true, args: { path: { required: true, diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/get_file_action.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/get_file_action.tsx index 1f8cb4de72717..d0f090e6595c6 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/get_file_action.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/get_file_action.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import { memo, useMemo } from 'react'; +import React, { memo, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; import { useSendGetFileRequest } from '../../hooks/endpoint/use_send_get_file_request'; import type { ResponseActionGetFileRequestBody } from '../../../../common/endpoint/schema/actions'; import { useConsoleActionSubmitter } from './hooks/use_console_action_submitter'; import type { ActionRequestComponentProps } from './types'; +import { ResponseActionFileDownloadLink } from '../response_action_file_download_link'; export const GetFileActionResult = memo< ActionRequestComponentProps<{ @@ -33,7 +35,7 @@ export const GetFileActionResult = memo< : undefined; }, [command.args.args, command.commandDefinition?.meta?.endpointId]); - return useConsoleActionSubmitter({ + const { result, actionDetails } = useConsoleActionSubmitter({ ResultComponent, setStore, store, @@ -42,8 +44,26 @@ export const GetFileActionResult = memo< actionCreator, actionRequestBody, dataTestSubj: 'getFile', - }).result; + pendingMessage: i18n.translate('xpack.securitySolution.getFileAction.pendingMessage', { + defaultMessage: 'Retrieving the file from host.', + }), + }); - // FIXME:PT implement success UI output once we have download API + if (actionDetails?.isCompleted && actionDetails.wasSuccessful) { + return ( + + + + ); + } + + return result; }); GetFileActionResult.displayName = 'GetFileActionResult'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx index 7183b5cc61ef7..98f8954f0dd65 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/hooks/use_console_action_submitter.tsx @@ -63,6 +63,11 @@ export interface UseConsoleActionSubmitterOptions< actionRequestBody: TReqBody | undefined; dataTestSubj?: string; + + /** */ + pendingMessage?: string; + + successMessage?: string; } /** @@ -78,6 +83,8 @@ export interface UseConsoleActionSubmitterOptions< * @param store * @param ResultComponent * @param dataTestSubj + * @param pendingMessage + * @param successMessage */ export const useConsoleActionSubmitter = < TReqBody extends BaseActionRequestBody = BaseActionRequestBody, @@ -91,6 +98,8 @@ export const useConsoleActionSubmitter = < store, ResultComponent, dataTestSubj, + pendingMessage, + successMessage, }: UseConsoleActionSubmitterOptions< TReqBody, TActionOutputContent @@ -237,7 +246,11 @@ export const useConsoleActionSubmitter = < // Calculate the action's UI result based on the different API responses const result = useMemo(() => { if (isPending) { - return ; + return ( + + {pendingMessage} + + ); } const apiError = actionRequestError || actionDetailsError; @@ -246,7 +259,7 @@ export const useConsoleActionSubmitter = < return ( @@ -271,6 +284,7 @@ export const useConsoleActionSubmitter = < ResultComponent={ResultComponent} action={actionDetails} data-test-subj={getTestId('success')} + title={successMessage} /> ); } @@ -283,6 +297,8 @@ export const useConsoleActionSubmitter = < actionDetails, ResultComponent, getTestId, + pendingMessage, + successMessage, ]); return { diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx index 01b50dc759a8b..2f8b84c81e038 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/integration_tests/get_file_action.test.tsx @@ -23,7 +23,9 @@ import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint import type { EndpointPrivileges } from '../../../../../common/endpoint/types'; import { INSUFFICIENT_PRIVILEGES_FOR_COMMAND } from '../../../../common/translations'; -describe('When using get-file aciton from response actions console', () => { +jest.mock('../../../../common/components/user_privileges'); + +describe('When using get-file action from response actions console', () => { let render: ( capabilities?: EndpointCapabilities[] ) => Promise>; @@ -124,4 +126,17 @@ describe('When using get-file aciton from response actions console', () => { 'Argument can only be used once: --comment' ); }); + + it('should display download link once action completes', async () => { + await render(); + enterConsoleCommand(renderResult, 'get-file --path="one/two"'); + + await waitFor(() => { + expect(apiMocks.responseProvider.actionDetails).toHaveBeenCalled(); + }); + + expect(renderResult.getByTestId('getFileSuccess').textContent).toEqual( + 'File retrieved from the host.Click here to download(ZIP file passcode: elastic)' + ); + }); }); diff --git a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts index f7796f8ef4c5c..ac4aebf65c496 100644 --- a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts +++ b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts @@ -8,6 +8,8 @@ import { i18n } from '@kbn/i18n'; import type { DocLinks } from '@kbn/doc-links'; +import { ENDPOINT_ERROR_CODES } from '../../../../common/endpoint/constants'; + type PackageActions = 'es_connection' | 'policy_failure'; export const titles = Object.freeze( @@ -93,7 +95,7 @@ export class PackageActionFormatter { } private getKeyFromErrorCode(code: number): PackageActions { - if (code === 123) { + if (code === ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR) { return 'es_connection'; } else if (code === 124) { return 'policy_failure'; diff --git a/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/index.ts b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/index.ts new file mode 100644 index 0000000000000..35a781976e565 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { ResponseActionFileDownloadLink } from './response_action_file_download_link'; diff --git a/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.tsx b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.tsx new file mode 100644 index 0000000000000..6c01b2284e997 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/response_action_file_download_link/response_action_file_download_link.tsx @@ -0,0 +1,78 @@ +/* + * 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 { CSSProperties } from 'react'; +import React, { memo } from 'react'; +import { EuiButtonEmpty, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { useUserPrivileges } from '../../../common/components/user_privileges'; +import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; +import type { MaybeImmutable } from '../../../../common/endpoint/types'; +import { getHostActionFileDownloadUrl } from '../../services/response_actions/get_host_action_file_download_url'; +import type { ActionDetails } from '../../../../common/endpoint/types/actions'; + +const STYLE_INHERIT_FONT_FAMILY = Object.freeze({ + fontFamily: 'inherit', +}); + +const DEFAULT_BUTTON_TITLE = i18n.translate( + 'xpack.securitySolution.responseActionFileDownloadLink.downloadButtonLabel', + { defaultMessage: 'Click here to download' } +); + +export interface ResponseActionFileDownloadLinkProps { + action: MaybeImmutable; + buttonTitle?: string; + 'data-test-subj'?: string; +} + +/** + * Displays the download link for a file retrieved via a Response Action. The download link + * button will only be displayed if the user has authorization to use file operations. + * + * NOTE: Currently displays only the link for the first host in the Action + */ +export const ResponseActionFileDownloadLink = memo( + ({ action, buttonTitle = DEFAULT_BUTTON_TITLE, 'data-test-subj': dataTestSubj }) => { + const getTestId = useTestIdGenerator(dataTestSubj); + const { canWriteFileOperations } = useUserPrivileges().endpointPrivileges; + + if (!canWriteFileOperations) { + return null; + } + + return ( + <> + + {buttonTitle} + + + + + + ); + } +); +ResponseActionFileDownloadLink.displayName = 'ResponseActionFileDownloadLink'; diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx index 7931e8a9765b8..3ad37c76c7ffc 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx @@ -58,7 +58,9 @@ export const useWithShowEndpointResponder = (): ShowEndpointResponseActionsConso }, PageTitleComponent: () => <>{RESPONDER_PAGE_TITLE}, PageBodyComponent: () => , - ActionComponents: [ActionLogButton], + ActionComponents: endpointPrivileges.canReadActionsLogManagement + ? [ActionLogButton] + : undefined, }) .show(); } diff --git a/x-pack/plugins/security_solution/public/management/links.test.ts b/x-pack/plugins/security_solution/public/management/links.test.ts index 3ddd52b918efd..8ac24fe4ed098 100644 --- a/x-pack/plugins/security_solution/public/management/links.test.ts +++ b/x-pack/plugins/security_solution/public/management/links.test.ts @@ -9,22 +9,18 @@ import type { HttpSetup } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; import { SecurityPageName } from '../app/types'; -import { licenseService } from '../common/hooks/use_license'; + +import { calculateEndpointAuthz } from '../../common/endpoint/service/authz'; import type { StartPlugins } from '../types'; import { links, getManagementFilteredLinks } from './links'; import { allowedExperimentalValues } from '../../common/experimental_features'; import { ExperimentalFeaturesService } from '../common/experimental_features_service'; -jest.mock('../common/hooks/use_license', () => { - const licenseServiceInstance = { - isPlatinumPlus: jest.fn(), - isEnterprise: jest.fn(() => true), - }; +jest.mock('../../common/endpoint/service/authz', () => { + const originalModule = jest.requireActual('../../common/endpoint/service/authz'); return { - licenseService: licenseServiceInstance, - useLicense: () => { - return licenseServiceInstance; - }, + ...originalModule, + calculateEndpointAuthz: jest.fn(), }; }); @@ -60,9 +56,13 @@ describe('links', () => { } as unknown as StartPlugins); }); - it('it returns all links without filtering when having isolate permission', async () => { - (licenseService.isPlatinumPlus as jest.Mock).mockReturnValue(true); - fakeHttpServices.get.mockResolvedValue({ total: 0 }); + it('should return all links without filtering when having isolate permission', async () => { + (calculateEndpointAuthz as jest.Mock).mockReturnValue({ + canIsolateHost: true, + canUnIsolateHost: true, + canReadActionsLogManagement: true, + }); + const filteredLinks = await getManagementFilteredLinks( coreMockStarted, getPlugins(['superuser']) @@ -70,77 +70,115 @@ describe('links', () => { expect(filteredLinks).toEqual(links); }); - it('it returns all but response actions history link when NO isolation permission but HAS at least one host isolation exceptions entry', async () => { - (licenseService.isPlatinumPlus as jest.Mock).mockReturnValue(false); - fakeHttpServices.get.mockResolvedValue({ total: 1 }); - const filteredLinks = await getManagementFilteredLinks( - coreMockStarted, - getPlugins(['superuser']) - ); - expect(filteredLinks).toEqual({ - ...links, - links: links.links?.filter((link) => link.id !== SecurityPageName.responseActionsHistory), + describe('Action Logs', () => { + it('should return all but response actions link when no actions log access', async () => { + (calculateEndpointAuthz as jest.Mock).mockReturnValue({ + canIsolateHost: true, + canUnIsolateHost: true, + canReadActionsLogManagement: false, + }); + fakeHttpServices.get.mockResolvedValue({ total: 0 }); + + const filteredLinks = await getManagementFilteredLinks( + coreMockStarted, + getPlugins(['superuser']) + ); + expect(filteredLinks).toEqual({ + ...links, + links: links.links?.filter((link) => link.id !== SecurityPageName.responseActionsHistory), + }); }); }); - it('it returns all but response actions history when NO access to either response actions history or HIE but have at least one HIE entry', async () => { - fakeHttpServices.get.mockResolvedValue({ total: 1 }); - (licenseService.isPlatinumPlus as jest.Mock).mockReturnValue(false); - const filteredLinks = await getManagementFilteredLinks( - coreMockStarted, - getPlugins(['superuser']) - ); + describe('Host Isolation Exception', () => { + it('should return all but HIE when NO isolation permission due to privilege', async () => { + (calculateEndpointAuthz as jest.Mock).mockReturnValue({ + canIsolateHost: false, + canUnIsolateHost: false, + canReadActionsLogManagement: true, + }); - expect(filteredLinks).toEqual({ - ...links, - links: links.links?.filter((link) => link.id !== SecurityPageName.responseActionsHistory), + const filteredLinks = await getManagementFilteredLinks( + coreMockStarted, + getPlugins(['superuser']) + ); + expect(filteredLinks).toEqual({ + ...links, + links: links.links?.filter((link) => link.id !== SecurityPageName.hostIsolationExceptions), + }); }); - }); - it('it returns all but response actions history when NO enterprise license and can not isolate but HAS an HIE entry', async () => { - (licenseService.isEnterprise as jest.Mock).mockReturnValue(false); - (licenseService.isPlatinumPlus as jest.Mock).mockReturnValue(false); - fakeHttpServices.get.mockResolvedValue({ total: 1 }); - const filteredLinks = await getManagementFilteredLinks( - coreMockStarted, - getPlugins(['superuser']) - ); + it('should return all but HIE when NO isolation permission due to license and NO host isolation exceptions entry', async () => { + (calculateEndpointAuthz as jest.Mock).mockReturnValue({ + canIsolateHost: false, + canUnIsolateHost: true, + canReadActionsLogManagement: true, + }); + fakeHttpServices.get.mockResolvedValue({ total: 0 }); - expect(filteredLinks).toEqual({ - ...links, - links: links.links?.filter((link) => link.id !== SecurityPageName.responseActionsHistory), + const filteredLinks = await getManagementFilteredLinks( + coreMockStarted, + getPlugins(['superuser']) + ); + expect(filteredLinks).toEqual({ + ...links, + links: links.links?.filter((link) => link.id !== SecurityPageName.hostIsolationExceptions), + }); }); - }); - it('it returns all but response actions history and HIE links when NO enterprise license and no HIE entry', async () => { - (licenseService.isEnterprise as jest.Mock).mockReturnValue(false); - fakeHttpServices.get.mockResolvedValue({ total: 0 }); - const filteredLinks = await getManagementFilteredLinks( - coreMockStarted, - getPlugins(['superuser']) - ); + it('should return all when NO isolation permission due to license but HAS at least one host isolation exceptions entry', async () => { + (calculateEndpointAuthz as jest.Mock).mockReturnValue({ + canIsolateHost: false, + canUnIsolateHost: true, + canReadActionsLogManagement: true, + }); + fakeHttpServices.get.mockResolvedValue({ total: 1 }); - expect(filteredLinks).toEqual({ - ...links, - links: links.links?.filter( - (link) => - link.id !== SecurityPageName.hostIsolationExceptions && - link.id !== SecurityPageName.responseActionsHistory - ), + const filteredLinks = await getManagementFilteredLinks( + coreMockStarted, + getPlugins(['superuser']) + ); + expect(filteredLinks).toEqual(links); }); - }); - it('it returns filtered links when not having NO isolation permission and NO host isolation exceptions entry', async () => { - fakeHttpServices.get.mockResolvedValue({ total: 0 }); - (licenseService.isPlatinumPlus as jest.Mock).mockReturnValue(false); - const filteredLinks = await getManagementFilteredLinks(coreMockStarted, getPlugins([])); - expect(filteredLinks).toEqual({ - ...links, - links: links.links?.filter( - (link) => - link.id !== SecurityPageName.hostIsolationExceptions && - link.id !== SecurityPageName.responseActionsHistory - ), + it('should not affect showing Action Log if getting from HIE API throws error', async () => { + (calculateEndpointAuthz as jest.Mock).mockReturnValue({ + canIsolateHost: false, + canUnIsolateHost: true, + canReadActionsLogManagement: true, + }); + fakeHttpServices.get.mockRejectedValue(new Error()); + + const filteredLinks = await getManagementFilteredLinks( + coreMockStarted, + getPlugins(['superuser']) + ); + expect(filteredLinks).toEqual({ + ...links, + links: links.links?.filter((link) => link.id !== SecurityPageName.hostIsolationExceptions), + }); + }); + + it('should not affect hiding Action Log if getting from HIE API throws error', async () => { + (calculateEndpointAuthz as jest.Mock).mockReturnValue({ + canIsolateHost: false, + canUnIsolateHost: true, + canReadActionsLogManagement: false, + }); + fakeHttpServices.get.mockRejectedValue(new Error()); + + const filteredLinks = await getManagementFilteredLinks( + coreMockStarted, + getPlugins(['superuser']) + ); + expect(filteredLinks).toEqual({ + ...links, + links: links.links?.filter( + (link) => + link.id !== SecurityPageName.hostIsolationExceptions && + link.id !== SecurityPageName.responseActionsHistory + ), + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/links.ts b/x-pack/plugins/security_solution/public/management/links.ts index 75436383547ab..0eaa0202bd0d1 100644 --- a/x-pack/plugins/security_solution/public/management/links.ts +++ b/x-pack/plugins/security_solution/public/management/links.ts @@ -246,10 +246,11 @@ export const getManagementFilteredLinks = async ( const fleetAuthz = plugins.fleet?.authz; const isEndpointRbacEnabled = ExperimentalFeaturesService.get().endpointRbacEnabled; const endpointPermissions = calculatePermissionsFromCapabilities(core.application.capabilities); + const linksToExclude: SecurityPageName[] = []; try { const currentUserResponse = await plugins.security.authc.getCurrentUser(); - const { canAccessEndpointManagement, canIsolateHost, canReadActionsLogManagement } = fleetAuthz + const { canReadActionsLogManagement, canIsolateHost, canUnIsolateHost } = fleetAuthz ? calculateEndpointAuthz( licenseService, fleetAuthz, @@ -259,37 +260,28 @@ export const getManagementFilteredLinks = async ( ) : getEndpointAuthzInitialState(); - if (!canAccessEndpointManagement) { - return excludeLinks([ - SecurityPageName.hostIsolationExceptions, - SecurityPageName.responseActionsHistory, - ]); + if (!canReadActionsLogManagement) { + linksToExclude.push(SecurityPageName.responseActionsHistory); } - if (!canReadActionsLogManagement) { - // <= enterprise license - const hostExceptionCount = await getHostIsolationExceptionTotal(core.http); - if (!canIsolateHost && !hostExceptionCount) { - return excludeLinks([ - SecurityPageName.hostIsolationExceptions, - SecurityPageName.responseActionsHistory, - ]); + if (!canIsolateHost && canUnIsolateHost) { + let shouldSeeHIEToBeAbleToDeleteEntries: boolean; + try { + const hostExceptionCount = await getHostIsolationExceptionTotal(core.http); + shouldSeeHIEToBeAbleToDeleteEntries = hostExceptionCount !== 0; + } catch { + shouldSeeHIEToBeAbleToDeleteEntries = false; } - return excludeLinks([SecurityPageName.responseActionsHistory]); - } else if (!canIsolateHost) { - const hostExceptionCount = await getHostIsolationExceptionTotal(core.http); - if (!hostExceptionCount) { - // <= platinum so exclude also links that require enterprise - return excludeLinks([ - SecurityPageName.hostIsolationExceptions, - SecurityPageName.responseActionsHistory, - ]); + + if (!shouldSeeHIEToBeAbleToDeleteEntries) { + linksToExclude.push(SecurityPageName.hostIsolationExceptions); } - return excludeLinks([SecurityPageName.responseActionsHistory]); + } else if (!canIsolateHost) { + linksToExclude.push(SecurityPageName.hostIsolationExceptions); } } catch { - return excludeLinks([SecurityPageName.hostIsolationExceptions]); + linksToExclude.push(SecurityPageName.hostIsolationExceptions); } - return links; + return excludeLinks(linksToExclude); }; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx index a293e278721ec..a8c219444e1ca 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx @@ -18,7 +18,7 @@ export enum EndpointDetailsTabsTypes { activityLog = 'activity_log', } -interface EndpointDetailsTabs { +export interface EndpointDetailsTabs { id: string; name: string; content: JSX.Element; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx index 3a15b6b3873a5..1d7c18016fc06 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx @@ -7,6 +7,7 @@ import { EuiFlyoutBody, EuiFlyoutFooter, EuiLoadingContent, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { memo, useCallback, useEffect, useMemo } from 'react'; +import { useUserPrivileges } from '../../../../../common/components/user_privileges'; import { ResponseActionsLog } from '../../../../components/endpoint_response_actions_list/response_actions_log'; import { PolicyResponseWrapper } from '../../../../components/policy_response'; import type { HostMetadata } from '../../../../../../common/endpoint/types'; @@ -26,6 +27,7 @@ import { ActionsMenu } from './components/actions_menu'; import { EndpointDetailsFlyoutTabs, EndpointDetailsTabsTypes, + type EndpointDetailsTabs, } from './components/endpoint_details_tabs'; import { EndpointIsolationFlyoutPanel } from './components/endpoint_isolate_flyout_panel'; import { EndpointDetailsFlyoutHeader } from './components/flyout_header'; @@ -41,6 +43,7 @@ export const EndpointDetails = memo(() => { const policyInfo = useEndpointSelector(policyVersionInfo); const hostStatus = useEndpointSelector(hostStatusInfo); const show = useEndpointSelector(showView); + const { canReadActionsLogManagement } = useUserPrivileges().endpointPrivileges; const ContentLoadingMarkup = useMemo( () => ( @@ -54,38 +57,53 @@ export const EndpointDetails = memo(() => { ); const getTabs = useCallback( - (id: string) => [ - { - id: EndpointDetailsTabsTypes.overview, - name: i18.OVERVIEW, - route: getEndpointDetailsPath({ - ...queryParams, - name: 'endpointDetails', - selected_endpoint: id, - }), - content: - hostDetails === undefined ? ( - ContentLoadingMarkup - ) : ( - - ), - }, - { - id: EndpointDetailsTabsTypes.activityLog, - name: i18.ACTIVITY_LOG.tabTitle, - route: getEndpointDetailsPath({ - ...queryParams, - name: 'endpointActivityLog', - selected_endpoint: id, - }), - content: , - }, - ], - [ContentLoadingMarkup, hostDetails, policyInfo, hostStatus, queryParams] + (id: string): EndpointDetailsTabs[] => { + const tabs: EndpointDetailsTabs[] = [ + { + id: EndpointDetailsTabsTypes.overview, + name: i18.OVERVIEW, + route: getEndpointDetailsPath({ + ...queryParams, + name: 'endpointDetails', + selected_endpoint: id, + }), + content: + hostDetails === undefined ? ( + ContentLoadingMarkup + ) : ( + + ), + }, + ]; + + // show the response actions history tab + // only when the user has the required permission + if (canReadActionsLogManagement) { + tabs.push({ + id: EndpointDetailsTabsTypes.activityLog, + name: i18.ACTIVITY_LOG.tabTitle, + route: getEndpointDetailsPath({ + ...queryParams, + name: 'endpointActivityLog', + selected_endpoint: id, + }), + content: , + }); + } + return tabs; + }, + [ + canReadActionsLogManagement, + ContentLoadingMarkup, + hostDetails, + policyInfo, + hostStatus, + queryParams, + ] ); const showFlyoutFooter = @@ -103,6 +121,7 @@ export const EndpointDetails = memo(() => { }); } }, [hostDetailsError, show, toasts]); + return ( <> {(show === 'policy_response' || show === 'isolate' || show === 'unisolate') && ( @@ -121,7 +140,9 @@ export const EndpointDetails = memo(() => { {(show === 'details' || show === 'activity_log') && ( )} diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx index 22ee280986830..4f0f7437ddc42 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx @@ -40,8 +40,12 @@ export const useEndpointActionItems = ( const isResponseActionsConsoleEnabled = useIsExperimentalFeatureEnabled( 'responseActionsConsoleEnabled' ); - const { canAccessResponseConsole, canIsolateHost, canUnIsolateHost } = - useUserPrivileges().endpointPrivileges; + const { + canAccessResponseConsole, + canIsolateHost, + canUnIsolateHost, + canReadActionsLogManagement, + } = useUserPrivileges().endpointPrivileges; return useMemo(() => { if (endpointMetadata) { @@ -137,7 +141,7 @@ export const useEndpointActionItems = ( }, ] : []), - ...(options?.isEndpointList + ...(options?.isEndpointList && canReadActionsLogManagement ? [ { 'data-test-subj': 'actionsLink', @@ -249,6 +253,7 @@ export const useEndpointActionItems = ( }, [ allCurrentUrlParams, canAccessResponseConsole, + canReadActionsLogManagement, endpointMetadata, fleetAgentPolicies, getAppUrl, diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx index 2c898e825258e..0c3d0242672e0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx @@ -56,6 +56,7 @@ import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '.. import { getUserPrivilegesMockDefaultValue } from '../../../../common/components/user_privileges/__mocks__'; import { ENDPOINT_CAPABILITIES } from '../../../../../common/endpoint/service/response_actions/constants'; +const mockUserPrivileges = useUserPrivileges as jest.Mock; // not sure why this can't be imported from '../../../../common/mock/formatted_relative'; // but sure enough it needs to be inline in this one file jest.mock('@kbn/i18n-react', () => { @@ -664,6 +665,7 @@ describe('when on the endpoint list page', () => { beforeEach(async () => { mockEndpointListApi(); + mockUserPrivileges.mockReturnValue(getUserPrivilegesMockDefaultValue()); reactTestingLibrary.act(() => { history.push(`${MANAGEMENT_PATH}/endpoints?selected_endpoint=1`); @@ -678,6 +680,7 @@ describe('when on the endpoint list page', () => { afterEach(() => { jest.clearAllMocks(); + mockUserPrivileges.mockReset(); }); it('should show the flyout and footer', async () => { @@ -777,29 +780,81 @@ describe('when on the endpoint list page', () => { }); }); - afterEach(reactTestingLibrary.cleanup); + afterEach(() => { + reactTestingLibrary.cleanup(); + }); - it('should start with the activity log tab as unselected', async () => { - const renderResult = await renderAndWaitForData(); - const detailsTab = renderResult.getByTestId('endpoint-details-flyout-tab-details'); - const activityLogTab = renderResult.getByTestId('endpoint-details-flyout-tab-activity_log'); + describe('when `canReadActionsLogManagement` is TRUE', () => { + it('should start with the activity log tab as unselected', async () => { + const renderResult = await renderAndWaitForData(); + const detailsTab = renderResult.getByTestId('endpoint-details-flyout-tab-details'); + const activityLogTab = renderResult.getByTestId( + 'endpoint-details-flyout-tab-activity_log' + ); + + expect(detailsTab).toHaveAttribute('aria-selected', 'true'); + expect(activityLogTab).toHaveAttribute('aria-selected', 'false'); + expect(renderResult.getByTestId('endpointDetailsFlyoutBody')).not.toBeNull(); + expect(renderResult.queryByTestId('endpointActivityLogFlyoutBody')).toBeNull(); + }); - expect(detailsTab).toHaveAttribute('aria-selected', 'true'); - expect(activityLogTab).toHaveAttribute('aria-selected', 'false'); - expect(renderResult.getByTestId('endpointDetailsFlyoutBody')).not.toBeNull(); - expect(renderResult.queryByTestId('endpointActivityLogFlyoutBody')).toBeNull(); + it('should show the activity log content when selected', async () => { + const renderResult = await renderAndWaitForData(); + const detailsTab = renderResult.getByTestId('endpoint-details-flyout-tab-details'); + const activityLogTab = renderResult.getByTestId( + 'endpoint-details-flyout-tab-activity_log' + ); + + userEvent.click(activityLogTab); + expect(detailsTab).toHaveAttribute('aria-selected', 'false'); + expect(activityLogTab).toHaveAttribute('aria-selected', 'true'); + expect(renderResult.getByTestId('endpointActivityLogFlyoutBody')).not.toBeNull(); + expect(renderResult.queryByTestId('endpointDetailsFlyoutBody')).toBeNull(); + }); }); - it('should show the activity log content when selected', async () => { - const renderResult = await renderAndWaitForData(); - const detailsTab = renderResult.getByTestId('endpoint-details-flyout-tab-details'); - const activityLogTab = renderResult.getByTestId('endpoint-details-flyout-tab-activity_log'); + describe('when `canReadActionsLogManagement` is FALSE', () => { + it('should not show the response actions history tab', async () => { + mockUserPrivileges.mockReturnValue({ + ...mockInitialUserPrivilegesState(), + endpointPrivileges: { + ...mockInitialUserPrivilegesState().endpointPrivileges, + canReadActionsLogManagement: false, + }, + }); + const renderResult = await renderAndWaitForData(); + const detailsTab = renderResult.getByTestId('endpoint-details-flyout-tab-details'); + const activityLogTab = renderResult.queryByTestId( + 'endpoint-details-flyout-tab-activity_log' + ); + + expect(detailsTab).toHaveAttribute('aria-selected', 'true'); + expect(activityLogTab).toBeNull(); + expect(renderResult.findByTestId('endpointDetailsFlyoutBody')).not.toBeNull(); + }); + + it('should show the overview tab when force loading actions history tab via URL', async () => { + mockUserPrivileges.mockReturnValue({ + ...mockInitialUserPrivilegesState(), + endpointPrivileges: { + ...mockInitialUserPrivilegesState().endpointPrivileges, + canReadActionsLogManagement: false, + }, + }); + reactTestingLibrary.act(() => { + history.push(`${MANAGEMENT_PATH}/endpoints?selected_endpoint=1&show=activity_log`); + }); + + const renderResult = await renderAndWaitForData(); + const detailsTab = renderResult.getByTestId('endpoint-details-flyout-tab-details'); + const activityLogTab = renderResult.queryByTestId( + 'endpoint-details-flyout-tab-activity_log' + ); - userEvent.click(activityLogTab); - expect(detailsTab).toHaveAttribute('aria-selected', 'false'); - expect(activityLogTab).toHaveAttribute('aria-selected', 'true'); - expect(renderResult.getByTestId('endpointActivityLogFlyoutBody')).not.toBeNull(); - expect(renderResult.queryByTestId('endpointDetailsFlyoutBody')).toBeNull(); + expect(detailsTab).toHaveAttribute('aria-selected', 'true'); + expect(activityLogTab).toBeNull(); + expect(renderResult.findByTestId('endpointDetailsFlyoutBody')).not.toBeNull(); + }); }); }); @@ -1082,7 +1137,7 @@ describe('when on the endpoint list page', () => { beforeEach(async () => { mockEndpointListApi(); - (useUserPrivileges as jest.Mock).mockReturnValue(getUserPrivilegesMockDefaultValue()); + mockUserPrivileges.mockReturnValue(getUserPrivilegesMockDefaultValue()); reactTestingLibrary.act(() => { history.push(`${MANAGEMENT_PATH}/endpoints`); @@ -1101,6 +1156,7 @@ describe('when on the endpoint list page', () => { afterEach(() => { jest.clearAllMocks(); + mockUserPrivileges.mockReset(); }); it('shows the Responder option when all 3 processes capabilities are present in the endpoint', async () => { @@ -1134,7 +1190,7 @@ describe('when on the endpoint list page', () => { }); it('hides isolate host option if canIsolateHost is false', () => { - (useUserPrivileges as jest.Mock).mockReturnValue({ + mockUserPrivileges.mockReturnValue({ ...mockInitialUserPrivilegesState(), endpointPrivileges: { ...mockInitialUserPrivilegesState().endpointPrivileges, diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/index.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/index.tsx index 27f3740394b32..ac6a191eddd85 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/index.tsx @@ -18,6 +18,7 @@ import { HostIsolationExceptionsList } from './view/host_isolation_exceptions_li * Provides the routing container for the hosts related views */ export const HostIsolationExceptionsContainer = memo(() => { + // TODO: Probably should not silently redirect here const canAccessHostIsolationExceptionsLink = useLinkExists( SecurityPageName.hostIsolationExceptions ); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts index 091559203f6d7..5e4c26e099428 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts @@ -16,6 +16,7 @@ import { HostIsolationExceptionsApiClient } from '../host_isolation_exceptions_a */ export function useCanSeeHostIsolationExceptionsMenu(): boolean { const http = useHttp(); + // TODO: why doesn't this use useUserPrivileges? const privileges = useEndpointPrivileges(); const apiQuery = useSummaryArtifact( HostIsolationExceptionsApiClient.getInstance(http), diff --git a/x-pack/plugins/security_solution/public/management/pages/index.tsx b/x-pack/plugins/security_solution/public/management/pages/index.tsx index 590b3786ece15..ec3d365cdbce4 100644 --- a/x-pack/plugins/security_solution/public/management/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/index.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import type { ComponentType } from 'react'; import React, { memo } from 'react'; import { Switch, Redirect } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; @@ -30,8 +31,8 @@ import { getEndpointListPath } from '../common/routing'; import { useUserPrivileges } from '../../common/components/user_privileges'; import { HostIsolationExceptionsContainer } from './host_isolation_exceptions'; import { BlocklistContainer } from './blocklist'; -import { NoPermissions } from '../components/no_permissons'; import { ResponseActionsContainer } from './response_actions'; +import { NoPermissions } from '../components/no_permissons'; const EndpointTelemetry = () => ( @@ -75,44 +76,74 @@ const ResponseActionsTelemetry = () => ( ); +interface PrivilegedRouteProps { + path: string; + component: ComponentType<{}>; + privilege: boolean; +} + +const PrivilegedRoute = ({ component, privilege, path }: PrivilegedRouteProps) => { + return ; +}; + export const ManagementContainer = memo(() => { - const { loading, canAccessEndpointManagement, canReadActionsLogManagement } = - useUserPrivileges().endpointPrivileges; + const { + loading, + canReadPolicyManagement, + canReadBlocklist, + canReadTrustedApplications, + canReadEventFilters, + canReadActionsLogManagement, + canReadEndpointList, + } = useUserPrivileges().endpointPrivileges; // Lets wait until we can verify permissions if (loading) { return ; } - if (!canAccessEndpointManagement) { - return ( - <> - - - - ); - } - return ( - - - - + + + + - - {canReadActionsLogManagement && ( - + + + + {canReadEndpointList && ( + + + )} - - - ); diff --git a/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx index 0fcc8aa1f0ca5..55d6730b8dc8c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/integration_tests/index.test.tsx @@ -12,33 +12,146 @@ import '../../../common/mock/match_media'; import type { AppContextTestRender } from '../../../common/mock/endpoint'; import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; import { useUserPrivileges } from '../../../common/components/user_privileges'; +import { useCanSeeHostIsolationExceptionsMenu } from '../host_isolation_exceptions/view/hooks'; import { endpointPageHttpMock } from '../endpoint_hosts/mocks'; jest.mock('../../../common/components/user_privileges'); +jest.mock('../host_isolation_exceptions/view/hooks'); + +const useUserPrivilegesMock = useUserPrivileges as jest.Mock; +const useCanSeeHostIsolationExceptionsMenuMock = useCanSeeHostIsolationExceptionsMenu as jest.Mock; describe('when in the Administration tab', () => { let render: () => ReturnType; + const mockedContext = createAppRootMockRenderer(); beforeEach(() => { - const mockedContext = createAppRootMockRenderer(); endpointPageHttpMock(mockedContext.coreStart.http); render = () => mockedContext.render(); mockedContext.history.push('/administration/endpoints'); }); - it('should display the No Permissions if no sufficient privileges', async () => { - (useUserPrivileges as jest.Mock).mockReturnValue({ - endpointPrivileges: { loading: false, canAccessEndpointManagement: false }, + afterEach(() => { + useUserPrivilegesMock.mockReset(); + useCanSeeHostIsolationExceptionsMenuMock.mockReset(); + }); + + describe('when the user has no permissions', () => { + it('should display `no permission` if no `canAccessEndpointManagement`', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canAccessEndpointManagement: false }, + }); + + expect(await render().findByTestId('noIngestPermissions')).toBeTruthy(); + }); + + it('should display `no permission` if no `canReadPolicyManagement`', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadPolicyManagement: false }, + }); + + mockedContext.history.push('/administration/policy'); + expect(await render().findByTestId('noIngestPermissions')).toBeTruthy(); + }); + + it('should display `no permission` if no `canReadTrustedApplications`', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadTrustedApplications: false }, + }); + + mockedContext.history.push('/administration/trusted_apps'); + expect(await render().findByTestId('noIngestPermissions')).toBeTruthy(); + }); + + it('should display `no permission` if no `canReadEventFilters`', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadEventFilters: false }, + }); + + mockedContext.history.push('/administration/event_filters'); + expect(await render().findByTestId('noIngestPermissions')).toBeTruthy(); + }); + + it('should display `no permission` if no `canReadHostIsolationExceptions`', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadHostIsolationExceptions: false }, + }); + + mockedContext.history.push('/administration/host_isolation_exceptions'); + expect(await render().findByTestId('noIngestPermissions')).toBeTruthy(); + }); + + it('should display `no permission` if no `canReadBlocklist`', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadBlocklist: false }, + }); + + mockedContext.history.push('/administration/blocklist'); + expect(await render().findByTestId('noIngestPermissions')).toBeTruthy(); }); - expect(await render().findByTestId('noIngestPermissions')).not.toBeNull(); + it('should display `no permission` if no `canReadActionsLogManagement`', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadActionsLogManagement: false }, + }); + + mockedContext.history.push('/administration/response_actions_history'); + expect(await render().findByTestId('noIngestPermissions')).toBeTruthy(); + }); }); - it('should display the Management view if user has privileges', async () => { - (useUserPrivileges as jest.Mock).mockReturnValue({ - endpointPrivileges: { loading: false, canAccessEndpointManagement: true }, + describe('when the user has permissions', () => { + it('should display the Management view if user has privileges', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadEndpointList: true }, + }); + + expect(await render().findByTestId('endpointPage')).toBeTruthy(); + }); + + it('should display policy list page when `canReadPolicyManagement` is TRUE', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadPolicyManagement: true }, + }); + + mockedContext.history.push('/administration/policy'); + expect(await render().findByTestId('policyListPage')).toBeTruthy(); + }); + + it('should display trusted apps list page when `canReadTrustedApplications` is TRUE', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadTrustedApplications: true }, + }); + + mockedContext.history.push('/administration/trusted_apps'); + expect(await render().findByTestId('trustedAppsListPage-container')).toBeTruthy(); }); - expect(await render().findByTestId('endpointPage')).not.toBeNull(); + it('should display event filters list page when `canReadEventFilters` is TRUE', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadEventFilters: true }, + }); + + mockedContext.history.push('/administration/event_filters'); + expect(await render().findByTestId('EventFiltersListPage-container')).toBeTruthy(); + }); + + it('should display blocklist list page when `canReadBlocklist` is TRUE', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadBlocklist: true }, + }); + + mockedContext.history.push('/administration/blocklist'); + expect(await render().findByTestId('blocklistPage-container')).toBeTruthy(); + }); + + it('should display response actions history page when `canReadActionsLogManagement` is TRUE', async () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canReadActionsLogManagement: true }, + }); + + mockedContext.history.push('/administration/response_actions_history'); + expect(await render().findByTestId('responseActionsPage')).toBeTruthy(); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/services/response_actions/get_host_action_file_download_url.ts b/x-pack/plugins/security_solution/public/management/services/response_actions/get_host_action_file_download_url.ts new file mode 100644 index 0000000000000..5061c6cd36457 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/services/response_actions/get_host_action_file_download_url.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 { resolvePathVariables } from '../../../common/utils/resolve_path_variables'; +import { ACTION_AGENT_FILE_DOWNLOAD_ROUTE } from '../../../../common/endpoint/constants'; +import type { ActionDetails, MaybeImmutable } from '../../../../common/endpoint/types'; + +/** + * get the download URL for a `get-file` action + * @param action + * @param agentId + */ +export const getHostActionFileDownloadUrl = ( + action: MaybeImmutable, + agentId?: string +): string => { + return resolvePathVariables(ACTION_AGENT_FILE_DOWNLOAD_ROUTE, { + action_id: action.id, + agent_id: agentId ?? action.agents[0], + }); +}; diff --git a/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx index 4985d7e896a61..560fc65583301 100644 --- a/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React from 'react'; import { Switch } from 'react-router-dom'; import { EuiFlexItem, EuiSpacer } from '@elastic/eui'; import type { DataViewBase, Filter } from '@kbn/es-query'; import { Route } from '@kbn/kibana-react-plugin/public'; import { TableId } from '../../../../common/types'; -import { getNetworkDetailsPageFilter } from '../../../common/components/visualization_actions/utils'; import { AnomaliesNetworkTable } from '../../../common/components/ml/tables/anomalies_network_table'; import { FlowTargetSourceDest } from '../../../../common/search_strategy/security_solution/network'; import { EventsQueryTabBody } from '../../../common/components/events_tab/events_query_tab_body'; @@ -43,21 +42,17 @@ interface NetworkDetailTabsProps { setQuery: GlobalTimeArgs['setQuery']; indexPattern: DataViewBase; flowTarget: FlowTargetSourceDest; + networkDetailsFilter: Filter[]; } export const NetworkDetailsTabs = React.memo( - ({ indexPattern, flowTarget, ...rest }) => { + ({ flowTarget, indexPattern, networkDetailsFilter, ...rest }) => { const type = networkModel.NetworkType.details; const commonProps = { ...rest, type }; const flowTabProps = { ...commonProps, indexPattern }; const commonPropsWithFlowTarget = { ...commonProps, flowTarget }; - const networkDetailsPageFilters: Filter[] = useMemo( - () => getNetworkDetailsPageFilter(rest.ip), - [rest.ip] - ); - return ( ( path={`${NETWORK_DETAILS_PAGE_PATH}/:flowTarget/:tabName(${NetworkDetailsRouteType.events})`} > diff --git a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx index c9327fe261c10..63eb9a1cb60c0 100644 --- a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx @@ -76,7 +76,7 @@ const NetworkDetailsComponent: React.FC = () => { const canReadAlerts = hasKibanaREAD && hasIndexRead; const query = useDeepEqualSelector(getGlobalQuerySelector); - const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const globalFilters = useDeepEqualSelector(getGlobalFiltersQuerySelector); const type = networkModel.NetworkType.details; const narrowDateRange = useCallback( @@ -101,7 +101,9 @@ const NetworkDetailsComponent: React.FC = () => { }, [detailName, dispatch]); const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); + const ip = decodeIpv6(detailName); + const networkDetailsFilter = useMemo(() => getNetworkDetailsPageFilter(ip), [ip]); const [rawFilteredQuery, kqlError] = useMemo(() => { try { @@ -109,14 +111,14 @@ const NetworkDetailsComponent: React.FC = () => { buildEsQuery( indexPattern, [query], - [...getNetworkDetailsPageFilter(ip), ...filters], + [...networkDetailsFilter, ...globalFilters], getEsQueryConfig(uiSettings) ), ]; } catch (e) { return [undefined, e]; } - }, [filters, indexPattern, ip, query, uiSettings]); + }, [globalFilters, indexPattern, networkDetailsFilter, query, uiSettings]); const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery); useInvalidFilterQuery({ @@ -150,12 +152,6 @@ const NetworkDetailsComponent: React.FC = () => { [flowTarget, ip] ); - // When the filterQuery comes back as undefined, it means an error has been thrown and the request should be skipped - const shouldSkip = useMemo( - () => isInitializing || rawFilteredQuery === undefined, - [isInitializing, rawFilteredQuery] - ); - const entityFilter = useMemo( () => ({ field: `${flowTarget}.ip`, @@ -243,10 +239,11 @@ const NetworkDetailsComponent: React.FC = () => { startDate={from} filterQuery={stringifiedAdditionalFilters} indexNames={selectedPatterns} - skip={shouldSkip} + skip={isInitializing || !!kqlError} setQuery={setQuery} indexPattern={indexPattern} flowTarget={flowTarget} + networkDetailsFilter={networkDetailsFilter} /> diff --git a/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx b/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx index 6f64628baabb9..b336fe1cf2a7f 100644 --- a/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx @@ -21,7 +21,7 @@ import { } from '.'; import { EventsQueryTabBody } from '../../../common/components/events_tab'; import { AnomaliesNetworkTable } from '../../../common/components/ml/tables/anomalies_network_table'; -import { filterNetworkExternalAlertData } from '../../../common/components/visualization_actions/utils'; +import { sourceOrDestinationIpExistsFilter } from '../../../common/components/visualization_actions/utils'; import { AnomaliesQueryTabBody } from '../../../common/containers/anomalies/anomalies_query_tab_body'; import { TableId } from '../../../../common/types'; import { ConditionalFlexGroup } from './conditional_flex_group'; @@ -115,7 +115,7 @@ export const NetworkRoutes = React.memo( diff --git a/x-pack/plugins/security_solution/public/network/pages/network.tsx b/x-pack/plugins/security_solution/public/network/pages/network.tsx index b9db632e3fd74..b15f6603ee52f 100644 --- a/x-pack/plugins/security_solution/public/network/pages/network.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/network.tsx @@ -49,7 +49,7 @@ import { TableId } from '../../../common/types/timeline'; import { useSourcererDataView } from '../../common/containers/sourcerer'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../common/hooks/use_selector'; import { useInvalidFilterQuery } from '../../common/hooks/use_invalid_filter_query'; -import { filterNetworkExternalAlertData } from '../../common/components/visualization_actions/utils'; +import { sourceOrDestinationIpExistsFilter } from '../../common/components/visualization_actions/utils'; import { LandingPageComponent } from '../../common/components/landing_page'; import { dataTableSelectors } from '../../common/store/data_table'; import { tableDefaults } from '../../common/store/data_table/defaults'; @@ -78,7 +78,7 @@ const NetworkComponent = React.memo( ); const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); const query = useDeepEqualSelector(getGlobalQuerySelector); - const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const globalFilters = useDeepEqualSelector(getGlobalFiltersQuerySelector); const { to, from, setQuery, isInitializing } = useGlobalTime(); const { globalFullScreen } = useGlobalFullScreen(); @@ -89,12 +89,10 @@ const NetworkComponent = React.memo( const tabsFilters = useMemo(() => { if (tabName === NetworkRouteType.events) { - return filters.length > 0 - ? [...filters, ...filterNetworkExternalAlertData] - : filterNetworkExternalAlertData; + return [...globalFilters, ...sourceOrDestinationIpExistsFilter]; } - return filters; - }, [tabName, filters]); + return globalFilters; + }, [tabName, globalFilters]); const updateDateRange = useCallback( ({ x }) => { @@ -143,8 +141,9 @@ const NetworkComponent = React.memo( config: getEsQueryConfig(kibana.services.uiSettings), indexPattern, queries: [query], - filters, + filters: globalFilters, }); + const [tabsFilterQuery] = convertToBuildEsQuery({ config: getEsQueryConfig(kibana.services.uiSettings), indexPattern, @@ -185,7 +184,7 @@ const NetworkComponent = React.memo( > >; @@ -30,10 +33,10 @@ const MediumShadeText = styled.span` color: ${({ theme }) => theme.eui.euiColorMediumShade}; `; -const INSTALL_JOBS_DOC = - 'https://www.elastic.co/guide/en/machine-learning/current/ml-ad-run-jobs.html'; - -export const useAnomaliesColumns = (loading: boolean): AnomaliesColumns => { +export const useAnomaliesColumns = ( + loading: boolean, + onJobStateChange: (job: SecurityJob) => Promise +): AnomaliesColumns => { const columns: AnomaliesColumns = useMemo( () => [ { @@ -42,8 +45,8 @@ export const useAnomaliesColumns = (loading: boolean): AnomaliesColumns => { truncateText: true, mobileOptions: { show: true }, 'data-test-subj': 'anomalies-table-column-name', - render: (name, { status, count }) => { - if (count > 0 || status === AnomalyJobStatus.enabled) { + render: (name, { count, job }) => { + if (count > 0 || (job && isJobStarted(job.jobState, job.datafeedState))) { return name; } else { return {name}; @@ -52,14 +55,16 @@ export const useAnomaliesColumns = (loading: boolean): AnomaliesColumns => { }, { field: 'count', - sortable: ({ count, status }) => { + sortable: ({ count, job }) => { if (count > 0) { return count; } - if (status === AnomalyJobStatus.disabled) { - return -1; + + if (job && isJobStarted(job.jobState, job.datafeedState)) { + return 0; } - return -2; + + return -1; }, truncateText: true, align: 'right', @@ -67,65 +72,41 @@ export const useAnomaliesColumns = (loading: boolean): AnomaliesColumns => { mobileOptions: { show: true }, width: '15%', 'data-test-subj': 'anomalies-table-column-count', - render: (count, { status, jobId, entity }) => { - if (loading) return ''; - - if (count > 0 || status === AnomalyJobStatus.enabled) { - return ; + render: (count, { entity, job }) => { + if (!job) return ''; + + if (count > 0 || isJobStarted(job.jobState, job.datafeedState)) { + return ; + } else if (isJobFailed(job.jobState, job.datafeedState)) { + return i18n.JOB_STATUS_FAILED; + } else if (job.isCompatible) { + return ; } else { - if (status === AnomalyJobStatus.disabled && jobId) { - return ; - } - - if (status === AnomalyJobStatus.uninstalled) { - return ( - - {i18n.JOB_STATUS_UNINSTALLED} - - ); - } - - return {I18N_JOB_STATUS[status]}; + return ; } }, }, ], - [loading] + [loading, onJobStateChange] ); return columns; }; -const I18N_JOB_STATUS = { - [AnomalyJobStatus.disabled]: i18n.JOB_STATUS_DISABLED, - [AnomalyJobStatus.failed]: i18n.JOB_STATUS_FAILED, -}; - -const EnableJobLink = ({ jobId }: { jobId: string }) => { - const { - services: { - ml, - http, - application: { navigateToUrl }, - }, - } = useKibana(); - - const jobUrl = useMlHref(ml, http.basePath.get(), { - page: ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE, - pageState: { - jobId, - }, - }); - - const onClick = useCallback( - (ev) => { - ev.preventDefault(); - navigateToUrl(jobUrl); - }, - [jobUrl, navigateToUrl] - ); +const EnableJob = ({ + job, + isLoading, + onJobStateChange, +}: { + job: SecurityJob; + isLoading: boolean; + onJobStateChange: (job: SecurityJob) => Promise; +}) => { + const handleChange = useCallback(() => onJobStateChange(job), [job, onJobStateChange]); - return ( - + return isLoading || isJobLoading(job.jobState, job.datafeedState) ? ( + + ) : ( + {i18n.RUN_JOB} ); diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx index 642e4ae207362..37d5cabca6ce4 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.test.tsx @@ -9,12 +9,10 @@ import { render } from '@testing-library/react'; import React from 'react'; import { EntityAnalyticsAnomalies } from '.'; import type { AnomaliesCount } from '../../../../common/components/ml/anomaly/use_anomalies_search'; -import { - AnomalyJobStatus, - AnomalyEntity, -} from '../../../../common/components/ml/anomaly/use_anomalies_search'; +import { AnomalyEntity } from '../../../../common/components/ml/anomaly/use_anomalies_search'; import { TestProviders } from '../../../../common/mock'; +import type { SecurityJob } from '../../../../common/components/ml_popover/types'; const mockUseNotableAnomaliesSearch = jest.fn().mockReturnValue({ isLoading: false, @@ -22,6 +20,15 @@ const mockUseNotableAnomaliesSearch = jest.fn().mockReturnValue({ refetch: jest.fn(), }); +jest.mock( + '@kbn/ml-plugin/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node_shared/lazy_loader', + () => { + return { + MLJobsAwaitingNodeWarning: () => <>, + }; + } +); + jest.mock('../../../../common/components/ml/anomaly/use_anomalies_search', () => { const original = jest.requireActual( '../../../../common/components/ml/anomaly/use_anomalies_search' @@ -66,10 +73,9 @@ describe('EntityAnalyticsAnomalies', () => { it('renders enabled jobs', () => { const jobCount: AnomaliesCount = { - jobId: 'v3_windows_anomalous_script', + job: { isInstalled: true, datafeedState: 'started', jobState: 'opened' } as SecurityJob, name: 'v3_windows_anomalous_script', count: 9999, - status: AnomalyJobStatus.enabled, entity: AnomalyEntity.User, }; @@ -93,10 +99,14 @@ describe('EntityAnalyticsAnomalies', () => { it('renders disabled jobs', () => { const jobCount: AnomaliesCount = { - jobId: 'v3_windows_anomalous_script', + job: { + isInstalled: true, + datafeedState: 'stopped', + jobState: 'closed', + isCompatible: true, + } as SecurityJob, name: 'v3_windows_anomalous_script', count: 0, - status: AnomalyJobStatus.disabled, entity: AnomalyEntity.User, }; @@ -114,15 +124,15 @@ describe('EntityAnalyticsAnomalies', () => { expect(getByTestId('anomalies-table-column-name')).toHaveTextContent(jobCount.name); expect(getByTestId('anomalies-table-column-count')).toHaveTextContent('Run job'); - expect(getByTestId('jobs-table-link')).toBeInTheDocument(); + expect(getByTestId('enable-job')).toBeInTheDocument(); }); it('renders uninstalled jobs', () => { const jobCount: AnomaliesCount = { - jobId: 'v3_windows_anomalous_script', + job: { isInstalled: false, isCompatible: true } as SecurityJob, name: 'v3_windows_anomalous_script', count: 0, - status: AnomalyJobStatus.uninstalled, + entity: AnomalyEntity.User, }; @@ -139,15 +149,20 @@ describe('EntityAnalyticsAnomalies', () => { ); expect(getByTestId('anomalies-table-column-name')).toHaveTextContent(jobCount.name); - expect(getByTestId('anomalies-table-column-count')).toHaveTextContent('uninstalled'); + expect(getByTestId('anomalies-table-column-count')).toHaveTextContent('Run job'); + expect(getByTestId('enable-job')).toBeInTheDocument(); }); it('renders failed jobs', () => { const jobCount: AnomaliesCount = { - jobId: 'v3_windows_anomalous_script', + job: { + isInstalled: true, + datafeedState: 'failed', + jobState: 'failed', + isCompatible: true, + } as SecurityJob, name: 'v3_windows_anomalous_script', count: 0, - status: AnomalyJobStatus.failed, entity: AnomalyEntity.User, }; @@ -169,10 +184,9 @@ describe('EntityAnalyticsAnomalies', () => { it('renders empty count column while loading', () => { const jobCount: AnomaliesCount = { - jobId: 'v3_windows_anomalous_script', + job: undefined, name: 'v3_windows_anomalous_script', count: 0, - status: AnomalyJobStatus.failed, entity: AnomalyEntity.User, }; diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx index d88ad343eab3c..beeae25f64b2a 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/index.tsx @@ -4,10 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, EuiPanel } from '@elastic/eui'; -import { ML_PAGES, useMlHref } from '@kbn/ml-plugin/public'; +import { MLJobsAwaitingNodeWarning, ML_PAGES, useMlHref } from '@kbn/ml-plugin/public'; import { HeaderSection } from '../../../../common/components/header_section'; import { useQueryToggle } from '../../../../common/containers/query_toggle'; import { LastUpdatedAt } from '../../../../common/components/last_updated_at'; @@ -27,6 +27,8 @@ import { SecurityPageName } from '../../../../app/types'; import { getTabsOnUsersUrl } from '../../../../common/components/link_to/redirect_to_users'; import { UsersTableType } from '../../../../users/store/model'; import { useKibana } from '../../../../common/lib/kibana'; +import { useEnableDataFeed } from '../../../../common/components/ml_popover/hooks/use_enable_data_feed'; +import type { SecurityJob } from '../../../../common/components/ml_popover/types'; const TABLE_QUERY_ID = 'entityAnalyticsDashboardAnomaliesTable'; @@ -51,22 +53,40 @@ export const EntityAnalyticsAnomalies = () => { const [updatedAt, setUpdatedAt] = useState(Date.now()); const { toggleStatus, setToggleStatus } = useQueryToggle(TABLE_QUERY_ID); const { deleteQuery, setQuery, from, to } = useGlobalTime(false); - const { isLoading, data, refetch } = useNotableAnomaliesSearch({ + const { + isLoading: isSearchLoading, + data, + refetch, + } = useNotableAnomaliesSearch({ skip: !toggleStatus, from, to, }); - const columns = useAnomaliesColumns(isLoading); + const { isLoading: isEnableDataFeedLoading, enableDatafeed } = useEnableDataFeed(); + + const handleJobStateChange = useCallback( + async (job: SecurityJob) => { + const result = await enableDatafeed(job, job.latestTimestampMs || 0, true); + refetch(); + return result; + }, + [refetch, enableDatafeed] + ); + + const columns = useAnomaliesColumns( + isSearchLoading || isEnableDataFeedLoading, + handleJobStateChange + ); const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); useEffect(() => { setUpdatedAt(Date.now()); - }, [isLoading]); // Update the time when data loads + }, [isSearchLoading]); // Update the time when data loads useQueryInspector({ refetch, queryId: TABLE_QUERY_ID, - loading: isLoading, + loading: isSearchLoading, setQuery, deleteQuery, }); @@ -87,12 +107,17 @@ export const EntityAnalyticsAnomalies = () => { return [onClick, href]; }, [getSecuritySolutionLinkProps]); + const installedJobsIds = useMemo( + () => data.filter(({ job }) => !!job && job.isInstalled).map(({ job }) => job?.id ?? ''), + [data] + ); + return ( } + subtitle={} toggleStatus={toggleStatus} toggleQuery={setToggleStatus} > @@ -124,12 +149,13 @@ export const EntityAnalyticsAnomalies = () => {
    + {toggleStatus && ( diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/header/index.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/header/index.tsx index 1daf91cd2285c..78ded5e6fc941 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/header/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/header/index.tsx @@ -30,6 +30,7 @@ import { useGlobalTime } from '../../../../common/containers/use_global_time'; import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; import { useQueryInspector } from '../../../../common/components/page/manage_query'; import { ENTITY_ANALYTICS_ANOMALIES_PANEL } from '../anomalies'; +import { isJobStarted } from '../../../../../common/machine_learning/helpers'; const StyledEuiTitle = styled(EuiTitle)` color: ${({ theme: { eui } }) => eui.euiColorDanger}; @@ -69,6 +70,7 @@ export const EntityAnalyticsHeader = () => { }); const { data } = useNotableAnomaliesSearch({ skip: false, from, to }); + const dispatch = useDispatch(); const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); const isPlatinumOrTrialLicense = useMlCapabilities().isPlatinumOrTrialLicense; @@ -138,8 +140,14 @@ export const EntityAnalyticsHeader = () => { inspect: inspectHostRiskScore, }); - // Anomalies are enabled if at least one job is installed - const areJobsEnabled = useMemo(() => data.some(({ jobId }) => !!jobId), [data]); + // Anomaly jobs are enabled if at least one job is started or has data + const areJobsEnabled = useMemo( + () => + data.some( + ({ job, count }) => count > 0 || (job && isJobStarted(job.jobState, job.datafeedState)) + ), + [data] + ); const totalAnomalies = useMemo( () => (areJobsEnabled ? sumBy('count', data) : '-'), diff --git a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx index e4706e40aa470..762d805ecb61b 100644 --- a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.test.tsx @@ -49,7 +49,7 @@ describe('EventCounts', () => { (wrapper.find('Memo(OverviewNetworkComponent)').first().props() as OverviewNetworkProps) .filterQuery ).toContain( - '{"bool":{"filter":[{"bool":{"should":[{"bool":{"should":[{"exists":{"field":"source.ip"}}],"minimum_should_match":1}},{"bool":{"should":[{"exists":{"field":"destination.ip"}}],"minimum_should_match":1}}],"minimum_should_match":1}}]}}]' + '{"bool":{"must":[],"filter":[{"bool":{"should":[{"exists":{"field":"source.ip"}},{"exists":{"field":"destination.ip"}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}' ); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx index 5194d697c96b1..f61ee1bf1fb1c 100644 --- a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx @@ -19,7 +19,7 @@ import type { GlobalTimeArgs } from '../../../common/containers/use_global_time' import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; import { hostNameExistsFilter, - filterNetworkExternalAlertData, + sourceOrDestinationIpExistsFilter, } from '../../../common/components/visualization_actions/utils'; interface Props extends Pick { @@ -57,7 +57,7 @@ const EventCountsComponent: React.FC = ({ config: getEsQueryConfig(uiSettings), indexPattern, queries: [query], - filters: [...filters, ...filterNetworkExternalAlertData], + filters: [...filters, ...sourceOrDestinationIpExistsFilter], }), [filters, indexPattern, uiSettings, query] ); diff --git a/x-pack/plugins/security_solution/public/rules/routes.tsx b/x-pack/plugins/security_solution/public/rules/routes.tsx index 633b4005110af..5cfaae23907d2 100644 --- a/x-pack/plugins/security_solution/public/rules/routes.tsx +++ b/x-pack/plugins/security_solution/public/rules/routes.tsx @@ -12,13 +12,13 @@ import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import * as i18n from './translations'; import { RULES_PATH, SecurityPageName } from '../../common/constants'; import { NotFoundPage } from '../app/404'; -import { RulesPage } from '../detections/pages/detection_engine/rules'; -import { CreateRulePage } from '../detections/pages/detection_engine/rules/create'; +import { RulesPage } from '../detection_engine/rule_management_ui/pages/rule_management'; +import { CreateRulePage } from '../detection_engine/rule_creation_ui/pages/rule_creation'; import { RuleDetailsPage, RuleDetailTabs, -} from '../detections/pages/detection_engine/rules/details'; -import { EditRulePage } from '../detections/pages/detection_engine/rules/edit'; +} from '../detection_engine/rule_details_ui/pages/rule_details'; +import { EditRulePage } from '../detection_engine/rule_creation_ui/pages/rule_editing'; import { useReadonlyHeader } from '../use_readonly_header'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; import { SpyRoute } from '../common/utils/route/spy_routes'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx index 092bbecb846c2..d372c8bca2de5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx @@ -63,13 +63,31 @@ export const FlyoutFooterComponent = React.memo( refetchFlyoutData, }: FlyoutFooterProps & PropsFromRedux) => { const alertId = detailsEcsData?.kibana?.alert ? detailsEcsData?._id : null; - const ruleIndex = useMemo( + const ruleIndexRaw = useMemo( () => find({ category: 'signal', field: 'signal.rule.index' }, detailsData)?.values ?? find({ category: 'kibana', field: 'kibana.alert.rule.parameters.index' }, detailsData) ?.values, [detailsData] ); + const ruleIndex = useMemo( + (): string[] | undefined => (Array.isArray(ruleIndexRaw) ? ruleIndexRaw : undefined), + [ruleIndexRaw] + ); + const ruleDataViewIdRaw = useMemo( + () => + find({ category: 'signal', field: 'signal.rule.data_view_id' }, detailsData)?.values ?? + find( + { category: 'kibana', field: 'kibana.alert.rule.parameters.data_view_id' }, + detailsData + )?.values, + [detailsData] + ); + const ruleDataViewId = useMemo( + (): string | undefined => + Array.isArray(ruleDataViewIdRaw) ? ruleDataViewIdRaw[0] : undefined, + [ruleDataViewIdRaw] + ); const addExceptionModalWrapperData = useMemo( () => @@ -102,12 +120,11 @@ export const FlyoutFooterComponent = React.memo( const { exceptionFlyoutType, + openAddExceptionFlyout, onAddExceptionTypeClick, onAddExceptionCancel, onAddExceptionConfirm, - ruleIndices, } = useExceptionFlyout({ - ruleIndex, refetch: refetchAll, isActiveTimelines: isActiveTimeline(scopeId), }); @@ -154,12 +171,13 @@ export const FlyoutFooterComponent = React.memo( {/* This is still wrong to do render flyout/modal inside of the flyout We need to completely refactor the EventDetails component to be correct */} - {exceptionFlyoutType != null && + {openAddExceptionFlyout && addExceptionModalWrapperData.ruleId != null && addExceptionModalWrapperData.eventId != null && ( ({ useCreateFieldButton: () => <>, })); -describe('Body', () => { +// SKIP: https://github.com/elastic/kibana/issues/143718 +describe.skip('Body', () => { const mount = useMountAppended(); const mockRefetch = jest.fn(); let appToastsMock: jest.Mocked>; diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.test.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.test.ts index 0d74241ed88bc..3f71bb099ed63 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.test.ts @@ -9,7 +9,7 @@ import * as api from './api'; import { KibanaServices } from '../../common/lib/kibana'; import { TimelineType, TimelineStatus } from '../../../common/types/timeline'; import { TIMELINE_DRAFT_URL, TIMELINE_URL } from '../../../common/constants'; -import type { ImportDataProps } from '../../detections/containers/detection_engine/rules/types'; +import type { ImportDataProps } from '../../detection_engine/rule_management/logic/types'; jest.mock('../../common/lib/kibana', () => { return { diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index cdabd37b443fe..f81910ff8013e 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -49,7 +49,7 @@ import type { ExportDocumentsProps, ImportDataProps, ImportDataResponse, -} from '../../detections/containers/detection_engine/rules'; +} from '../../detection_engine/rule_management/logic'; import type { TimelineInput } from '../../../common/search_strategy'; interface RequestPostTimeline { diff --git a/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx index a4b82b47b9484..e7df8a7678084 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; @@ -18,7 +18,6 @@ import { AnomaliesQueryTabBody } from '../../../common/containers/anomalies/anom import { usersDetailsPagePath } from '../constants'; import { TableId } from '../../../../common/types'; import { EventsQueryTabBody } from '../../../common/components/events_tab'; -import { userNameExistsFilter } from './helpers'; import { AuthenticationsQueryTabBody } from '../navigation'; export const UsersDetailsTabs = React.memo( @@ -32,7 +31,7 @@ export const UsersDetailsTabs = React.memo( to, type, detailName, - pageFilters = [], + userDetailFilter, }) => { const tabProps = { deleteQuery, @@ -46,11 +45,6 @@ export const UsersDetailsTabs = React.memo( userName: detailName, }; - const externalAlertPageFilters = useMemo( - () => [...userNameExistsFilter, ...pageFilters], - [pageFilters] - ); - return ( @@ -61,10 +55,9 @@ export const UsersDetailsTabs = React.memo( diff --git a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx index a1491fc2e5a01..e2c6fff56eda4 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx @@ -83,7 +83,7 @@ const UsersDetailsComponent: React.FC = ({ ); const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); const query = useDeepEqualSelector(getGlobalQuerySelector); - const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const globalFilters = useDeepEqualSelector(getGlobalFiltersQuerySelector); const { signalIndexName } = useSignalIndex(); const { hasKibanaREAD, hasIndexRead } = useAlertsPrivileges(); @@ -109,14 +109,14 @@ const UsersDetailsComponent: React.FC = ({ buildEsQuery( indexPattern, [query], - [...usersDetailsPageFilters, ...filters], + [...usersDetailsPageFilters, ...globalFilters], getEsQueryConfig(uiSettings) ), ]; } catch (e) { return [undefined, e]; } - }, [filters, indexPattern, query, uiSettings, usersDetailsPageFilters]); + }, [globalFilters, indexPattern, query, uiSettings, usersDetailsPageFilters]); const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery); useInvalidFilterQuery({ @@ -251,7 +251,7 @@ const UsersDetailsComponent: React.FC = ({ indexNames={selectedPatterns} indexPattern={indexPattern} isInitializing={isInitializing} - pageFilters={usersDetailsPageFilters} + userDetailFilter={usersDetailsPageFilters} setQuery={setQuery} to={to} type={type} diff --git a/x-pack/plugins/security_solution/public/users/pages/details/types.ts b/x-pack/plugins/security_solution/public/users/pages/details/types.ts index d3fc93b14b88b..139b268132578 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/types.ts +++ b/x-pack/plugins/security_solution/public/users/pages/details/types.ts @@ -45,7 +45,7 @@ export type UsersDetailsNavTab = Partial>; export type UsersDetailsTabsProps = UserBodyComponentDispatchProps & UsersQueryProps & { indexNames: string[]; - pageFilters?: Filter[]; + userDetailFilter: Filter[]; filterQuery?: string; indexPattern: DataViewBase; type: usersModel.UsersType; diff --git a/x-pack/plugins/security_solution/public/users/pages/types.ts b/x-pack/plugins/security_solution/public/users/pages/types.ts index 955b565b328a8..e3a55417451c4 100644 --- a/x-pack/plugins/security_solution/public/users/pages/types.ts +++ b/x-pack/plugins/security_solution/public/users/pages/types.ts @@ -5,14 +5,12 @@ * 2.0. */ -import type { Filter } from '@kbn/es-query'; import type { GlobalTimeArgs } from '../../common/containers/use_global_time'; import type { usersModel } from '../store'; export type UsersTabsProps = GlobalTimeArgs & { - filterQuery: string; - pageFilters?: Filter[]; + filterQuery?: string; indexNames: string[]; type: usersModel.UsersType; }; diff --git a/x-pack/plugins/security_solution/public/users/pages/users.tsx b/x-pack/plugins/security_solution/public/users/pages/users.tsx index df5b891c24e8d..7de9f603b0efe 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users.tsx @@ -74,7 +74,7 @@ const UsersComponent = () => { ); const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); const query = useDeepEqualSelector(getGlobalQuerySelector); - const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + const globalFilters = useDeepEqualSelector(getGlobalFiltersQuerySelector); const getUserRiskScoreFilterQuerySelector = useMemo( () => usersSelectors.userRiskScoreSeverityFilterSelector(), @@ -91,27 +91,27 @@ const UsersComponent = () => { const { tabName } = useParams<{ tabName: string }>(); const tabsFilters: Filter[] = React.useMemo(() => { if (tabName === UsersTableType.events) { - return filters.length > 0 ? [...filters, ...userNameExistsFilter] : userNameExistsFilter; + return [...globalFilters, ...userNameExistsFilter]; } if (tabName === UsersTableType.risk) { const severityFilter = generateSeverityFilter(severitySelection, RiskScoreEntity.user); - return [...severityFilter, ...filters]; + return [...severityFilter, ...globalFilters]; } - return filters; - }, [severitySelection, tabName, filters]); + return globalFilters; + }, [severitySelection, tabName, globalFilters]); const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); - const [filterQuery, kqlError] = useMemo( + const [globalFiltersQuery, kqlError] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), indexPattern, queries: [query], - filters, + filters: globalFilters, }), - [filters, indexPattern, uiSettings, query] + [globalFilters, indexPattern, uiSettings, query] ); const [tabsFilterQuery] = useMemo( () => @@ -124,7 +124,14 @@ const UsersComponent = () => { [indexPattern, query, tabsFilters, uiSettings] ); - useInvalidFilterQuery({ id: ID, filterQuery, kqlError, query, startDate: from, endDate: to }); + useInvalidFilterQuery({ + id: ID, + filterQuery: globalFiltersQuery, + kqlError, + query, + startDate: from, + endDate: to, + }); const onSkipFocusBeforeEventsTable = useCallback(() => { containerElement.current @@ -193,12 +200,12 @@ const UsersComponent = () => { /> @@ -210,14 +217,13 @@ const UsersComponent = () => { diff --git a/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx b/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx index a0229ccbe1c8c..510d6d1fc9c04 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx @@ -18,20 +18,11 @@ import { AnomaliesUserTable } from '../../common/components/ml/tables/anomalies_ import { UserRiskScoreQueryTabBody } from './navigation/user_risk_score_tab_body'; import { EventsQueryTabBody } from '../../common/components/events_tab'; +import { userNameExistsFilter } from './details/helpers'; import { TableId } from '../../../common/types'; export const UsersTabs = memo( - ({ - deleteQuery, - filterQuery, - pageFilters, - from, - indexNames, - isInitializing, - setQuery, - to, - type, - }) => { + ({ deleteQuery, filterQuery, from, indexNames, isInitializing, setQuery, to, type }) => { const tabProps = { deleteQuery, endDate: to, @@ -59,9 +50,9 @@ export const UsersTabs = memo( diff --git a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/constants.ts b/x-pack/plugins/security_solution/scripts/endpoint/action_responder/constants.ts deleted file mode 100644 index 23c3292da66e7..0000000000000 --- a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/constants.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. - */ - -export const HORIZONTAL_LINE = '-'.repeat(80); - -export const SUPPORTED_TOKENS = `The following tokens can be used in the Action request 'comment' to drive - the type of response that is sent: - Token Description - --------------------------- ------------------------------------------------------- - RESPOND.STATE=SUCCESS Will ensure the Endpoint Action response is success - RESPOND.STATE=FAILURE Will ensure the Endpoint Action response is a failure - RESPOND.FLEET.STATE=SUCCESS Will ensure the Fleet Action response is success - RESPOND.FLEET.STATE=FAILURE Will ensure the Fleet Action response is a failure - -`; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/action_responder/index.ts deleted file mode 100644 index ae73a3a978d21..0000000000000 --- a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/index.ts +++ /dev/null @@ -1,68 +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 { RunContext } from '@kbn/dev-cli-runner'; -import { run } from '@kbn/dev-cli-runner'; -import { HORIZONTAL_LINE, SUPPORTED_TOKENS } from './constants'; -import { runInAutoMode } from './run_in_auto_mode'; - -export const cli = () => { - run( - async (context: RunContext) => { - context.log.write(` -${HORIZONTAL_LINE} - Endpoint Action Responder -${HORIZONTAL_LINE} -`); - if (context.flags.mode === 'auto') { - return runInAutoMode(context); - } - - context.log.warning(`exiting... Nothing to do. use '--help' to see list of options`); - - context.log.write(` -${HORIZONTAL_LINE} -`); - }, - - { - description: `Respond to pending Endpoint actions. - ${SUPPORTED_TOKENS}`, - flags: { - string: ['mode', 'kibana', 'elastic', 'username', 'password', 'delay'], - boolean: ['asSuperuser'], - default: { - mode: 'auto', - kibana: 'http://localhost:5601', - elastic: 'http://localhost:9200', - username: 'elastic', - password: 'changeme', - asSuperuser: false, - delay: '', - }, - help: ` - --mode The mode for running the tool. (Default: 'auto'). - Value values are: - auto : tool will continue to run and checking for pending - actions periodically. - --username User name to be used for auth against elasticsearch and - kibana (Default: elastic). - **IMPORTANT:** This username's roles MUST have 'superuser'] - and 'kibana_system' roles - --password User name Password (Default: changeme) - --asSuperuser If defined, then a Security super user will be created using the - the credentials defined via 'username' and 'password' options. This - new user will then be used to run this utility. - --delay The delay (in milliseconds) that should be applied before responding - to an action. (Default: 40000 (40s)) - --kibana The url to Kibana (Default: http://localhost:5601) - --elastic The url to Elasticsearch (Default: http:localholst:9200) - `, - }, - } - ); -}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/run_in_auto_mode.ts b/x-pack/plugins/security_solution/scripts/endpoint/action_responder/run_in_auto_mode.ts deleted file mode 100644 index 8e93cf7625b73..0000000000000 --- a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/run_in_auto_mode.ts +++ /dev/null @@ -1,131 +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 { RunContext } from '@kbn/dev-cli-runner'; -import { set } from 'lodash'; -import { SUPPORTED_TOKENS } from './constants'; -import type { ActionDetails } from '../../../common/endpoint/types'; -import type { RuntimeServices } from '../common/stack_services'; -import { createRuntimeServices } from '../common/stack_services'; - -import { - fetchEndpointActionList, - sendEndpointActionResponse, - sendFleetActionResponse, - sleep, -} from './utils'; - -const ACTION_RESPONSE_DELAY = 40_000; - -export const runInAutoMode = async ({ - log, - flags: { username, password, asSuperuser, kibana, elastic, delay: _delay }, -}: RunContext) => { - const runtimeServices = await createRuntimeServices({ - log, - password: password as string, - username: username as string, - asSuperuser: asSuperuser as boolean, - elasticsearchUrl: elastic as string, - kibanaUrl: kibana as string, - }); - - log.write(` ${SUPPORTED_TOKENS}`); - - const delay = Number(_delay) || ACTION_RESPONSE_DELAY; - - do { - await checkPendingActionsAndRespond(runtimeServices, { delay }); - await sleep(5_000); - } while (true); -}; - -const checkPendingActionsAndRespond = async ( - { kbnClient, esClient, log }: RuntimeServices, - { delay = ACTION_RESPONSE_DELAY }: { delay?: number } = {} -) => { - let hasMore = true; - let nextPage = 1; - - try { - while (hasMore) { - const { data: actions } = await fetchEndpointActionList(kbnClient, { - page: nextPage++, - pageSize: 100, - }); - - if (actions.length === 0) { - hasMore = false; - } - - for (const action of actions) { - if (action.isCompleted === false) { - if (Date.now() - new Date(action.startedAt).getTime() >= delay) { - log.info( - `[${new Date().toLocaleTimeString()}]: Responding to [${ - action.command - }] action [id: ${action.id}] agent: [${action.agents.join(', ')}]` - ); - - const tokens = parseCommentTokens(getActionComment(action)); - - log.verbose('tokens found in action:', tokens); - - const fleetResponse = await sendFleetActionResponse(esClient, action, { - // If an Endpoint state token was found, then force the Fleet response to `success` - // so that we can actually generate an endpoint response below. - state: tokens.state ? 'success' : tokens.fleet.state, - }); - - // If not a fleet response error, then also sent the Endpoint Response - if (!fleetResponse.error) { - await sendEndpointActionResponse(esClient, action, { state: tokens.state }); - } - } - } - } - } - } catch (e) { - log.error(`${e.message}. Run with '--verbose' option to see more`); - log.verbose(e); - } -}; - -interface CommentTokens { - state: 'success' | 'failure' | undefined; - fleet: { - state: 'success' | 'failure' | undefined; - }; -} - -const parseCommentTokens = (comment: string): CommentTokens => { - const response: CommentTokens = { - state: undefined, - fleet: { - state: undefined, - }, - }; - - if (comment) { - const findTokensRegExp = /(respond\.\S*=\S*)/gi; - let matches; - - while ((matches = findTokensRegExp.exec(comment)) !== null) { - const [key, value] = matches[0] - .toLowerCase() - .split('=') - .map((s) => s.trim()); - - set(response, key.split('.').slice(1), value); - } - } - return response; -}; - -const getActionComment = (action: ActionDetails): string => { - return action.comment ?? ''; -}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/agent_emulator.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/agent_emulator.ts new file mode 100644 index 0000000000000..637befd89e2f0 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/agent_emulator.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RunFn } from '@kbn/dev-cli-runner'; +import { MainScreen } from './screens/main'; +import { loadEndpointsIfNoneExist } from './services/endpoint_loader'; +import { EmulatorRunContext } from './services/emulator_run_context'; + +export const DEFAULT_CHECKIN_INTERVAL = 60_000; // 1m +export const DEFAULT_ACTION_DELAY = 5_000; // 5s + +export const agentEmulatorRunner: RunFn = async (cliContext) => { + const actionResponseDelay = Number(cliContext.flags.actionDelay) || DEFAULT_ACTION_DELAY; + const checkinInterval = Number(cliContext.flags.checkinInterval) || DEFAULT_CHECKIN_INTERVAL; + + const emulatorContext = new EmulatorRunContext({ + username: cliContext.flags.username as string, + password: cliContext.flags.password as string, + kibanaUrl: cliContext.flags.kibana as string, + elasticsearchUrl: cliContext.flags.elasticsearch as string, + asSuperuser: cliContext.flags.asSuperuser as boolean, + log: cliContext.log, + actionResponseDelay, + checkinInterval, + }); + await emulatorContext.start(); + + loadEndpointsIfNoneExist( + emulatorContext.getEsClient(), + emulatorContext.getKbnClient(), + emulatorContext.getLogger() + ); + + await new MainScreen(emulatorContext).show(); + + await emulatorContext.stop(); +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/constants.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/constants.ts new file mode 100644 index 0000000000000..50b825136532f --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/constants.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export const TOOL_TITLE = 'Endpoint Agent Emulator' as const; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/index.ts new file mode 100644 index 0000000000000..5daba7f613fa9 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/index.ts @@ -0,0 +1,52 @@ +/* + * 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 { run } from '@kbn/dev-cli-runner'; +import { agentEmulatorRunner } from './agent_emulator'; + +const DEFAULT_CHECKIN_INTERVAL = 60_000; // 1m +const DEFAULT_ACTION_DELAY = 5_000; // 5s + +export const cli = () => { + run( + agentEmulatorRunner, + + // Options + { + description: `Endpoint agent emulator.`, + flags: { + string: ['kibana', 'elastic', 'username', 'password'], + boolean: ['asSuperuser'], + default: { + kibana: 'http://localhost:5601', + elasticsearch: 'http://localhost:9200', + username: 'elastic', + password: 'changeme', + asSuperuser: false, + actionDelay: DEFAULT_ACTION_DELAY, + checkinInterval: DEFAULT_CHECKIN_INTERVAL, + }, + help: ` + --username User name to be used for auth against elasticsearch and + kibana (Default: elastic). + **IMPORTANT:** if 'asSuperuser' option is not used, then the + user defined here MUST have 'superuser' AND 'kibana_system' roles + --password User name Password (Default: changeme) + --asSuperuser If defined, then a Security super user will be created using the + the credentials defined via 'username' and 'password' options. This + new user will then be used to run this utility. + --kibana The url to Kibana (Default: http://localhost:5601) + --elasticsearch The url to Elasticsearch (Default: http://localhost:9200) + --checkinInterval The interval between how often the Agent is checked into fleet and a + metadata document update is sent for the endpoint. Default is 1 minute + --actionDelay The delay (in milliseconds) that should be applied before responding + to an action. (Default: 5000 (5s)) + `, + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/actions_responder.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/actions_responder.ts new file mode 100644 index 0000000000000..448f8907986fc --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/actions_responder.ts @@ -0,0 +1,71 @@ +/* + * 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 { blue } from 'chalk'; +import { HORIZONTAL_LINE } from '../../common/constants'; +import { RunServiceStatus } from './components/run_service_status_formatter'; +import { ColumnLayoutFormatter } from '../../common/screen/column_layout_formatter'; +import { TOOL_TITLE } from '../constants'; +import type { EmulatorRunContext } from '../services/emulator_run_context'; +import type { DataFormatter } from '../../common/screen'; +import { ChoiceMenuFormatter, ScreenBaseClass } from '../../common/screen'; + +export class ActionResponderScreen extends ScreenBaseClass { + constructor(private readonly emulatorContext: EmulatorRunContext) { + super(); + } + + protected header() { + return super.header(TOOL_TITLE, 'Actions Responder'); + } + + protected body(): string | DataFormatter { + const isServiceRunning = this.emulatorContext.getActionResponderService().isRunning; + const actionsAndStatus = new ColumnLayoutFormatter([ + new ChoiceMenuFormatter([isServiceRunning ? 'Stop Service' : 'Start Service']), + `Status: ${new RunServiceStatus(isServiceRunning).output}`, + ]); + + return `Service checks for new Endpoint Actions and automatically responds to them. + The following tokens can be used in the Action request 'comment' to drive + the type of response that is sent: + Token Description + --------------------------- ------------------------------------ + RESPOND.STATE=SUCCESS Respond with success + RESPOND.STATE=FAILURE Respond with failure + RESPOND.FLEET.STATE=SUCCESS Respond to Fleet Action with success + RESPOND.FLEET.STATE=FAILURE Respond to Fleet Action with failure + +${blue(HORIZONTAL_LINE.substring(0, HORIZONTAL_LINE.length - 2))} + ${actionsAndStatus.output}`; + } + + protected onEnterChoice(choice: string) { + const choiceValue = choice.trim().toUpperCase(); + + switch (choiceValue) { + case 'Q': + this.hide(); + return; + + case '1': + { + const actionsResponderService = this.emulatorContext.getActionResponderService(); + const isRunning = actionsResponderService.isRunning; + if (isRunning) { + actionsResponderService.stop(); + } else { + actionsResponderService.start(); + } + } + this.reRender(); + return; + } + + this.throwUnknownChoiceError(choice); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/components/run_service_status_formatter.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/components/run_service_status_formatter.ts new file mode 100644 index 0000000000000..273c323e56e40 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/components/run_service_status_formatter.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { bgCyan, red, dim } from 'chalk'; +import type { BaseRunningService } from '../../../common/base_running_service'; +import { DataFormatter } from '../../../common/screen'; + +export class RunServiceStatus extends DataFormatter { + constructor(private readonly serviceOrIsRunning: boolean | BaseRunningService) { + super(); + } + + protected getOutput(): string { + const isRunning = + typeof this.serviceOrIsRunning === 'boolean' + ? this.serviceOrIsRunning + : this.serviceOrIsRunning.isRunning; + + if (isRunning) { + return bgCyan(' Running '); + } + + return dim(red(' Stopped ')); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/load_endpoints.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/load_endpoints.ts new file mode 100644 index 0000000000000..894a668b6fb72 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/load_endpoints.ts @@ -0,0 +1,224 @@ +/* + * 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. + */ + +/* eslint-disable require-atomic-updates */ + +import { blue, green } from 'chalk'; +import type { DistinctQuestion } from 'inquirer'; +import type { LoadEndpointsConfig } from '../types'; +import { loadEndpoints } from '../services/endpoint_loader'; +import type { EmulatorRunContext } from '../services/emulator_run_context'; +import { ProgressFormatter } from '../../common/screen/progress_formatter'; +import type { DataFormatter } from '../../common/screen'; +import { ChoiceMenuFormatter, ScreenBaseClass } from '../../common/screen'; +import { TOOL_TITLE } from '../constants'; + +interface LoadOptions { + count: number; + progress: ProgressFormatter; + isRunning: boolean; + isDone: boolean; +} + +const promptQuestion = ( + options: DistinctQuestion +): DistinctQuestion => { + const question: DistinctQuestion = { + type: 'input', + name: 'Unknown?', + message: 'Unknown?', + // @ts-expect-error unclear why this is not defined in the definition file + askAnswered: true, + prefix: green(' ==> '), + ...options, + }; + + if (question.default === undefined) { + question.default = (answers: TAnswers) => { + return answers[(question.name ?? '-') as keyof TAnswers] ?? ''; + }; + } + + return question; +}; + +export class LoadEndpointsScreen extends ScreenBaseClass { + private runInfo: LoadOptions | undefined = undefined; + private choices: ChoiceMenuFormatter = new ChoiceMenuFormatter([ + { + title: 'Run', + key: '1', + }, + { + title: 'Configure', + key: '2', + }, + ]); + private config: LoadEndpointsConfig = { count: 2 }; + + constructor(private readonly emulatorContext: EmulatorRunContext) { + super(); + } + + private async loadSettings(): Promise { + const allSettings = await this.emulatorContext.getSettingsService().get(); + + this.config = allSettings.endpointLoader; + } + + private async saveSettings(): Promise { + const settingsService = this.emulatorContext.getSettingsService(); + + const allSettings = await settingsService.get(); + await settingsService.save({ + ...allSettings, + endpointLoader: this.config, + }); + } + + protected header() { + return super.header(TOOL_TITLE, 'Endpoint loader'); + } + + protected body(): string | DataFormatter { + if (this.runInfo) { + if (this.runInfo.isDone) { + return this.doneView(); + } + + return this.loadingView(); + } + + return this.mainView(); + } + + protected onEnterChoice(choice: string) { + const choiceValue = choice.trim().toUpperCase(); + + switch (choiceValue) { + case 'Q': + this.hide(); + return; + + case '1': + this.runInfo = { + count: this.config.count, + progress: new ProgressFormatter(), + isRunning: false, + isDone: false, + }; + + this.reRender(); + this.loadEndpoints(); + return; + + case '2': + this.configView(); + return; + + default: + if (!choiceValue) { + if (this.runInfo?.isDone) { + this.runInfo = undefined; + this.reRender(); + return; + } + } + + this.throwUnknownChoiceError(choice); + } + } + + private async configView() { + this.config = await this.prompt({ + questions: [ + promptQuestion({ + type: 'number', + name: 'count', + message: 'How many endpoints to load?', + validate(input: number, answers): boolean | string { + if (!Number.isFinite(input)) { + return 'Enter valid number'; + } + return true; + }, + filter(input: number): number | string { + if (Number.isNaN(input)) { + return ''; + } + return input; + }, + }), + ], + answers: this.config, + title: blue('Endpoint Loader Settings'), + }); + + await this.saveSettings(); + this.reRender(); + } + + private async loadEndpoints() { + const runInfo = this.runInfo; + + if (runInfo && !runInfo.isDone && !runInfo.isRunning) { + runInfo.isRunning = true; + + await loadEndpoints({ + count: runInfo.count, + esClient: this.emulatorContext.getEsClient(), + kbnClient: this.emulatorContext.getKbnClient(), + log: this.emulatorContext.getLogger(), + onProgress: (progress) => { + runInfo.progress.setProgress(progress.percent); + this.reRender(); + }, + }); + + runInfo.isDone = true; + runInfo.isRunning = false; + this.reRender(); + } + } + + private mainView(): string | DataFormatter { + return ` + Generate and load endpoints into elasticsearch along with associated + fleet agents. Current settings: + + Count: ${this.config.count} + + Options: + ${this.choices.output}`; + } + + private loadingView(): string | DataFormatter { + if (this.runInfo) { + return ` + + Creating ${this.runInfo.count} endpoint(s): + + ${this.runInfo.progress.output} +`; + } + + return 'Unknown state'; + } + + private doneView(): string { + return `${this.loadingView()} + + Done. Endpoint(s) have been loaded into Elastic/Kibana. + Press Enter to continue +`; + } + + async show(options: Partial<{ prompt: string; resume: boolean }> = {}): Promise { + await this.loadSettings(); + return super.show(options); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/main.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/main.ts new file mode 100644 index 0000000000000..0c8722be6706a --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/screens/main.ts @@ -0,0 +1,98 @@ +/* + * 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 { ActionResponderScreen } from './actions_responder'; +import { SCREEN_ROW_MAX_WIDTH } from '../../common/screen/constants'; +import { ColumnLayoutFormatter } from '../../common/screen/column_layout_formatter'; +import type { EmulatorRunContext } from '../services/emulator_run_context'; +import { LoadEndpointsScreen } from './load_endpoints'; +import { TOOL_TITLE } from '../constants'; +import { ScreenBaseClass, ChoiceMenuFormatter } from '../../common/screen'; +import type { DataFormatter } from '../../common/screen/data_formatter'; +import { RunServiceStatus } from './components/run_service_status_formatter'; + +export class MainScreen extends ScreenBaseClass { + private readonly loadEndpointsScreen: LoadEndpointsScreen; + private readonly actionsResponderScreen: ActionResponderScreen; + + private actionColumnWidthPrc = 30; + private runningStateColumnWidthPrc = 70; + + constructor(private readonly emulatorContext: EmulatorRunContext) { + super(); + this.loadEndpointsScreen = new LoadEndpointsScreen(this.emulatorContext); + this.actionsResponderScreen = new ActionResponderScreen(this.emulatorContext); + } + + protected header(title: string = '', subTitle: string = ''): string | DataFormatter { + return super.header(TOOL_TITLE); + } + + protected body(): string | DataFormatter { + return `\n${ + new ColumnLayoutFormatter([this.getMenuOptions(), this.runStateView()], { + widths: [this.actionColumnWidthPrc, this.runningStateColumnWidthPrc], + }).output + }`; + } + + private getMenuOptions(): ChoiceMenuFormatter { + return new ChoiceMenuFormatter(['Load endpoints', 'Actions Responder']); + } + + private runStateView(): ColumnLayoutFormatter { + const context = this.emulatorContext; + + return new ColumnLayoutFormatter( + [ + ['Agent Keep Alive Service', 'Actions Responder Service'].join('\n'), + [ + new RunServiceStatus(context.getAgentKeepAliveService()).output, + new RunServiceStatus(context.getActionResponderService()).output, + ].join('\n'), + ], + { + rowLength: Math.floor(SCREEN_ROW_MAX_WIDTH * (this.runningStateColumnWidthPrc / 100)), + separator: ': ', + widths: [70, 30], + } + ); + } + + protected footer(): string | DataFormatter { + return super.footer([ + { + key: 'E', + title: 'Exit', + }, + ]); + } + + protected onEnterChoice(choice: string) { + switch (choice.toUpperCase().trim()) { + // Load endpoints + case '1': + this.pause(); + this.loadEndpointsScreen.show({ resume: true }).then(() => { + this.show({ resume: true }); + }); + return; + + case '2': + this.pause(); + this.actionsResponderScreen.show({ resume: true }).then(() => { + this.show({ resume: true }); + }); + return; + case 'E': + this.hide(); + return; + } + + this.throwUnknownChoiceError(choice); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/action_responder.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/action_responder.ts new file mode 100644 index 0000000000000..93816e06bb7fb --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/action_responder.ts @@ -0,0 +1,122 @@ +/* + * 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 { set } from 'lodash'; +import type { Client } from '@elastic/elasticsearch'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type { KbnClient } from '@kbn/test'; +import { BaseRunningService } from '../../common/base_running_service'; +import { + fetchEndpointActionList, + sendEndpointActionResponse, + sendFleetActionResponse, +} from './endpoint_response_actions'; +import type { ActionDetails } from '../../../../common/endpoint/types'; + +/** + * Base class for start/stopping background services + */ +export class ActionResponderService extends BaseRunningService { + private readonly delay: number; + + constructor( + esClient: Client, + kbnClient: KbnClient, + logger?: ToolingLog, + intervalMs?: number, + delay: number = 5_000 // 5s + ) { + super(esClient, kbnClient, logger, intervalMs); + this.delay = delay; + } + + protected async run(): Promise { + const { logger: log, kbnClient, esClient, delay } = this; + + let hasMore = true; + let nextPage = 1; + + try { + while (hasMore) { + const { data: actions } = await fetchEndpointActionList(kbnClient, { + page: nextPage++, + pageSize: 100, + }); + + if (actions.length === 0) { + hasMore = false; + return; + } + + for (const action of actions) { + if (action.isCompleted === false) { + if (Date.now() - new Date(action.startedAt).getTime() >= delay) { + log.verbose( + `${this.logPrefix}.run() [${new Date().toLocaleTimeString()}]: Responding to [${ + action.command + }] action [id: ${action.id}] agent: [${action.agents.join(', ')}]` + ); + + const tokens = parseCommentTokens(getActionComment(action)); + + log.verbose(`${this.logPrefix}.run() tokens found in action:`, tokens); + + const fleetResponse = await sendFleetActionResponse(esClient, action, { + // If an Endpoint state token was found, then force the Fleet response to `success` + // so that we can actually generate an endpoint response below. + state: tokens.state ? 'success' : tokens.fleet.state, + }); + + // If not a fleet response error, then also sent the Endpoint Response + if (!fleetResponse.error) { + await sendEndpointActionResponse(esClient, action, { state: tokens.state }); + } + } + } + } + } + } catch (e) { + log.error(`${this.logPrefix}.run() ${e.message}. Run with '--verbose' option to see more`); + log.verbose(e); + } + } +} + +interface CommentTokens { + state: 'success' | 'failure' | undefined; + fleet: { + state: 'success' | 'failure' | undefined; + }; +} + +const parseCommentTokens = (comment: string): CommentTokens => { + const response: CommentTokens = { + state: undefined, + fleet: { + state: undefined, + }, + }; + + if (comment) { + const findTokensRegExp = /(respond\.\S*=\S*)/gi; + let matches; + + while ((matches = findTokensRegExp.exec(comment)) !== null) { + const [key, value] = matches[0] + .toLowerCase() + .split('=') + .map((s) => s.trim()); + + set(response, key.split('.').slice(1), value); + } + } + return response; +}; + +const getActionComment = (action: ActionDetails): string => { + return action.comment ?? ''; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/agent_keep_alive.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/agent_keep_alive.ts new file mode 100644 index 0000000000000..1d0a94df9e7af --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/agent_keep_alive.ts @@ -0,0 +1,71 @@ +/* + * 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 { checkInFleetAgent } from '../../common/fleet_services'; +import { + fetchEndpointMetadataList, + sendEndpointMetadataUpdate, +} from '../../common/endpoint_metadata_services'; +import { BaseRunningService } from '../../common/base_running_service'; + +export class AgentKeepAliveService extends BaseRunningService { + protected async run(): Promise { + const { logger: log, kbnClient, esClient } = this; + + let hasMore = true; + let page = 0; + let errorFound = 0; + + try { + do { + const endpoints = await fetchEndpointMetadataList(kbnClient, { + page: page++, + pageSize: 100, + }); + + if (endpoints.data.length === 0) { + hasMore = false; + } else { + if (endpoints.page === 0) { + log.verbose( + `${this.logPrefix}.run() Number of endpoints to process: ${endpoints.total}` + ); + } + + for (const endpoint of endpoints.data) { + await Promise.all([ + checkInFleetAgent(esClient, endpoint.metadata.elastic.agent.id, { + log, + }).catch((err) => { + log.verbose(err); + errorFound++; + return Promise.resolve(); + }), + sendEndpointMetadataUpdate(esClient, endpoint.metadata.agent.id).catch((err) => { + log.verbose(err); + errorFound++; + return Promise.resolve(); + }), + ]); + } + } + } while (hasMore); + } catch (err) { + log.error( + `${this.logPrefix}.run() Error: ${err.message}. Use the '--verbose' option to see more.` + ); + + log.verbose(err); + } + + if (errorFound > 0) { + log.error( + `${this.logPrefix}.run() Error: Encountered ${errorFound} error(s). Use the '--verbose' option to see more.` + ); + } + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/emulator_run_context.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/emulator_run_context.ts new file mode 100644 index 0000000000000..3c4978cd4447c --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/emulator_run_context.ts @@ -0,0 +1,155 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/no-non-null-assertion */ + +import type { KbnClient } from '@kbn/test'; +import type { Client } from '@elastic/elasticsearch'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type { AgentEmulatorSettings } from '../types'; +import { SettingsStorage } from '../../common/settings_storage'; +import { AgentKeepAliveService } from './agent_keep_alive'; +import { ActionResponderService } from './action_responder'; +import { createRuntimeServices } from '../../common/stack_services'; + +export interface EmulatorRunContextConstructorOptions { + username: string; + password: string; + kibanaUrl: string; + elasticsearchUrl: string; + actionResponseDelay: number; + checkinInterval: number; + asSuperuser?: boolean; + log?: ToolingLog; +} + +export class EmulatorRunContext { + private esClient: Client | undefined = undefined; + private kbnClient: KbnClient | undefined = undefined; + private wasStarted: boolean = false; + private agentKeepAliveService: AgentKeepAliveService | undefined = undefined; + private actionResponderService: ActionResponderService | undefined = undefined; + + private readonly username: string; + private readonly password: string; + private readonly kibanaUrl: string; + private readonly elasticsearchUrl: string; + private readonly actionResponseDelay: number; + private readonly checkinInterval: number; + private readonly asSuperuser: boolean = false; + private log: ToolingLog | undefined = undefined; + private settings: SettingsStorage | undefined = undefined; + + constructor(options: EmulatorRunContextConstructorOptions) { + this.username = options.username; + this.password = options.password; + this.kibanaUrl = options.kibanaUrl; + this.elasticsearchUrl = options.elasticsearchUrl; + this.actionResponseDelay = options.actionResponseDelay; + this.checkinInterval = options.checkinInterval; + this.asSuperuser = options.asSuperuser ?? false; + this.log = options.log; + } + + async start() { + if (this.wasStarted) { + return; + } + + this.settings = new SettingsStorage('endpoint_agent_emulator.json', { + defaultSettings: { + version: 1, + endpointLoader: { + count: 2, + }, + }, + }); + + const { esClient, kbnClient, log } = await createRuntimeServices({ + kibanaUrl: this.kibanaUrl, + elasticsearchUrl: this.elasticsearchUrl, + username: this.username, + password: this.password, + asSuperuser: this.asSuperuser, + log: this.log, + }); + + this.esClient = esClient; + this.kbnClient = kbnClient; + this.log = log; + + this.agentKeepAliveService = new AgentKeepAliveService( + esClient, + kbnClient, + log, + this.checkinInterval + ); + this.agentKeepAliveService.start(); + + this.actionResponderService = new ActionResponderService( + esClient, + kbnClient, + log, + 5_000, // Check for actions every 5s + this.actionResponseDelay + ); + this.actionResponderService.start(); + + this.wasStarted = true; + } + + async stop(): Promise { + this.getAgentKeepAliveService().stop(); + this.getActionResponderService().stop(); + this.wasStarted = false; + } + + protected ensureStarted() { + if (!this.wasStarted) { + throw new Error('RunContext instance has not been `.start()`ed!'); + } + } + + public get whileRunning(): Promise { + this.ensureStarted(); + + return Promise.all([ + this.getActionResponderService().whileRunning, + this.getAgentKeepAliveService().whileRunning, + ]).then(() => {}); + } + + getSettingsService(): SettingsStorage { + this.ensureStarted(); + return this.settings!; + } + + getActionResponderService(): ActionResponderService { + this.ensureStarted(); + return this.actionResponderService!; + } + + getAgentKeepAliveService(): AgentKeepAliveService { + this.ensureStarted(); + return this.agentKeepAliveService!; + } + + getEsClient(): Client { + this.ensureStarted(); + return this.esClient!; + } + + getKbnClient(): KbnClient { + this.ensureStarted(); + return this.kbnClient!; + } + + getLogger(): ToolingLog { + this.ensureStarted(); + return this.log!; + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_loader.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_loader.ts new file mode 100644 index 0000000000000..ccf252c4d551a --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_loader.ts @@ -0,0 +1,182 @@ +/* + * 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. + */ + +/* eslint-disable max-classes-per-file */ + +import type { Client } from '@elastic/elasticsearch'; +import type { KbnClient } from '@kbn/test'; +import pMap from 'p-map'; +import type { CreatePackagePolicyResponse } from '@kbn/fleet-plugin/common'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type seedrandom from 'seedrandom'; +import { kibanaPackageJson } from '@kbn/utils'; +import { indexAlerts } from '../../../../common/endpoint/data_loaders/index_alerts'; +import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; +import { fetchEndpointMetadataList } from '../../common/endpoint_metadata_services'; +import { indexEndpointHostDocs } from '../../../../common/endpoint/data_loaders/index_endpoint_hosts'; +import { setupFleetForEndpoint } from '../../../../common/endpoint/data_loaders/setup_fleet_for_endpoint'; +import { enableFleetServerIfNecessary } from '../../../../common/endpoint/data_loaders/index_fleet_server'; +import { fetchEndpointPackageInfo } from '../../common/fleet_services'; +import { METADATA_DATASTREAM } from '../../../../common/endpoint/constants'; +import { EndpointMetadataGenerator } from '../../../../common/endpoint/data_generators/endpoint_metadata_generator'; +import { ENDPOINT_ALERTS_INDEX, ENDPOINT_EVENTS_INDEX } from '../../common/constants'; + +let WAS_FLEET_SETUP_DONE = false; + +const CurrentKibanaVersionDocGenerator = class extends EndpointDocGenerator { + constructor(seedValue: string | seedrandom.prng) { + const MetadataGenerator = class extends EndpointMetadataGenerator { + protected randomVersion(): string { + return kibanaPackageJson.version; + } + }; + + super(seedValue, MetadataGenerator); + } +}; + +export const loadEndpointsIfNoneExist = async ( + esClient: Client, + kbnClient: KbnClient, + log?: ToolingLog, + count: number = 2 +): Promise => { + if (!count || (await fetchEndpointMetadataList(kbnClient, { pageSize: 1 })).total > 0) { + if (log) { + log.verbose('loadEndpointsIfNoneExist(): Endpoints exist. Exiting (nothing was done)'); + } + + return; + } + + return loadEndpoints({ + count: 2, + esClient, + kbnClient, + log, + }); +}; + +interface LoadEndpointsProgress { + percent: number; + total: number; + created: number; +} + +interface LoadEndpointsOptions { + esClient: Client; + kbnClient: KbnClient; + count?: number; + log?: ToolingLog; + onProgress?: (percentDone: LoadEndpointsProgress) => void; + DocGeneratorClass?: typeof EndpointDocGenerator; +} + +/** + * Loads endpoints, including the corresponding fleet agent, into Kibana along with events and alerts + * + * @param count + * @param esClient + * @param kbnClient + * @param log + * @param onProgress + * @param DocGeneratorClass + */ +export const loadEndpoints = async ({ + esClient, + kbnClient, + log, + onProgress, + count = 2, + DocGeneratorClass = CurrentKibanaVersionDocGenerator, +}: LoadEndpointsOptions): Promise => { + if (log) { + log.verbose(`loadEndpoints(): Loading ${count} endpoints...`); + } + + if (!WAS_FLEET_SETUP_DONE) { + await setupFleetForEndpoint(kbnClient); + await enableFleetServerIfNecessary(esClient); + // eslint-disable-next-line require-atomic-updates + WAS_FLEET_SETUP_DONE = true; + } + + const endpointPackage = await fetchEndpointPackageInfo(kbnClient); + const realPolicies: Record = {}; + + let progress: LoadEndpointsProgress = { + total: count, + created: 0, + percent: 0, + }; + + const updateProgress = () => { + const created = progress.created + 1; + progress = { + ...progress, + created, + percent: Math.ceil((created / count) * 100), + }; + + if (onProgress) { + onProgress(progress); + } + }; + + await pMap( + Array.from({ length: count }), + async () => { + const endpointGenerator = new DocGeneratorClass(); + + await indexEndpointHostDocs({ + numDocs: 1, + client: esClient, + kbnClient, + realPolicies, + epmEndpointPackage: endpointPackage, + generator: endpointGenerator, + enrollFleet: true, + metadataIndex: METADATA_DATASTREAM, + policyResponseIndex: 'metrics-endpoint.policy-default', + }); + + await indexAlerts({ + client: esClient, + generator: endpointGenerator, + eventIndex: ENDPOINT_EVENTS_INDEX, + alertIndex: ENDPOINT_ALERTS_INDEX, + numAlerts: 1, + options: { + ancestors: 3, + generations: 3, + children: 3, + relatedEvents: 5, + relatedAlerts: 5, + percentWithRelated: 30, + percentTerminated: 30, + alwaysGenMaxChildrenPerNode: false, + ancestryArraySize: 2, + eventsDataStream: { + type: 'logs', + dataset: 'endpoint.events.process', + namespace: 'default', + }, + alertsDataStream: { type: 'logs', dataset: 'endpoint.alerts', namespace: 'default' }, + }, + }); + + updateProgress(); + }, + { + concurrency: 4, + } + ); + + if (log) { + log.verbose(`loadEndpoints(): ${count} endpoint(s) successfully loaded`); + } +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/utils.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts similarity index 65% rename from x-pack/plugins/security_solution/scripts/endpoint/action_responder/utils.ts rename to x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts index 57c8ecf7f7243..8daeae3a28767 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/action_responder/utils.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts @@ -8,15 +8,18 @@ import type { KbnClient } from '@kbn/test'; import type { Client } from '@elastic/elasticsearch'; import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; -import type { UploadedFile } from '../../../common/endpoint/types/file_storage'; -import { sendEndpointMetadataUpdate } from '../common/endpoint_metadata_services'; -import { FleetActionGenerator } from '../../../common/endpoint/data_generators/fleet_action_generator'; +import * as cborx from 'cbor-x'; +import { getFileDownloadId } from '../../../../common/endpoint/service/response_actions/get_file_download_id'; +import type { UploadedFile } from '../../../../common/endpoint/types/file_storage'; +import { checkInFleetAgent } from '../../common/fleet_services'; +import { sendEndpointMetadataUpdate } from '../../common/endpoint_metadata_services'; +import { FleetActionGenerator } from '../../../../common/endpoint/data_generators/fleet_action_generator'; import { ENDPOINT_ACTION_RESPONSES_INDEX, ENDPOINTS_ACTION_LIST_ROUTE, FILE_STORAGE_DATA_INDEX, FILE_STORAGE_METADATA_INDEX, -} from '../../../common/endpoint/constants'; +} from '../../../../common/endpoint/constants'; import type { ActionDetails, ActionListApiResponse, @@ -26,9 +29,9 @@ import type { GetProcessesActionOutputContent, ResponseActionGetFileOutputContent, ResponseActionGetFileParameters, -} from '../../../common/endpoint/types'; -import type { EndpointActionListRequestQuery } from '../../../common/endpoint/schema/actions'; -import { EndpointActionGenerator } from '../../../common/endpoint/data_generators/endpoint_action_generator'; +} from '../../../../common/endpoint/types'; +import type { EndpointActionListRequestQuery } from '../../../../common/endpoint/schema/actions'; +import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; const ES_INDEX_OPTIONS = { headers: { 'X-elastic-product-origin': 'fleet' } }; @@ -42,13 +45,33 @@ export const fetchEndpointActionList = async ( kbn: KbnClient, options: EndpointActionListRequestQuery = {} ): Promise => { - return ( - await kbn.request({ - method: 'GET', - path: ENDPOINTS_ACTION_LIST_ROUTE, - query: options, - }) - ).data; + try { + return ( + await kbn.request({ + method: 'GET', + path: ENDPOINTS_ACTION_LIST_ROUTE, + query: options, + }) + ).data; + } catch (error) { + // FIXME: remove once the Action List API is fixed (task #5221) + if (error?.response?.status === 404) { + return { + data: [], + total: 0, + page: 1, + pageSize: 10, + startDate: undefined, + elasticAgentIds: undefined, + endDate: undefined, + userIds: undefined, + commands: undefined, + statuses: undefined, + }; + } + + throw error; + } }; export const sendFleetActionResponse = async ( @@ -125,26 +148,34 @@ export const sendEndpointActionResponse = async ( // For isolate, If the response is not an error, then also send a metadata update if (action.command === 'isolate' && !endpointResponse.error) { for (const agentId of action.agents) { - await sendEndpointMetadataUpdate(esClient, agentId, { - Endpoint: { - state: { - isolation: true, + await Promise.all([ + sendEndpointMetadataUpdate(esClient, agentId, { + Endpoint: { + state: { + isolation: true, + }, }, - }, - }); + }), + + checkInFleetAgent(esClient, agentId), + ]); } } // For UnIsolate, if response is not an Error, then also send metadata update if (action.command === 'unisolate' && !endpointResponse.error) { for (const agentId of action.agents) { - await sendEndpointMetadataUpdate(esClient, agentId, { - Endpoint: { - state: { - isolation: false, + await Promise.all([ + sendEndpointMetadataUpdate(esClient, agentId, { + Endpoint: { + state: { + isolation: false, + }, }, - }, - }); + }), + + checkInFleetAgent(esClient, agentId), + ]); } } @@ -153,7 +184,7 @@ export const sendEndpointActionResponse = async ( // Index the file's metadata const fileMeta = await esClient.index({ index: FILE_STORAGE_METADATA_INDEX, - id: `${action.id}.${action.hosts[0]}`, + id: getFileDownloadId(action, action.agents[0]), body: { file: { created: new Date().toISOString(), @@ -171,16 +202,29 @@ export const sendEndpointActionResponse = async ( }); // Index the file content (just one chunk) - await esClient.index({ - index: FILE_STORAGE_DATA_INDEX, - id: `${fileMeta._id}.0`, - body: { - bid: fileMeta._id, - last: true, - data: 'UEsDBBQACAAIAFVeRFUAAAAAAAAAABMAAAAMACAAYmFkX2ZpbGUudHh0VVQNAAdTVjxjU1Y8Y1NWPGN1eAsAAQT1AQAABBQAAAArycgsVgCiRIWkxBSFtMycVC4AUEsHCKkCwMsTAAAAEwAAAFBLAQIUAxQACAAIAFVeRFWpAsDLEwAAABMAAAAMACAAAAAAAAAAAACkgQAAAABiYWRfZmlsZS50eHRVVA0AB1NWPGNTVjxjU1Y8Y3V4CwABBPUBAAAEFAAAAFBLBQYAAAAAAQABAFoAAABtAAAAAAA=', + // call to `.index()` copied from File plugin here: + // https://github.com/elastic/kibana/blob/main/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts#L195 + await esClient.index( + { + index: FILE_STORAGE_DATA_INDEX, + id: `${fileMeta._id}.0`, + document: cborx.encode({ + bid: fileMeta._id, + last: true, + data: Buffer.from( + 'UEsDBAoACQAAAFZeRFWpAsDLHwAAABMAAAAMABwAYmFkX2ZpbGUudHh0VVQJAANTVjxjU1Y8Y3V4CwABBPUBAAAEFAAAAMOcoyEq/Q4VyG02U9O0LRbGlwP/y5SOCfRKqLz1rsBQSwcIqQLAyx8AAAATAAAAUEsBAh4DCgAJAAAAVl5EVakCwMsfAAAAEwAAAAwAGAAAAAAAAQAAAKSBAAAAAGJhZF9maWxlLnR4dFVUBQADU1Y8Y3V4CwABBPUBAAAEFAAAAFBLBQYAAAAAAQABAFIAAAB1AAAAAAA=', + 'base64' + ), + }), + refresh: 'wait_for', }, - refresh: 'wait_for', - }); + { + headers: { + 'content-type': 'application/cbor', + accept: 'application/json', + }, + } + ); } return endpointResponse; diff --git a/x-pack/plugins/apm/common/rules/apm_rule_field_map.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/types.ts similarity index 50% rename from x-pack/plugins/apm/common/rules/apm_rule_field_map.ts rename to x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/types.ts index 9bbd9381c2319..5713f28c4916d 100644 --- a/x-pack/plugins/apm/common/rules/apm_rule_field_map.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/types.ts @@ -5,16 +5,12 @@ * 2.0. */ -export const apmRuleFieldMap = { - 'service.environment': { - type: 'keyword', - }, - 'transaction.type': { - type: 'keyword', - }, - 'processor.event': { - type: 'keyword', - }, -} as const; +export interface AgentEmulatorSettings { + /** Version of the settings. Can be used in the future if we need to do settings migration */ + version: number; + endpointLoader: LoadEndpointsConfig; +} -export type APMRuleFieldMap = typeof apmRuleFieldMap; +export interface LoadEndpointsConfig { + count: number; +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/base_running_service.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/base_running_service.ts new file mode 100644 index 0000000000000..e195d7e1f60ca --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/base_running_service.ts @@ -0,0 +1,108 @@ +/* + * 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 { ToolingLog } from '@kbn/tooling-log'; +import type { KbnClient } from '@kbn/test'; +import type { Client } from '@elastic/elasticsearch'; +import moment from 'moment'; + +/** + * A base class for creating a service that runs on a interval + */ +export class BaseRunningService { + private nextRunId: ReturnType | undefined; + private markRunComplete: (() => void) | undefined; + + protected wasStarted = false; + + /** Promise that remains pending while the service is running */ + public whileRunning: Promise = Promise.resolve(); + + protected readonly logPrefix: string; + + constructor( + protected readonly esClient: Client, + protected readonly kbnClient: KbnClient, + protected readonly logger: ToolingLog = new ToolingLog(), + protected readonly intervalMs: number = 30_000 // 30s + ) { + this.logPrefix = this.constructor.name ?? 'BaseRunningService'; + this.logger.verbose(`${this.logPrefix} run interval: [ ${this.intervalMs} ]`); + } + + public get isRunning(): boolean { + return this.wasStarted; + } + + start() { + if (this.wasStarted) { + return; + } + + this.wasStarted = true; + this.whileRunning = new Promise((resolve) => { + this.markRunComplete = () => resolve(); + }); + + this.logger.verbose(`${this.logPrefix}: started at ${new Date().toISOString()}`); + + this.run().finally(() => { + this.scheduleNextRun(); + }); + } + + stop() { + if (this.wasStarted) { + this.clearNextRun(); + this.wasStarted = false; + + if (this.markRunComplete) { + this.markRunComplete(); + this.markRunComplete = undefined; + } + + this.logger.verbose(`${this.logPrefix}: stopped at ${new Date().toISOString()}`); + } + } + + protected scheduleNextRun() { + this.clearNextRun(); + + if (this.wasStarted) { + this.nextRunId = setTimeout(async () => { + const startedAt = new Date(); + + await this.run(); + + const endedAt = new Date(); + + this.logger.verbose( + `${this.logPrefix}.run(): completed in ${moment + .duration(moment(endedAt).diff(startedAt, 'seconds')) + .as('seconds')}s` + ); + this.logger.indent(4, () => { + this.logger.verbose(`started at: ${startedAt.toISOString()}`); + this.logger.verbose(`ended at: ${startedAt.toISOString()}`); + }); + + this.scheduleNextRun(); + }, this.intervalMs); + } + } + + protected clearNextRun() { + if (this.nextRunId) { + clearTimeout(this.nextRunId); + this.nextRunId = undefined; + } + } + + protected async run(): Promise { + throw new Error(`${this.logPrefix}.run() not implemented!`); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/constants.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/constants.ts new file mode 100644 index 0000000000000..1d2b3d5f47784 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/constants.ts @@ -0,0 +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. + */ + +export const HORIZONTAL_LINE = '-'.repeat(80); + +export const ENDPOINT_EVENTS_INDEX = 'logs-endpoint.events.process-default'; + +export const ENDPOINT_ALERTS_INDEX = 'logs-endpoint.alerts-default'; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts index 2a51c57de8bc4..a1f21b80567d6 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts @@ -6,31 +6,62 @@ */ import type { Client } from '@elastic/elasticsearch'; +import type { KbnClient } from '@kbn/test'; import type { WriteResponseBase } from '@elastic/elasticsearch/lib/api/types'; import { clone, merge } from 'lodash'; import type { DeepPartial } from 'utility-types'; -import { METADATA_DATASTREAM } from '../../../common/endpoint/constants'; -import type { HostMetadata } from '../../../common/endpoint/types'; +import type { GetMetadataListRequestQuery } from '../../../common/endpoint/schema/metadata'; +import { resolvePathVariables } from '../../../public/common/utils/resolve_path_variables'; +import { + HOST_METADATA_GET_ROUTE, + HOST_METADATA_LIST_ROUTE, + METADATA_DATASTREAM, +} from '../../../common/endpoint/constants'; +import type { HostInfo, HostMetadata, MetadataListResponse } from '../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../common/endpoint/generate_data'; -import { checkInFleetAgent } from './fleet_services'; const endpointGenerator = new EndpointDocGenerator(); +export const fetchEndpointMetadata = async ( + kbnClient: KbnClient, + agentId: string +): Promise => { + return ( + await kbnClient.request({ + method: 'GET', + path: resolvePathVariables(HOST_METADATA_GET_ROUTE, { id: agentId }), + }) + ).data; +}; + +export const fetchEndpointMetadataList = async ( + kbnClient: KbnClient, + { page = 0, pageSize = 100, ...otherOptions }: Partial = {} +): Promise => { + return ( + await kbnClient.request({ + method: 'GET', + path: HOST_METADATA_LIST_ROUTE, + query: { + page, + pageSize, + ...otherOptions, + }, + }) + ).data; +}; + export const sendEndpointMetadataUpdate = async ( esClient: Client, agentId: string, - overrides: DeepPartial = {}, - { checkInAgent = true }: Partial<{ checkInAgent: boolean }> = {} + overrides: DeepPartial = {} ): Promise => { const lastStreamedDoc = await fetchLastStreamedEndpointUpdate(esClient, agentId); if (!lastStreamedDoc) { - throw new Error(`An endpoint with agent.id of [${agentId}] not found!`); - } - - if (checkInAgent) { - // Trigger an agent checkin and just let it run - checkInFleetAgent(esClient, agentId); + throw new Error( + `An endpoint with agent.id of [${agentId}] not found! [sendEndpointMetadataUpdate()]` + ); } const generatedHostMetadataDoc = clone(endpointGenerator.generateHostMetadata()); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts index 3d7d3c5a03172..c94b66d68a5da 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts @@ -5,23 +5,81 @@ * 2.0. */ -import type { Client } from '@elastic/elasticsearch'; -import { AGENTS_INDEX } from '@kbn/fleet-plugin/common'; +import type { Client, estypes } from '@elastic/elasticsearch'; +import { AGENTS_INDEX, EPM_API_ROUTES } from '@kbn/fleet-plugin/common'; +import type { AgentStatus, GetPackagesResponse } from '@kbn/fleet-plugin/common'; +import { pick } from 'lodash'; +import { ToolingLog } from '@kbn/tooling-log'; +import type { AxiosResponse } from 'axios'; +import type { KbnClient } from '@kbn/test'; +import { FleetAgentGenerator } from '../../../common/endpoint/data_generators/fleet_agent_generator'; -export const checkInFleetAgent = async (esClient: Client, agentId: string) => { - const checkinNow = new Date().toISOString(); +const fleetGenerator = new FleetAgentGenerator(); - await esClient.update({ +export const checkInFleetAgent = async ( + esClient: Client, + agentId: string, + { + agentStatus = 'online', + log = new ToolingLog(), + }: Partial<{ + /** The agent status to be sent. If set to `random`, then one will be randomly generated */ + agentStatus: AgentStatus | 'random'; + log: ToolingLog; + }> = {} +): Promise => { + const fleetAgentStatus = + agentStatus === 'random' ? fleetGenerator.randomAgentStatus() : agentStatus; + + const update = pick(fleetGenerator.generateEsHitWithStatus(fleetAgentStatus)._source, [ + 'last_checkin_status', + 'last_checkin', + 'active', + 'unenrollment_started_at', + 'unenrolled_at', + 'upgrade_started_at', + 'upgraded_at', + ]); + + // WORKAROUND: Endpoint API will exclude metadata for any fleet agent whose status is `inactive`, + // which means once we update the Fleet agent with that status, the metadata api will no longer + // return the endpoint host info.'s. So - we avoid that here. + update.active = true; + + // Ensure any `undefined` value is set to `null` for the update + Object.entries(update).forEach(([key, value]) => { + if (value === undefined) { + // @ts-expect-error TS7053 Element implicitly has an 'any' type + update[key] = null; + } + }); + + log.verbose(`update to fleet agent [${agentId}][${agentStatus} / ${fleetAgentStatus}]: `, update); + + return esClient.update({ index: AGENTS_INDEX, id: agentId, refresh: 'wait_for', retry_on_conflict: 5, body: { - doc: { - active: true, - last_checkin: checkinNow, - updated_at: checkinNow, - }, + doc: update, }, }); }; + +export const fetchEndpointPackageInfo = async ( + kbnClient: KbnClient +): Promise => { + const endpointPackage = ( + (await kbnClient.request({ + path: `${EPM_API_ROUTES.LIST_PATTERN}?category=security`, + method: 'GET', + })) as AxiosResponse + ).data.items.find((epmPackage) => epmPackage.name === 'endpoint'); + + if (!endpointPackage) { + throw new Error('EPM Endpoint package was not found!'); + } + + return endpointPackage; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/choice_menu_formatter.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/choice_menu_formatter.ts new file mode 100644 index 0000000000000..a1348ad719b03 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/choice_menu_formatter.ts @@ -0,0 +1,61 @@ +/* + * 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 { green } from 'chalk'; +import { isChoice } from './type_gards'; +import type { Choice } from './types'; +import { DataFormatter } from './data_formatter'; + +type ChoiceMenuFormatterItems = string[] | Choice[]; + +interface ChoiceMenuFormatterOptions { + layout: 'vertical' | 'horizontal'; +} + +const getDefaultOptions = (): ChoiceMenuFormatterOptions => { + return { + layout: 'vertical', + }; +}; + +/** + * Formatter for displaying lists of choices + */ +export class ChoiceMenuFormatter extends DataFormatter { + private readonly outputContent: string; + + constructor( + private readonly choiceList: ChoiceMenuFormatterItems, + private readonly options: ChoiceMenuFormatterOptions = getDefaultOptions() + ) { + super(); + + const list = this.buildList(); + + this.outputContent = `${list.join(this.options.layout === 'horizontal' ? ' ' : '\n')}`; + } + + protected getOutput(): string { + return this.outputContent; + } + + private buildList(): string[] { + return this.choiceList.map((choice, index) => { + let key: string = `${index + 1}`; + let title: string = ''; + + if (isChoice(choice)) { + key = choice.key; + title = choice.title; + } else { + title = choice; + } + + return green(`[${key}] `) + title; + }); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/column_layout_formatter.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/column_layout_formatter.ts new file mode 100644 index 0000000000000..ab07ddd535534 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/column_layout_formatter.ts @@ -0,0 +1,87 @@ +/* + * 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 stripAnsi from 'strip-ansi'; +// eslint-disable-next-line import/no-extraneous-dependencies +import ansiRegex from 'ansi-regex'; // its a dependency of `strip-ansi` so it should be fine +import { blue } from 'chalk'; +import { DataFormatter } from './data_formatter'; +import { SCREEN_ROW_MAX_WIDTH } from './constants'; + +interface ColumnLayoutFormatterOptions { + /** + * The width (percentage) for each of the columns. Example: 80 (for 80%). + */ + widths?: number[]; + + /** The column separator */ + separator?: string; + + /** The max length for each screen row. Defaults to the overall screen width */ + rowLength?: number; +} + +export class ColumnLayoutFormatter extends DataFormatter { + private readonly defaultSeparator = ` ${blue('\u2506')} `; + + constructor( + private readonly columns: Array, + private readonly options: ColumnLayoutFormatterOptions = {} + ) { + super(); + } + + protected getOutput(): string { + const colSeparator = this.options.separator ?? this.defaultSeparator; + let rowCount = 0; + const columnData: string[][] = this.columns.map((item) => { + const itemOutput = (typeof item === 'string' ? item : item.output).split('\n'); + + rowCount = Math.max(rowCount, itemOutput.length); + + return itemOutput; + }); + const columnSizes = this.calculateColumnSizes(); + let output = ''; + + let row = 0; + while (row < rowCount) { + const rowIndex = row++; + + output += `${columnData + .map((columnDataRows, colIndex) => { + return this.fillColumnToWidth(columnDataRows[rowIndex] ?? '', columnSizes[colIndex]); + }) + .join(colSeparator)}`; + + if (row !== rowCount) { + output += '\n'; + } + } + + return output; + } + + private calculateColumnSizes(): number[] { + const maxWidth = this.options.rowLength ?? SCREEN_ROW_MAX_WIDTH; + const widths = this.options.widths ?? []; + const defaultWidthPrct = Math.floor(100 / this.columns.length); + + return this.columns.map((_, colIndex) => { + return Math.floor(maxWidth * ((widths[colIndex] ?? defaultWidthPrct) / 100)); + }); + } + + private fillColumnToWidth(colData: string, width: number) { + const countOfControlChar = (colData.match(ansiRegex()) || []).length; + const colDataNoControlChar = stripAnsi(colData); + const colDataFilled = colDataNoControlChar.padEnd(width).substring(0, width); + const fillCount = colDataFilled.length - colDataNoControlChar.length - countOfControlChar; + + return colData + (fillCount > 0 ? ' '.repeat(fillCount) : ''); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/common_choices.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/common_choices.ts new file mode 100644 index 0000000000000..12cd636e07d81 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/common_choices.ts @@ -0,0 +1,16 @@ +/* + * 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 { Choice } from './types'; + +/** + * The Quit choice definition + */ +export const QuitChoice: Choice = { + key: 'Q', + title: 'Quit', +} as const; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/constants.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/constants.ts new file mode 100644 index 0000000000000..a1c3eab88314b --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/constants.ts @@ -0,0 +1,10 @@ +/* + * 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 { HORIZONTAL_LINE } from '../constants'; + +export const SCREEN_ROW_MAX_WIDTH = HORIZONTAL_LINE.length; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/data_formatter.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/data_formatter.ts new file mode 100644 index 0000000000000..6f02d21d56127 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/data_formatter.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. + */ + +/** + * Base class for screen data formatters + */ +export class DataFormatter { + /** + * Must be defiened by Subclasses + * @protected + */ + protected getOutput(): string { + throw new Error(`${this.constructor.name}.getOutput() not implemented!`); + } + + public get output(): string { + return this.getOutput(); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/index.ts new file mode 100644 index 0000000000000..29f289b4d241f --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { ScreenBaseClass } from './screen_base_class'; +export { ChoiceMenuFormatter } from './choice_menu_formatter'; +export { DataFormatter } from './data_formatter'; +export * from './types'; +export * from './type_gards'; +export * from './common_choices'; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/progress_formatter.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/progress_formatter.ts new file mode 100644 index 0000000000000..c5a09d02b472c --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/progress_formatter.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { green } from 'chalk'; +import { SCREEN_ROW_MAX_WIDTH } from './constants'; +import { DataFormatter } from './data_formatter'; + +const MAX_WIDTH = SCREEN_ROW_MAX_WIDTH - 14; + +export class ProgressFormatter extends DataFormatter { + private percentDone: number = 0; + + public setProgress(percentDone: number) { + this.percentDone = percentDone; + } + + protected getOutput(): string { + const prctDone = Math.min(100, this.percentDone); + const repeatValue = Math.ceil(MAX_WIDTH * (prctDone / 100)); + const progressPrct = `${prctDone}%`; + + return `[ ${'='.repeat(repeatValue).padEnd(MAX_WIDTH)} ] ${ + prctDone === 100 ? green(progressPrct) : progressPrct + }`; + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/screen_base_class.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/screen_base_class.ts new file mode 100644 index 0000000000000..32657bac374fe --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/screen_base_class.ts @@ -0,0 +1,364 @@ +/* + * 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. + */ + +/* eslint-disable max-classes-per-file */ + +import type { WriteStream as TtyWriteStream } from 'tty'; +import { stdin, stdout } from 'node:process'; +import * as readline from 'node:readline'; +import { blue, green, red, bold, cyan } from 'chalk'; +import type { QuestionCollection } from 'inquirer'; +import inquirer from 'inquirer'; +import { QuitChoice } from './common_choices'; +import type { Choice } from './types'; +import { ChoiceMenuFormatter } from './choice_menu_formatter'; +import { DataFormatter } from './data_formatter'; +import { HORIZONTAL_LINE } from '../constants'; +import { SCREEN_ROW_MAX_WIDTH } from './constants'; + +const CONTENT_60_PERCENT = Math.floor(SCREEN_ROW_MAX_WIDTH * 0.6); +const CONTENT_40_PERCENT = Math.floor(SCREEN_ROW_MAX_WIDTH * 0.4); + +/** + * Base class for creating a CLI screen. + * + * @example + * + * // Screen definition + * export class FooScreen extends ScreenBaseClass { + * protected body() { + * return `this is a test screen` + * } + * + * protected onEnterChoice(choice) { + * if (choice.toUpperCase() === 'Q') { + * this.hide(); + * return; + * } + * + * this.throwUnknownChoiceError(choice); + * } + * } + * + * // Using the screen + * await new FooScreen().show() + */ +export class ScreenBaseClass { + private readonly ttyOut: TtyWriteStream = stdout; + private readlineInstance: readline.Interface | undefined = undefined; + private showPromise: Promise | undefined = undefined; + private endSession: (() => void) | undefined = undefined; + private screenRenderInfo: RenderedScreen | undefined; + private isPaused: boolean = false; + private isHidden: boolean = true; + private autoClearMessageId: undefined | NodeJS.Timeout = undefined; + + /** + * Provides content for the header of the screen. + * + * @param title Displayed on the left side of the header area + * @param subTitle Displayed to the right of the header + * @protected + */ + protected header(title: string = '', subTitle: string = ''): string | DataFormatter { + const paddedTitle = title ? ` ${title}`.padEnd(CONTENT_60_PERCENT) : ''; + const paddedSubTitle = subTitle ? `| ${`${subTitle} `.padStart(CONTENT_40_PERCENT - 2)}` : ''; + + return title || subTitle + ? `${blue(HORIZONTAL_LINE)}\n${blue(bold(paddedTitle))}${ + subTitle ? `${cyan(paddedSubTitle)}` : '' + }\n${blue(HORIZONTAL_LINE)}\n` + : `${blue(HORIZONTAL_LINE)}\n`; + } + + /** + * Provides content for the footer of the screen + * + * @param choices Optional list of choices for display above the footer. + * @protected + */ + protected footer(choices: Choice[] = [QuitChoice]): string | DataFormatter { + const displayChoices = + choices && choices.length + ? `${this.leftPad(new ChoiceMenuFormatter(choices, { layout: 'horizontal' }).output)}\n` + : ''; + + return ` +${displayChoices}${blue(HORIZONTAL_LINE)}`; + } + + /** + * Content for the Body area of the screen + * + * @protected + */ + protected body(): string | DataFormatter { + return '\n\n(This screen has no content)\n\n'; + } + + /** + * Should be defined by the subclass to handle user selections. If the user's + * selection is invalid, this method should `throw` and `Error` - the message + * will be displayed in the screen and the user will be asked for input again. + * + * @param choice + * @protected + */ + protected onEnterChoice(choice: string) { + if (choice.toUpperCase() === 'Q') { + this.hide(); + return; + } + + throw new Error(`${this.constructor.name}.onEnterChoice() not implemented!`); + } + + /** + * Throw an error indicating invalid choice was made by the user. + * @param choice + * @protected + */ + protected throwUnknownChoiceError(choice: string): never { + throw new Error(`Unknown choice: ${choice}`); + } + + protected getOutputContent(item: string | DataFormatter): string { + return item instanceof DataFormatter ? item.output : item; + } + + private closeReadline() { + if (this.readlineInstance) { + this.readlineInstance.close(); + this.readlineInstance = undefined; + } + } + + protected leftPad(content: string, padWith: string = ' ') { + return content + .split('\n') + .map((contentLine) => { + if (!contentLine.startsWith(padWith)) { + return padWith + contentLine; + } + return contentLine; + }) + .join('\n'); + } + + public showMessage( + message: string, + color: 'blue' | 'red' | 'green' = 'blue', + autoClear: boolean = false + ) { + const { screenRenderInfo, ttyOut } = this; + + if (this.autoClearMessageId) { + clearTimeout(this.autoClearMessageId); + this.autoClearMessageId = undefined; + } + + if (screenRenderInfo) { + ttyOut.cursorTo(0, screenRenderInfo.statusPos); + ttyOut.clearLine(0); + + let coloredMessage = message; + + switch (color) { + case 'green': + coloredMessage = green(`\u2713 ${message}`); + break; + case 'red': + coloredMessage = red(`\u24e7 ${message}`); + break; + + case 'blue': + coloredMessage = blue(`\u24d8 ${message}`); + break; + } + + ttyOut.write(` ${coloredMessage}`); + + if (autoClear) { + this.autoClearMessageId = setTimeout(() => { + this.showMessage(''); + }, 4000); + } + } + } + + private clearPromptOutput() { + const { ttyOut, screenRenderInfo } = this; + + if (screenRenderInfo) { + ttyOut.cursorTo(0, screenRenderInfo.promptPos ?? 0); + ttyOut.clearScreenDown(); + } + } + + private async askForChoice(prompt?: string): Promise { + this.closeReadline(); + this.clearPromptOutput(); + + return new Promise((resolve) => { + const rl = readline.createInterface({ input: stdin, output: stdout }); + this.readlineInstance = rl; + + // TODO:PT experiment with using `rl.prompt()` instead of `question()` and possibly only initialize `rl` once + + rl.question(green(prompt ?? 'Enter choice: '), (selection) => { + if (this.isPaused || this.isHidden) { + return; + } + + if (this.readlineInstance === rl) { + this.clearPromptOutput(); + this.closeReadline(); + + try { + this.onEnterChoice(selection); + } catch (error) { + this.showMessage(error.message, 'red'); + + resolve(this.askForChoice(prompt)); + + return; + } + + resolve(); + } + }); + }); + } + + private clearScreen() { + this.ttyOut.cursorTo(0, 0); + this.ttyOut.clearScreenDown(); + } + + /** + * Renders (or re-renders) the screen. Can be called multiple times + * + * @param prompt + */ + public reRender(prompt?: string) { + if (this.isHidden || this.isPaused) { + return; + } + + const { ttyOut } = this; + const headerContent = this.header(); + const bodyContent = this.body(); + const footerContent = this.footer(); + + const screenRenderInfo = new RenderedScreen( + this.getOutputContent(headerContent) + + this.leftPad(this.getOutputContent(bodyContent)) + + this.getOutputContent(footerContent) + ); + this.screenRenderInfo = screenRenderInfo; + + this.clearScreen(); + + ttyOut.write(screenRenderInfo.output); + + this.askForChoice(prompt); + } + + /** + * Will display the screen and return a promise that is resolved once the screen is hidden. + * + * @param prompt + * @param resume + */ + public show({ + prompt, + resume, + }: Partial<{ prompt: string; resume: boolean }> = {}): Promise { + if (resume) { + this.isPaused = false; + } + + if (this.isPaused) { + return Promise.resolve(undefined); + } + + this.isHidden = false; + this.reRender(prompt); + + // `show()` can be called multiple times, so only create the `showPromise` if one is not already present + if (!this.showPromise) { + this.showPromise = new Promise((resolve) => { + this.endSession = () => resolve(); + }); + } + + return this.showPromise; + } + + /** + * Will hide the screen and fulfill the promise returned by `.show()` + */ + public hide() { + this.closeReadline(); + this.clearScreen(); + this.screenRenderInfo = undefined; + this.isHidden = true; + this.isPaused = false; + + if (this.endSession) { + this.endSession(); + this.showPromise = undefined; + this.endSession = undefined; + } + } + + public pause() { + this.isPaused = true; + this.closeReadline(); + } + + public async prompt({ + questions, + answers = {}, + title = blue('Settings:'), + }: { + questions: QuestionCollection; + answers?: Partial; + title?: string; + }): Promise { + if (this.isPaused || this.isHidden) { + return answers as TAnswers; + } + + const screenRenderInfo = new RenderedScreen(this.getOutputContent(this.header())); + + this.screenRenderInfo = screenRenderInfo; + this.clearScreen(); + this.ttyOut.write(`${screenRenderInfo.output}${title ? `${this.leftPad(title)}\n` : ''}`); + + const ask = inquirer.createPromptModule(); + const newAnswers = await ask(questions, answers); + + return newAnswers; + } +} + +class RenderedScreen { + public statusPos: number = -1; + public promptPos: number = -1; + public statusMessage: string | undefined = undefined; + + constructor(private readonly screenOutput: string) { + const outputBottomPos = screenOutput.split('\n').length - 1; + this.statusPos = outputBottomPos + 1; + this.promptPos = this.statusPos + 1; + } + + public get output(): string { + return `${this.screenOutput}\n${this.statusMessage ?? ' '}\n`; + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/type_gards.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/type_gards.ts new file mode 100644 index 0000000000000..e9fd23d56293d --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/type_gards.ts @@ -0,0 +1,17 @@ +/* + * 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 { Choice } from './types'; + +/** + * Type guard that checks if a item is a `Choice` + * + * @param item + */ +export const isChoice = (item: string | object): item is Choice => { + return 'string' !== typeof item && 'key' in item && 'title' in item; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/screen/types.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/types.ts new file mode 100644 index 0000000000000..815403528dca9 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/screen/types.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +/** + * An item representing a choice/item to be shown on a screen + */ +export interface Choice { + /** The keyboard key (or combination of keys) that the user will enter to select this choice */ + key: string; + /** The title of the choice */ + title: string; +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/settings_storage.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/settings_storage.ts new file mode 100644 index 0000000000000..d68da4bfc92b6 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/settings_storage.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { homedir } from 'os'; +import { join } from 'path'; +import { mkdir, writeFile, readFile, unlink } from 'fs/promises'; +import { existsSync } from 'fs'; + +interface SettingStorageOptions { + /** The default directory where settings will be saved. Defaults to `~/.kibanaSecuritySolutionCliTools` */ + directory?: string; + + /** The default settings object (used if file does not exist yet) */ + defaultSettings?: TSettingsDef; +} + +/** + * A generic service for persisting settings. By default, all settings are saved to a directory + * under `~/.kibanaSecuritySolutionCliTools` + */ +export class SettingsStorage { + private options: Required>; + private readonly settingsFileFullPath: string; + private dirExists: boolean = false; + + constructor(fileName: string, options: SettingStorageOptions = {}) { + const { + directory = join(homedir(), '.kibanaSecuritySolutionCliTools'), + defaultSettings = {} as TSettingsDef, + } = options; + + this.options = { + directory, + defaultSettings, + }; + + this.settingsFileFullPath = join(this.options.directory, fileName); + } + + private async ensureExists(): Promise { + if (!this.dirExists) { + await mkdir(this.options.directory, { recursive: true }); + this.dirExists = true; + + if (!existsSync(this.settingsFileFullPath)) { + await this.save(this.options.defaultSettings); + } + } + } + + /** Retrieve the content of the settings file */ + public async get(): Promise { + await this.ensureExists(); + const fileContent = await readFile(this.settingsFileFullPath); + return JSON.parse(fileContent.toString()) as TSettingsDef; + } + + /** Save a new version of the settings to disk */ + public async save(newSettings: TSettingsDef): Promise { + // FIXME: Enhance this method so that Partial `newSettings` can be provided and they are merged into the existing set. + await this.ensureExists(); + await writeFile(this.settingsFileFullPath, JSON.stringify(newSettings, null, 2)); + } + + /** Deletes the settings file from disk */ + public async delete(): Promise { + await this.ensureExists(); + await unlink(this.settingsFileFullPath); + } +} diff --git a/x-pack/plugins/security_solution/scripts/endpoint/endpoint_action_responder.js b/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_emulator.js similarity index 89% rename from x-pack/plugins/security_solution/scripts/endpoint/endpoint_action_responder.js rename to x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_emulator.js index 3617b8d0d5b32..9eacefa57a2b9 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/endpoint_action_responder.js +++ b/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_emulator.js @@ -6,4 +6,4 @@ */ require('../../../../../src/setup_node_env'); -require('./action_responder').cli(); +require('./agent_emulator').cli(); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts b/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts index a871151ed0b0d..b6c1c3a266d9b 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts @@ -14,10 +14,12 @@ import { CA_CERT_PATH } from '@kbn/dev-utils'; import { ToolingLog } from '@kbn/tooling-log'; import type { KbnClientOptions } from '@kbn/test'; import { KbnClient } from '@kbn/test'; +import { METADATA_DATASTREAM } from '../../common/endpoint/constants'; import { EndpointMetadataGenerator } from '../../common/endpoint/data_generators/endpoint_metadata_generator'; import { indexHostsAndAlerts } from '../../common/endpoint/index_data'; import { ANCESTRY_LIMIT, EndpointDocGenerator } from '../../common/endpoint/generate_data'; import { fetchStackVersion } from './common/stack_services'; +import { ENDPOINT_ALERTS_INDEX, ENDPOINT_EVENTS_INDEX } from './common/constants'; main(); @@ -130,19 +132,19 @@ async function main() { eventIndex: { alias: 'ei', describe: 'index to store events in', - default: 'logs-endpoint.events.process-default', + default: ENDPOINT_EVENTS_INDEX, type: 'string', }, alertIndex: { alias: 'ai', describe: 'index to store alerts in', - default: 'logs-endpoint.alerts-default', + default: ENDPOINT_ALERTS_INDEX, type: 'string', }, metadataIndex: { alias: 'mi', describe: 'index to store host metadata in', - default: 'metrics-endpoint.metadata-default', + default: METADATA_DATASTREAM, type: 'string', }, policyIndex: { diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 7639e73b0a36d..7a0d7fa1950fe 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -5,10 +5,25 @@ * 2.0. */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import type { AwaitedProperties } from '@kbn/utility-types'; import type { ScopedClusterClientMock } from '@kbn/core/server/mocks'; -import { loggingSystemMock, savedObjectsServiceMock } from '@kbn/core/server/mocks'; -import type { SavedObjectsClientContract } from '@kbn/core/server'; +import { + elasticsearchServiceMock, + httpServerMock, + httpServiceMock, + loggingSystemMock, + savedObjectsClientMock, + savedObjectsServiceMock, +} from '@kbn/core/server/mocks'; +import type { + KibanaRequest, + RouteConfig, + SavedObjectsClientContract, + RequestHandler, + IRouter, +} from '@kbn/core/server'; import { listMock } from '@kbn/lists-plugin/server/mocks'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; @@ -25,6 +40,8 @@ import { // a restricted path. import { createCasesClientMock } from '@kbn/cases-plugin/server/client/mocks'; import { createFleetAuthzMock } from '@kbn/fleet-plugin/common'; +import type { RequestFixtureOptions } from '@kbn/core-http-router-server-mocks'; +import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { xpackMocks } from '../fixtures'; import { createMockConfig, requestContextMock } from '../lib/detection_engine/routes/__mocks__'; import type { @@ -192,3 +209,77 @@ export function createRouteHandlerContext( context.core.savedObjects.client = savedObjectsClient; return context; } + +export interface HttpApiTestSetupMock

    { + routerMock: ReturnType; + scopedEsClusterClientMock: ReturnType; + savedObjectClientMock: ReturnType; + endpointAppContextMock: EndpointAppContext; + httpResponseMock: ReturnType; + httpHandlerContextMock: ReturnType; + getEsClientMock: (type?: 'internalUser' | 'currentUser') => ElasticsearchClientMock; + createRequestMock: (options?: RequestFixtureOptions) => KibanaRequest; + /** Retrieves the handler that was registered with the `router` for a given `method` and `path` */ + getRegisteredRouteHandler: ( + method: keyof Pick, + path: string + ) => RequestHandler; +} + +/** + * Returns all of the setup needed to test an HTTP api handler + */ +export const createHttpApiTestSetupMock =

    (): HttpApiTestSetupMock< + P, + Q, + B +> => { + const routerMock = httpServiceMock.createRouter(); + const endpointAppContextMock = createMockEndpointAppContext(); + const scopedEsClusterClientMock = elasticsearchServiceMock.createScopedClusterClient(); + const savedObjectClientMock = savedObjectsClientMock.create(); + const httpHandlerContextMock = requestContextMock.convertContext( + createRouteHandlerContext(scopedEsClusterClientMock, savedObjectClientMock) + ); + const httpResponseMock = httpServerMock.createResponseFactory(); + const getRegisteredRouteHandler: HttpApiTestSetupMock['getRegisteredRouteHandler'] = ( + method, + path + ): RequestHandler => { + const methodCalls = routerMock[method].mock.calls as Array< + [route: RouteConfig, handler: RequestHandler] + >; + const handler = methodCalls.find(([routeConfig]) => routeConfig.path.startsWith(path)); + + if (!handler) { + throw new Error(`Handler for [${method}][${path}] not found`); + } + + return handler[1]; + }; + + return { + routerMock, + + endpointAppContextMock, + scopedEsClusterClientMock, + savedObjectClientMock, + + httpHandlerContextMock, + httpResponseMock, + + createRequestMock: (options: RequestFixtureOptions = {}): KibanaRequest => { + return httpServerMock.createKibanaRequest(options); + }, + + getEsClientMock: ( + type: 'internalUser' | 'currentUser' = 'internalUser' + ): ElasticsearchClientMock => { + return type === 'currentUser' + ? scopedEsClusterClientMock.asCurrentUser + : scopedEsClusterClientMock.asInternalUser; + }, + + getRegisteredRouteHandler, + }; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.test.ts new file mode 100644 index 0000000000000..5711baac65f54 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.test.ts @@ -0,0 +1,147 @@ +/* + * 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 { + getActionFileDownloadRouteHandler, + registerActionFileDownloadRoutes, +} from './file_download_handler'; +import type { HttpApiTestSetupMock } from '../../mocks'; +import { createHttpApiTestSetupMock } from '../../mocks'; +import type { EndpointActionFileDownloadParams } from '../../../../common/endpoint/schema/actions'; +import { getActionDetailsById as _getActionDetailsById } from '../../services'; +import { EndpointAuthorizationError, NotFoundError } from '../../errors'; +import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; +import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; +import { getFileDownloadStream as _getFileDownloadStream } from '../../services/actions/action_files'; +import stream from 'stream'; +import type { ActionDetails } from '../../../../common/endpoint/types'; +import { ACTION_AGENT_FILE_DOWNLOAD_ROUTE } from '../../../../common/endpoint/constants'; + +jest.mock('../../services'); +jest.mock('../../services/actions/action_files'); + +describe('Response Actions file download API', () => { + const getActionDetailsById = _getActionDetailsById as jest.Mock; + const getFileDownloadStream = _getFileDownloadStream as jest.Mock; + + let apiTestSetup: HttpApiTestSetupMock; + let httpRequestMock: ReturnType< + HttpApiTestSetupMock['createRequestMock'] + >; + let httpHandlerContextMock: HttpApiTestSetupMock['httpHandlerContextMock']; + let httpResponseMock: HttpApiTestSetupMock['httpResponseMock']; + + beforeEach(() => { + apiTestSetup = createHttpApiTestSetupMock(); + + ({ httpHandlerContextMock, httpResponseMock } = apiTestSetup); + httpRequestMock = apiTestSetup.createRequestMock({ + params: { action_id: '111', agent_id: '222' }, + }); + }); + + describe('#registerActionFileDownloadRoutes()', () => { + beforeEach(() => { + registerActionFileDownloadRoutes( + apiTestSetup.routerMock, + apiTestSetup.endpointAppContextMock + ); + }); + + it('should register the route', () => { + expect( + apiTestSetup.getRegisteredRouteHandler('get', ACTION_AGENT_FILE_DOWNLOAD_ROUTE) + ).toBeDefined(); + }); + + it('should error if user has no authz to api', async () => { + const authz = (await httpHandlerContextMock.securitySolution).endpointAuthz; + authz.canWriteFileOperations = false; + + await apiTestSetup.getRegisteredRouteHandler('get', ACTION_AGENT_FILE_DOWNLOAD_ROUTE)( + httpHandlerContextMock, + httpRequestMock, + httpResponseMock + ); + + expect(httpResponseMock.forbidden).toHaveBeenCalledWith({ + body: expect.any(EndpointAuthorizationError), + }); + }); + }); + + describe('Route handler', () => { + let fileDownloadHandler: ReturnType; + let esClientMock: ReturnType; + let action: ActionDetails; + + beforeEach(() => { + esClientMock = apiTestSetup.getEsClientMock(); + action = new EndpointActionGenerator().generateActionDetails({ + id: '111', + agents: ['222'], + }); + fileDownloadHandler = getActionFileDownloadRouteHandler(apiTestSetup.endpointAppContextMock); + + getActionDetailsById.mockImplementation(async () => { + return action; + }); + + getFileDownloadStream.mockImplementation(async () => { + return { + stream: new stream.Readable(), + fileName: 'test.txt', + mimeType: 'text/plain', + }; + }); + }); + + it('should error if action ID is invalid', async () => { + getActionDetailsById.mockImplementationOnce(async () => { + throw new NotFoundError('not found'); + }); + await fileDownloadHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(httpResponseMock.notFound).toHaveBeenCalled(); + }); + + it('should error if agent id is not in the action', async () => { + action.agents = ['333']; + await fileDownloadHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(httpResponseMock.customError).toHaveBeenCalledWith({ + statusCode: 400, + body: expect.any(CustomHttpRequestError), + }); + }); + + it('should retrieve the download Stream using correct file ID', async () => { + await fileDownloadHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(getFileDownloadStream).toHaveBeenCalledWith( + esClientMock, + expect.anything(), + '111.222' + ); + }); + + it('should respond with expected HTTP headers', async () => { + await fileDownloadHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + + expect(httpResponseMock.ok).toHaveBeenCalledWith( + expect.objectContaining({ + headers: { + 'cache-control': 'max-age=31536000, immutable', + 'content-disposition': 'attachment; filename="test.txt"', + 'content-type': 'application/octet-stream', + 'x-content-type-options': 'nosniff', + }, + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.ts new file mode 100644 index 0000000000000..304c92e6d0184 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RequestHandler } from '@kbn/core/server'; +import { getFileDownloadId } from '../../../../common/endpoint/service/response_actions/get_file_download_id'; +import { getActionDetailsById } from '../../services'; +import { errorHandler } from '../error_handler'; +import { ACTION_AGENT_FILE_DOWNLOAD_ROUTE } from '../../../../common/endpoint/constants'; +import type { EndpointActionFileDownloadParams } from '../../../../common/endpoint/schema/actions'; +import { EndpointActionFileDownloadSchema } from '../../../../common/endpoint/schema/actions'; +import { withEndpointAuthz } from '../with_endpoint_authz'; +import type { EndpointAppContext } from '../../types'; +import type { + SecuritySolutionPluginRouter, + SecuritySolutionRequestHandlerContext, +} from '../../../types'; +import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; +import { getFileDownloadStream } from '../../services/actions/action_files'; + +export const registerActionFileDownloadRoutes = ( + router: SecuritySolutionPluginRouter, + endpointContext: EndpointAppContext +) => { + const logger = endpointContext.logFactory.get('actionFileDownload'); + + router.get( + { + path: ACTION_AGENT_FILE_DOWNLOAD_ROUTE, + validate: EndpointActionFileDownloadSchema, + options: { authRequired: true, tags: ['access:securitySolution'] }, + }, + withEndpointAuthz( + { all: ['canWriteFileOperations'] }, + logger, + getActionFileDownloadRouteHandler(endpointContext) + ) + ); +}; + +export const getActionFileDownloadRouteHandler = ( + endpointContext: EndpointAppContext +): RequestHandler< + EndpointActionFileDownloadParams, + unknown, + unknown, + SecuritySolutionRequestHandlerContext +> => { + const logger = endpointContext.logFactory.get('actionFileDownload'); + + return async (context, req, res) => { + const { action_id: actionId, agent_id: agentId } = req.params; + const esClient = (await context.core).elasticsearch.client.asInternalUser; + const endpointMetadataService = endpointContext.service.getEndpointMetadataService(); + + try { + // Ensure action id is valid and that it was sent to the Agent ID requested. + const actionDetails = await getActionDetailsById(esClient, endpointMetadataService, actionId); + + if (!actionDetails.agents.includes(agentId)) { + throw new CustomHttpRequestError(`Action was not sent to agent id [${agentId}]`, 400); + } + + const fileDownloadId = getFileDownloadId(actionDetails, agentId); + const { stream, fileName } = await getFileDownloadStream(esClient, logger, fileDownloadId); + + return res.ok({ + body: stream, + headers: { + 'content-type': 'application/octet-stream', + 'cache-control': 'max-age=31536000, immutable', + // Note, this name can be overridden by the client if set via a "download" attribute on the HTML tag. + 'content-disposition': `attachment; filename="${fileName ?? 'download.zip'}"`, + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options + 'x-content-type-options': 'nosniff', + }, + }); + } catch (error) { + return errorHandler(logger, res, error); + } + }; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts index d947cfefa9a2a..a801360772b28 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { registerActionFileDownloadRoutes } from './file_download_handler'; import { registerActionDetailsRoutes } from './details'; import type { SecuritySolutionPluginRouter } from '../../../types'; import type { EndpointAppContext } from '../../types'; @@ -23,5 +24,6 @@ export function registerActionRoutes( registerActionAuditLogRoutes(router, endpointContext); registerActionListRoutes(router, endpointContext); registerActionDetailsRoutes(router, endpointContext); + registerActionFileDownloadRoutes(router, endpointContext); registerResponseActionRoutes(router, endpointContext); } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts index c2a460fa88b79..b8e7211874cd9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts @@ -9,6 +9,7 @@ import type { SecuritySolutionRequestHandlerContextMock } from '../../../lib/det import type { AwaitedProperties } from '@kbn/utility-types'; import type { EndpointActionListRequestQuery } from '../../../../common/endpoint/schema/actions'; import type { EndpointAuthz } from '../../../../common/endpoint/types/authz'; +import type { License } from '@kbn/licensing-plugin/common/license'; import { createMockEndpointAppContextServiceSetupContract, createMockEndpointAppContextServiceStartContract, @@ -31,13 +32,16 @@ import { Subject } from 'rxjs'; import type { ILicense } from '@kbn/licensing-plugin/common/types'; import { licenseMock } from '@kbn/licensing-plugin/common/licensing.mock'; import { registerActionListRoutes } from './list'; +import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz/mocks'; interface CallApiRouteInterface { query?: EndpointActionListRequestQuery; + license?: License; authz?: Partial; } const Platinum = licenseMock.createLicense({ license: { type: 'platinum', mode: 'platinum' } }); +const Gold = licenseMock.createLicense({ license: { type: 'gold', mode: 'gold' } }); describe('Action List Route', () => { const superUser = { @@ -82,7 +86,7 @@ describe('Action List Route', () => { callApiRoute = async ( routePrefix: string, - { query, authz = {} }: CallApiRouteInterface + { query, license, authz = {} }: CallApiRouteInterface ): Promise> => { (startContract.security.authc.getCurrentUser as jest.Mock).mockImplementationOnce( () => superUser @@ -90,12 +94,21 @@ describe('Action List Route', () => { const ctx = createRouteHandlerContext(mockScopedClient, mockSavedObjectClient); + const withLicense = license ? license : Platinum; + licenseEmitter.next(withLicense); + ctx.securitySolution.endpointAuthz = { - ...ctx.securitySolution.endpointAuthz, + ...getEndpointAuthzInitialStateMock({ + canReadActionsLogManagement: + // mimicking the behavior of the EndpointAuthz class + // just so we can test the license check here + // since getEndpointAuthzInitialStateMock sets all keys to true + ctx.securitySolution.endpointAuthz.canAccessEndpointManagement && + licenseService.isPlatinumPlus(), + }), ...authz, }; - licenseEmitter.next(Platinum); const mockRequest = httpServerMock.createKibanaRequest({ query }); const [, routeHandler]: [ // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -117,14 +130,23 @@ describe('Action List Route', () => { }); describe('User auth level', () => { - it('allows user with canReadSecuritySolution access to allow requests to API', async () => { - await callApiRoute(ENDPOINTS_ACTION_LIST_ROUTE, {}); + it('allows user with `canReadActionsLogManagement` access for API requests', async () => { + await callApiRoute(ENDPOINTS_ACTION_LIST_ROUTE, { + authz: { canReadActionsLogManagement: true }, + }); expect(mockResponse.ok).toBeCalled(); }); - it('does not allow user without canReadSecuritySolution access to allow requests to API', async () => { + it('does not allow user without `canReadActionsLogManagement` access for API requests', async () => { + await callApiRoute(ENDPOINTS_ACTION_LIST_ROUTE, { + authz: { canReadActionsLogManagement: false }, + }); + expect(mockResponse.forbidden).toBeCalled(); + }); + + it('does not allow user access to API requests if license is below platinum', async () => { await callApiRoute(ENDPOINTS_ACTION_LIST_ROUTE, { - authz: { canReadSecuritySolution: false }, + license: Gold, }); expect(mockResponse.forbidden).toBeCalled(); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts index a8b3ff5d70749..6a932f9bb8af8 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts @@ -33,7 +33,7 @@ export function registerActionListRoutes( options: { authRequired: true, tags: ['access:securitySolution'] }, }, withEndpointAuthz( - { all: ['canReadSecuritySolution'] }, + { all: ['canReadActionsLogManagement'] }, endpointContext.logFactory.get('endpointActionList'), actionListHandler(endpointContext) ) diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.test.ts new file mode 100644 index 0000000000000..288c8ba043693 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.test.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 type { ElasticsearchClientMock } from '@kbn/core/server/mocks'; +import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import type { Logger } from '@kbn/core/server'; +import { createEsFileClient as _createEsFileClient } from '@kbn/files-plugin/server'; +import { createFileClientMock } from '@kbn/files-plugin/server/mocks'; +import { getFileDownloadStream } from './action_files'; +import type { DiagnosticResult } from '@elastic/elasticsearch'; +import { errors } from '@elastic/elasticsearch'; +import { NotFoundError } from '../../errors'; + +jest.mock('@kbn/files-plugin/server'); +const createEsFileClient = _createEsFileClient as jest.Mock; + +describe('Action Files service', () => { + describe('#getFileDownloadStream()', () => { + let loggerMock: Logger; + let esClientMock: ElasticsearchClientMock; + let fileClientMock: ReturnType; + + beforeEach(() => { + loggerMock = loggingSystemMock.create().get('mock'); + esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + fileClientMock = createFileClientMock(); + createEsFileClient.mockReturnValue(fileClientMock); + }); + + it('should return expected output', async () => { + await expect(getFileDownloadStream(esClientMock, loggerMock, '123')).resolves.toEqual({ + stream: expect.anything(), + fileName: 'test.txt', + mimeType: 'text/plain', + }); + }); + + it('should return NotFoundError if file or index is not found', async () => { + fileClientMock.get.mockRejectedValue( + new errors.ResponseError({ + statusCode: 404, + } as DiagnosticResult) + ); + + await expect(getFileDownloadStream(esClientMock, loggerMock, '123')).rejects.toBeInstanceOf( + NotFoundError + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.ts new file mode 100644 index 0000000000000..5db82681c3572 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_files.ts @@ -0,0 +1,59 @@ +/* + * 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 { ElasticsearchClient, Logger } from '@kbn/core/server'; +import type { Readable } from 'stream'; +import { createEsFileClient } from '@kbn/files-plugin/server'; +import { errors } from '@elastic/elasticsearch'; +import { NotFoundError } from '../../errors'; +import { + FILE_STORAGE_DATA_INDEX, + FILE_STORAGE_METADATA_INDEX, +} from '../../../../common/endpoint/constants'; +import { EndpointError } from '../../../../common/endpoint/errors'; + +/** + * Returns a NodeJS `Readable` data stream to a file + * @param esClient + * @param logger + * @param fileId + */ +export const getFileDownloadStream = async ( + esClient: ElasticsearchClient, + logger: Logger, + fileId: string +): Promise<{ stream: Readable; fileName: string; mimeType?: string }> => { + const fileClient = createEsFileClient({ + metadataIndex: FILE_STORAGE_METADATA_INDEX, + blobStorageIndex: FILE_STORAGE_DATA_INDEX, + elasticsearchClient: esClient, + logger, + }); + + try { + const file = await fileClient.get({ id: fileId }); + const { name: fileName, mimeType } = file.data; + + return { + stream: await file.downloadContent(), + fileName, + mimeType, + }; + } catch (error) { + if (error instanceof errors.ResponseError) { + const statusCode = error.statusCode; + + // 404 will be returned if file id is not found -or- index does not exist yet. + // Using the `NotFoundError` error class will result in the API returning a 404 + if (statusCode === 404) { + throw new NotFoundError(`File with id [${fileId}] not found`, error); + } + } + + throw new EndpointError(`Failed to get file using id [${fileId}]: ${error.message}`, error); + } +}; diff --git a/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts b/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts index da52432571f97..d4a60be85d3ea 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts @@ -9,7 +9,7 @@ import type { KibanaRequest, Logger } from '@kbn/core/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; import type { PluginStartContract as AlertsStartContract } from '@kbn/alerting-plugin/server'; import { createDetectionIndex } from '../../lib/detection_engine/routes/index/create_index_route'; -import { createPrepackagedRules } from '../../lib/detection_engine/routes/rules/add_prepackaged_rules_route'; +import { createPrepackagedRules } from '../../lib/detection_engine/prebuilt_rules'; import type { SecuritySolutionApiRequestHandlerContext } from '../../types'; export interface InstallPrepackagedRulesProps { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/installed_integration_set.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/installed_integration_set.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/installed_integration_set.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/installed_integration_set.ts index e124e0322192c..156d1c99fde5d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/installed_integration_set.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/installed_integration_set.ts @@ -14,7 +14,7 @@ import type { InstalledPackage, InstalledPackageArray, InstalledPackageBasicInfo, -} from '../../../../../../common/detection_engine/schemas/common'; +} from '../../../../../../common/detection_engine/fleet_integrations'; export interface IInstalledIntegrationSet { addPackagePolicy(policy: PackagePolicy): void; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/route.ts similarity index 91% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/route.ts index 9e9091e1b578c..7b904c282e1e4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/route.ts @@ -8,11 +8,11 @@ import type { Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { initPromisePool } from '../../../../../utils/promise_pool'; -import { buildSiemResponse } from '../../utils'; +import { buildSiemResponse } from '../../../routes/utils'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; -import { DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL } from '../../../../../../common/constants'; -import type { GetInstalledIntegrationsResponse } from '../../../../../../common/detection_engine/schemas/response/get_installed_integrations_response_schema'; +import type { GetInstalledIntegrationsResponse } from '../../../../../../common/detection_engine/fleet_integrations'; +import { GET_INSTALLED_INTEGRATIONS_URL } from '../../../../../../common/detection_engine/fleet_integrations'; import { createInstalledIntegrationSet } from './installed_integration_set'; const MAX_CONCURRENT_REQUESTS_TO_PACKAGE_REGISTRY = 5; @@ -26,7 +26,7 @@ export const getInstalledIntegrationsRoute = ( ) => { router.get( { - path: DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL, + path: GET_INSTALLED_INTEGRATIONS_URL, validate: {}, options: { tags: ['access:securitySolution'], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/register_routes.ts new file mode 100644 index 0000000000000..2c6c2c2ae21f8 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/register_routes.ts @@ -0,0 +1,18 @@ +/* + * 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 { Logger } from '@kbn/core/server'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; + +import { getInstalledIntegrationsRoute } from './get_installed_integrations/route'; + +export const registerFleetIntegrationsRoutes = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + getInstalledIntegrationsRoute(router, logger); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/index.ts new file mode 100644 index 0000000000000..c0123e587d9bf --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './api/register_routes'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/route.test.ts similarity index 89% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/route.test.ts index 5853aecf13021..fd7351c677a2a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/route.test.ts @@ -5,24 +5,24 @@ * 2.0. */ -import { getPrepackagedRulesStatusRoute } from './get_prepackaged_rules_status_route'; +import { getPrebuiltRulesAndTimelinesStatusRoute } from './route'; import { getEmptyFindResult, getFindResultWithSingleHit, getPrepackagedRulesStatusRequest, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, createMockConfig } from '../__mocks__'; +} from '../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, createMockConfig } from '../../../routes/__mocks__'; import type { SecurityPluginSetup } from '@kbn/security-plugin/server'; -import { checkTimelinesStatus } from '../../../timeline/utils/check_timelines_status'; +import { checkTimelinesStatus } from '../../../../timeline/utils/check_timelines_status'; import { mockCheckTimelinesStatusBeforeInstallResult, mockCheckTimelinesStatusAfterInstallResult, -} from '../../../timeline/__mocks__/import_timelines'; +} from '../../../../timeline/__mocks__/import_timelines'; -jest.mock('../../rules/get_prepackaged_rules', () => { +jest.mock('../../logic/get_latest_prebuilt_rules', () => { return { - getLatestPrepackagedRules: async () => { + getLatestPrebuiltRules: async () => { return [ { rule_id: 'rule-1', @@ -43,8 +43,8 @@ jest.mock('../../rules/get_prepackaged_rules', () => { }; }); -jest.mock('../../../timeline/utils/check_timelines_status', () => { - const actual = jest.requireActual('../../../timeline/utils/check_timelines_status'); +jest.mock('../../../../timeline/utils/check_timelines_status', () => { + const actual = jest.requireActual('../../../../timeline/utils/check_timelines_status'); return { ...actual, checkTimelinesStatus: jest.fn(), @@ -82,7 +82,7 @@ describe('get_prepackaged_rule_status_route', () => { prepackagedTimelines: [], }); - getPrepackagedRulesStatusRoute(server.router, createMockConfig(), securitySetup); + getPrebuiltRulesAndTimelinesStatusRoute(server.router, createMockConfig(), securitySetup); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/route.ts new file mode 100644 index 0000000000000..e8f947b0540c1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/route.ts @@ -0,0 +1,114 @@ +/* + * 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 { transformError } from '@kbn/securitysolution-es-utils'; +import { validate } from '@kbn/securitysolution-io-ts-utils'; +import { buildSiemResponse } from '../../../routes/utils'; +import type { ConfigType } from '../../../../../config'; +import type { SetupPlugins } from '../../../../../plugin'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; + +import { + PREBUILT_RULES_STATUS_URL, + GetPrebuiltRulesAndTimelinesStatusResponse, +} from '../../../../../../common/detection_engine/prebuilt_rules'; + +import { getExistingPrepackagedRules } from '../../../rule_management/logic/search/get_existing_prepackaged_rules'; +import { findRules } from '../../../rule_management/logic/search/find_rules'; +import { getLatestPrebuiltRules } from '../../logic/get_latest_prebuilt_rules'; +import { getRulesToInstall } from '../../logic/get_rules_to_install'; +import { getRulesToUpdate } from '../../logic/get_rules_to_update'; +import { ruleAssetSavedObjectsClientFactory } from '../../logic/rule_asset/rule_asset_saved_objects_client'; +import { rulesToMap } from '../../logic/utils'; + +import { buildFrameworkRequest } from '../../../../timeline/utils/common'; +import { + checkTimelinesStatus, + checkTimelineStatusRt, +} from '../../../../timeline/utils/check_timelines_status'; + +export const getPrebuiltRulesAndTimelinesStatusRoute = ( + router: SecuritySolutionPluginRouter, + config: ConfigType, + security: SetupPlugins['security'] +) => { + router.get( + { + path: PREBUILT_RULES_STATUS_URL, + validate: false, + options: { + tags: ['access:securitySolution'], + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + const ctx = await context.resolve(['core', 'alerting']); + const savedObjectsClient = ctx.core.savedObjects.client; + const rulesClient = ctx.alerting.getRulesClient(); + const ruleAssetsClient = ruleAssetSavedObjectsClientFactory(savedObjectsClient); + + try { + const latestPrebuiltRules = await getLatestPrebuiltRules( + ruleAssetsClient, + config.prebuiltRulesFromFileSystem, + config.prebuiltRulesFromSavedObjects + ); + + const customRules = await findRules({ + rulesClient, + perPage: 1, + page: 1, + sortField: 'enabled', + sortOrder: 'desc', + filter: 'alert.attributes.params.immutable: false', + fields: undefined, + }); + + const installedPrebuiltRules = rulesToMap( + await getExistingPrepackagedRules({ rulesClient }) + ); + + const rulesToInstall = getRulesToInstall(latestPrebuiltRules, installedPrebuiltRules); + const rulesToUpdate = getRulesToUpdate(latestPrebuiltRules, installedPrebuiltRules); + + const frameworkRequest = await buildFrameworkRequest(context, security, request); + const prebuiltTimelineStatus = await checkTimelinesStatus(frameworkRequest); + const [validatedPrebuiltTimelineStatus] = validate( + prebuiltTimelineStatus, + checkTimelineStatusRt + ); + + const responseBody: GetPrebuiltRulesAndTimelinesStatusResponse = { + rules_custom_installed: customRules.total, + rules_installed: installedPrebuiltRules.size, + rules_not_installed: rulesToInstall.length, + rules_not_updated: rulesToUpdate.length, + timelines_installed: validatedPrebuiltTimelineStatus?.prepackagedTimelines.length ?? 0, + timelines_not_installed: validatedPrebuiltTimelineStatus?.timelinesToInstall.length ?? 0, + timelines_not_updated: validatedPrebuiltTimelineStatus?.timelinesToUpdate.length ?? 0, + }; + + const [validatedBody, validationError] = validate( + responseBody, + GetPrebuiltRulesAndTimelinesStatusResponse + ); + + if (validationError != null) { + return siemResponse.error({ statusCode: 500, body: validationError }); + } else { + return response.ok({ body: validatedBody ?? {} }); + } + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/route.test.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/route.test.ts index 6c6cfde2cbaa8..f529369438742 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/route.test.ts @@ -11,28 +11,30 @@ import { getFindResultWithSingleHit, getRuleMock, getBasicEmptySearchResponse, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock } from '../__mocks__'; -import type { AddPrepackagedRulesSchema } from '../../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import { addPrepackedRulesRoute, createPrepackagedRules } from './add_prepackaged_rules_route'; +} from '../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock } from '../../../routes/__mocks__'; +import type { PrebuiltRuleToInstall } from '../../../../../../common/detection_engine/prebuilt_rules'; +import { installPrebuiltRulesAndTimelinesRoute, createPrepackagedRules } from './route'; import { listMock } from '@kbn/lists-plugin/server/mocks'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; -import { installPrepackagedTimelines } from '../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines'; +import { installPrepackagedTimelines } from '../../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { legacyMigrate } from '../../rules/utils'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; +import { legacyMigrate } from '../../../rule_management'; -jest.mock('../../rules/utils', () => { - const actual = jest.requireActual('../../rules/utils'); +jest.mock('../../../rule_management/logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual( + '../../../rule_management/logic/rule_actions/legacy_action_migration' + ); return { ...actual, legacyMigrate: jest.fn(), }; }); -jest.mock('../../rules/get_prepackaged_rules', () => { +jest.mock('../../logic/get_latest_prebuilt_rules', () => { return { - getLatestPrepackagedRules: async (): Promise => { + getLatestPrebuiltRules: async (): Promise => { return [ { author: ['Elastic'], @@ -66,7 +68,7 @@ jest.mock('../../rules/get_prepackaged_rules', () => { }; }); -jest.mock('../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines', () => { +jest.mock('../../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines', () => { return { installPrepackagedTimelines: jest.fn().mockResolvedValue({ success: true, @@ -105,7 +107,7 @@ describe('add_prepackaged_rules_route', () => { context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse()) ); - addPrepackedRulesRoute(server.router); + installPrebuiltRulesAndTimelinesRoute(server.router); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/route.ts similarity index 71% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/route.ts index 9960101f399c7..4399627692e22 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/route.ts @@ -13,30 +13,30 @@ import type { ExceptionListClient } from '@kbn/lists-plugin/server'; import type { SecuritySolutionApiRequestHandlerContext, SecuritySolutionPluginRouter, -} from '../../../../types'; - -import type { PrePackagedRulesAndTimelinesSchema } from '../../../../../common/detection_engine/schemas/response/prepackaged_rules_schema'; -import { prePackagedRulesAndTimelinesSchema } from '../../../../../common/detection_engine/schemas/response/prepackaged_rules_schema'; -import { importTimelineResultSchema } from '../../../../../common/types/timeline'; -import { DETECTION_ENGINE_PREPACKAGED_URL } from '../../../../../common/constants'; - -import { getLatestPrepackagedRules } from '../../rules/get_prepackaged_rules'; -import { installPrepackagedRules } from '../../rules/install_prepacked_rules'; -import { updatePrepackagedRules } from '../../rules/update_prepacked_rules'; -import { getRulesToInstall } from '../../rules/get_rules_to_install'; -import { getRulesToUpdate } from '../../rules/get_rules_to_update'; -import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules'; -import { ruleAssetSavedObjectsClientFactory } from '../../rules/rule_asset/rule_asset_saved_objects_client'; - -import { buildSiemResponse } from '../utils'; - -import { installPrepackagedTimelines } from '../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines'; -import { rulesToMap } from '../../rules/utils'; - -export const addPrepackedRulesRoute = (router: SecuritySolutionPluginRouter) => { +} from '../../../../../types'; + +import { + PREBUILT_RULES_URL, + InstallPrebuiltRulesAndTimelinesResponse, +} from '../../../../../../common/detection_engine/prebuilt_rules'; +import { importTimelineResultSchema } from '../../../../../../common/types/timeline'; + +import { getExistingPrepackagedRules } from '../../../rule_management/logic/search/get_existing_prepackaged_rules'; +import { getLatestPrebuiltRules } from '../../logic/get_latest_prebuilt_rules'; +import { createPrebuiltRules } from '../../logic/create_prebuilt_rules'; +import { updatePrebuiltRules } from '../../logic/update_prebuilt_rules'; +import { getRulesToInstall } from '../../logic/get_rules_to_install'; +import { getRulesToUpdate } from '../../logic/get_rules_to_update'; +import { ruleAssetSavedObjectsClientFactory } from '../../logic/rule_asset/rule_asset_saved_objects_client'; +import { rulesToMap } from '../../logic/utils'; + +import { installPrepackagedTimelines } from '../../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines'; +import { buildSiemResponse } from '../../../routes/utils'; + +export const installPrebuiltRulesAndTimelinesRoute = (router: SecuritySolutionPluginRouter) => { router.put( { - path: DETECTION_ENGINE_PREPACKAGED_URL, + path: PREBUILT_RULES_URL, validate: false, options: { tags: ['access:securitySolution'], @@ -84,7 +84,7 @@ export const createPrepackagedRules = async ( context: SecuritySolutionApiRequestHandlerContext, rulesClient: RulesClient, exceptionsClient?: ExceptionListClient -): Promise => { +): Promise => { const config = context.getConfig(); const frameworkRequest = context.getFrameworkRequest(); const savedObjectsClient = context.core.savedObjects.client; @@ -107,7 +107,7 @@ export const createPrepackagedRules = async ( await exceptionsListClient.createEndpointList(); } - const latestPrepackagedRulesMap = await getLatestPrepackagedRules( + const latestPrepackagedRulesMap = await getLatestPrebuiltRules( ruleAssetsClient, prebuiltRulesFromFileSystem, prebuiltRulesFromSavedObjects @@ -116,7 +116,8 @@ export const createPrepackagedRules = async ( const rulesToInstall = getRulesToInstall(latestPrepackagedRulesMap, installedPrePackagedRules); const rulesToUpdate = getRulesToUpdate(latestPrepackagedRulesMap, installedPrePackagedRules); - await installPrepackagedRules(rulesClient, rulesToInstall); + await createPrebuiltRules(rulesClient, rulesToInstall); + const timeline = await installPrepackagedTimelines( maxTimelineImportExportSize, frameworkRequest, @@ -126,28 +127,32 @@ export const createPrepackagedRules = async ( timeline, importTimelineResultSchema ); - await updatePrepackagedRules( + + await updatePrebuiltRules( rulesClient, savedObjectsClient, rulesToUpdate, context.getRuleExecutionLog() ); - const prepackagedRulesOutput: PrePackagedRulesAndTimelinesSchema = { + const prepackagedRulesOutput: InstallPrebuiltRulesAndTimelinesResponse = { rules_installed: rulesToInstall.length, rules_updated: rulesToUpdate.length, timelines_installed: prepackagedTimelinesResult?.timelines_installed ?? 0, timelines_updated: prepackagedTimelinesResult?.timelines_updated ?? 0, }; + const [validated, genericErrors] = validate( prepackagedRulesOutput, - prePackagedRulesAndTimelinesSchema + InstallPrebuiltRulesAndTimelinesResponse ); + if (genericErrors != null && timelinesErrors != null) { throw new PrepackagedRulesError( [genericErrors, timelinesErrors].filter((msg) => msg != null).join(', '), 500 ); } + return validated; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/register_routes.ts new file mode 100644 index 0000000000000..39e822af3e147 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/register_routes.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 { ConfigType } from '../../../../config'; +import type { SetupPlugins } from '../../../../plugin_contract'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; + +import { getPrebuiltRulesAndTimelinesStatusRoute } from './get_prebuilt_rules_and_timelines_status/route'; +import { installPrebuiltRulesAndTimelinesRoute } from './install_prebuilt_rules_and_timelines/route'; + +export const registerPrebuiltRulesRoutes = ( + router: SecuritySolutionPluginRouter, + config: ConfigType, + security: SetupPlugins['security'] +) => { + getPrebuiltRulesAndTimelinesStatusRoute(router, config, security); + installPrebuiltRulesAndTimelinesRoute(router); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/apm_403_response_to_a_post.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/apm_403_response_to_a_post.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/apm_403_response_to_a_post.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/apm_403_response_to_a_post.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/apm_405_response_method_not_allowed.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/apm_405_response_method_not_allowed.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/apm_405_response_method_not_allowed.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/apm_405_response_method_not_allowed.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/apm_sqlmap_user_agent.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/apm_sqlmap_user_agent.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/apm_sqlmap_user_agent.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/apm_sqlmap_user_agent.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_cloudtrail_logging_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_cloudtrail_logging_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_cloudtrail_logging_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_cloudtrail_logging_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_email_powershell_exchange_mailbox.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_email_powershell_exchange_mailbox.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_email_powershell_exchange_mailbox.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_email_powershell_exchange_mailbox.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_gcp_pub_sub_subscription_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_gcp_pub_sub_subscription_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_gcp_pub_sub_subscription_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_gcp_pub_sub_subscription_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_gcp_pub_sub_topic_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_gcp_pub_sub_topic_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_gcp_pub_sub_topic_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_gcp_pub_sub_topic_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_google_drive_ownership_transferred_via_google_workspace.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_google_drive_ownership_transferred_via_google_workspace.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_google_drive_ownership_transferred_via_google_workspace.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_google_drive_ownership_transferred_via_google_workspace.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_google_workspace_custom_gmail_route_created_or_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_google_workspace_custom_gmail_route_created_or_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_google_workspace_custom_gmail_route_created_or_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_google_workspace_custom_gmail_route_created_or_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_microsoft_365_new_inbox_rule.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_microsoft_365_new_inbox_rule.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_microsoft_365_new_inbox_rule.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_microsoft_365_new_inbox_rule.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_posh_audio_capture.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_posh_audio_capture.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_posh_audio_capture.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_posh_audio_capture.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_posh_keylogger.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_posh_keylogger.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_posh_keylogger.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_posh_keylogger.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_posh_screen_grabber.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_posh_screen_grabber.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_posh_screen_grabber.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_posh_screen_grabber.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_update_event_hub_auth_rule.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_update_event_hub_auth_rule.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_update_event_hub_auth_rule.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_update_event_hub_auth_rule.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_winrar_encryption.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_winrar_encryption.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/collection_winrar_encryption.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/collection_winrar_encryption.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_certutil_network_connection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_certutil_network_connection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_certutil_network_connection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_certutil_network_connection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_cobalt_strike_beacon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_cobalt_strike_beacon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_cobalt_strike_beacon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_cobalt_strike_beacon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_cobalt_strike_default_teamserver_cert.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_cobalt_strike_default_teamserver_cert.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_cobalt_strike_default_teamserver_cert.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_cobalt_strike_default_teamserver_cert.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_common_webservices.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_common_webservices.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_common_webservices.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_common_webservices.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_connection_attempt_by_non_ssh_root_session.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_connection_attempt_by_non_ssh_root_session.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_connection_attempt_by_non_ssh_root_session.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_connection_attempt_by_non_ssh_root_session.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_dns_tunneling_nslookup.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_dns_tunneling_nslookup.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_dns_tunneling_nslookup.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_dns_tunneling_nslookup.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_download_rar_powershell_from_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_download_rar_powershell_from_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_download_rar_powershell_from_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_download_rar_powershell_from_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_encrypted_channel_freesslcert.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_encrypted_channel_freesslcert.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_encrypted_channel_freesslcert.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_encrypted_channel_freesslcert.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_fin7_c2_behavior.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_fin7_c2_behavior.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_fin7_c2_behavior.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_fin7_c2_behavior.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_halfbaked_beacon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_halfbaked_beacon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_halfbaked_beacon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_halfbaked_beacon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_iexplore_via_com.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_iexplore_via_com.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_iexplore_via_com.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_iexplore_via_com.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_linux_iodine_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_linux_iodine_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_linux_iodine_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_linux_iodine_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_dns_tunneling.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_dns_tunneling.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_dns_tunneling.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_dns_tunneling.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_rare_dns_question.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_rare_dns_question.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_rare_dns_question.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_rare_dns_question.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_rare_urls.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_rare_urls.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_rare_urls.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_rare_urls.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_rare_user_agent.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_rare_user_agent.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_ml_packetbeat_rare_user_agent.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_ml_packetbeat_rare_user_agent.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_nat_traversal_port_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_nat_traversal_port_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_nat_traversal_port_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_nat_traversal_port_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_port_26_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_port_26_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_port_26_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_port_26_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_port_forwarding_added_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_port_forwarding_added_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_port_forwarding_added_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_port_forwarding_added_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_rdp_remote_desktop_protocol_from_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_rdp_remote_desktop_protocol_from_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_rdp_remote_desktop_protocol_from_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_rdp_remote_desktop_protocol_from_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_rdp_tunnel_plink.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_rdp_tunnel_plink.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_rdp_tunnel_plink.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_rdp_tunnel_plink.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_desktopimgdownldr.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_desktopimgdownldr.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_desktopimgdownldr.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_desktopimgdownldr.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_mpcmdrun.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_mpcmdrun.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_mpcmdrun.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_mpcmdrun.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_powershell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_powershell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_powershell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_powershell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_scripts.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_scripts.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_remote_file_copy_scripts.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_remote_file_copy_scripts.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_sunburst_c2_activity_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_sunburst_c2_activity_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_sunburst_c2_activity_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_sunburst_c2_activity_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_teamviewer_remote_file_copy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_teamviewer_remote_file_copy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_teamviewer_remote_file_copy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_teamviewer_remote_file_copy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_telnet_port_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_telnet_port_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_telnet_port_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_telnet_port_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_tunneling_via_earthworm.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_tunneling_via_earthworm.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_tunneling_via_earthworm.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_tunneling_via_earthworm.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_vnc_virtual_network_computing_from_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_vnc_virtual_network_computing_from_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_vnc_virtual_network_computing_from_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_vnc_virtual_network_computing_from_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_vnc_virtual_network_computing_to_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_vnc_virtual_network_computing_to_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/command_and_control_vnc_virtual_network_computing_to_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/command_and_control_vnc_virtual_network_computing_to_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_access_to_browser_credentials_procargs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_access_to_browser_credentials_procargs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_access_to_browser_credentials_procargs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_access_to_browser_credentials_procargs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_attempted_bypass_of_okta_mfa.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_attempted_bypass_of_okta_mfa.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_attempted_bypass_of_okta_mfa.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_attempted_bypass_of_okta_mfa.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_attempts_to_brute_force_okta_user_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_attempts_to_brute_force_okta_user_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_attempts_to_brute_force_okta_user_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_attempts_to_brute_force_okta_user_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_aws_iam_assume_role_brute_force.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_aws_iam_assume_role_brute_force.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_aws_iam_assume_role_brute_force.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_aws_iam_assume_role_brute_force.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_azure_full_network_packet_capture_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_azure_full_network_packet_capture_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_azure_full_network_packet_capture_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_azure_full_network_packet_capture_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_admin_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_admin_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_admin_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_admin_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_followed_by_success.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_followed_by_success.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_followed_by_success.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_followed_by_success.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_same_srcip.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_same_srcip.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_same_srcip.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_multiple_logon_failure_same_srcip.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_passowrd_guessing.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_passowrd_guessing.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_bruteforce_passowrd_guessing.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_bruteforce_passowrd_guessing.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_cmdline_dump_tool.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_cmdline_dump_tool.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_cmdline_dump_tool.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_cmdline_dump_tool.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_collection_sensitive_files.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_collection_sensitive_files.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_collection_sensitive_files.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_collection_sensitive_files.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_cookies_chromium_browsers_debugging.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_cookies_chromium_browsers_debugging.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_cookies_chromium_browsers_debugging.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_cookies_chromium_browsers_debugging.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_copy_ntds_sam_volshadowcp_cmdline.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_copy_ntds_sam_volshadowcp_cmdline.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_copy_ntds_sam_volshadowcp_cmdline.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_copy_ntds_sam_volshadowcp_cmdline.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_credential_dumping_msbuild.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_credential_dumping_msbuild.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_credential_dumping_msbuild.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_credential_dumping_msbuild.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_credentials_keychains.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_credentials_keychains.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_credentials_keychains.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_credentials_keychains.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dcsync_replication_rights.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dcsync_replication_rights.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dcsync_replication_rights.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dcsync_replication_rights.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_disable_kerberos_preauth.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_disable_kerberos_preauth.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_disable_kerberos_preauth.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_disable_kerberos_preauth.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_domain_backup_dpapi_private_keys.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_domain_backup_dpapi_private_keys.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_domain_backup_dpapi_private_keys.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_domain_backup_dpapi_private_keys.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dump_registry_hives.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dump_registry_hives.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dump_registry_hives.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dump_registry_hives.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dumping_hashes_bi_cmds.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dumping_hashes_bi_cmds.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dumping_hashes_bi_cmds.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dumping_hashes_bi_cmds.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dumping_keychain_security.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dumping_keychain_security.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_dumping_keychain_security.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_dumping_keychain_security.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_endgame_cred_dumping_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_endgame_cred_dumping_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_endgame_cred_dumping_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_endgame_cred_dumping_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_endgame_cred_dumping_prevented.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_endgame_cred_dumping_prevented.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_endgame_cred_dumping_prevented.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_endgame_cred_dumping_prevented.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_generic_localdumps.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_generic_localdumps.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_generic_localdumps.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_generic_localdumps.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_iam_user_addition_to_group.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_iam_user_addition_to_group.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_iam_user_addition_to_group.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_iam_user_addition_to_group.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_iis_apppoolsa_pwd_appcmd.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_iis_apppoolsa_pwd_appcmd.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_iis_apppoolsa_pwd_appcmd.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_iis_apppoolsa_pwd_appcmd.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_iis_connectionstrings_dumping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_iis_connectionstrings_dumping.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_iis_connectionstrings_dumping.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_iis_connectionstrings_dumping.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_kerberoasting_unusual_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_kerberoasting_unusual_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_kerberoasting_unusual_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_kerberoasting_unusual_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_kerberosdump_kcc.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_kerberosdump_kcc.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_kerberosdump_kcc.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_kerberosdump_kcc.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_key_vault_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_key_vault_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_key_vault_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_key_vault_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_keychain_pwd_retrieval_security_cmd.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_keychain_pwd_retrieval_security_cmd.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_keychain_pwd_retrieval_security_cmd.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_keychain_pwd_retrieval_security_cmd.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_lsass_handle_via_malseclogon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_lsass_handle_via_malseclogon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_lsass_handle_via_malseclogon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_lsass_handle_via_malseclogon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_lsass_memdump_file_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_lsass_memdump_file_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_lsass_memdump_file_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_lsass_memdump_file_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_lsass_memdump_handle_access.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_lsass_memdump_handle_access.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_lsass_memdump_handle_access.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_lsass_memdump_handle_access.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mfa_push_brute_force.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mfa_push_brute_force.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mfa_push_brute_force.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mfa_push_brute_force.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_microsoft_365_brute_force_user_account_attempt.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_microsoft_365_brute_force_user_account_attempt.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_microsoft_365_brute_force_user_account_attempt.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_microsoft_365_brute_force_user_account_attempt.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_microsoft_365_potential_password_spraying_attack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_microsoft_365_potential_password_spraying_attack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_microsoft_365_potential_password_spraying_attack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_microsoft_365_potential_password_spraying_attack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mimikatz_memssp_default_logs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mimikatz_memssp_default_logs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mimikatz_memssp_default_logs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mimikatz_memssp_default_logs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mimikatz_powershell_module.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mimikatz_powershell_module.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mimikatz_powershell_module.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mimikatz_powershell_module.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mitm_localhost_webproxy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mitm_localhost_webproxy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mitm_localhost_webproxy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mitm_localhost_webproxy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_auth_spike_in_failed_logon_events.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_auth_spike_in_failed_logon_events.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_auth_spike_in_failed_logon_events.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_auth_spike_in_failed_logon_events.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events_from_a_source_ip.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events_from_a_source_ip.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events_from_a_source_ip.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_auth_spike_in_logon_events_from_a_source_ip.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_linux_anomalous_metadata_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_suspicious_login_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_suspicious_login_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_suspicious_login_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_suspicious_login_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ml_windows_anomalous_metadata_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mod_wdigest_security_provider.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mod_wdigest_security_provider.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_mod_wdigest_security_provider.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_mod_wdigest_security_provider.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_moving_registry_hive_via_smb.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_moving_registry_hive_via_smb.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_moving_registry_hive_via_smb.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_moving_registry_hive_via_smb.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_okta_brute_force_or_password_spraying.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_okta_brute_force_or_password_spraying.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_okta_brute_force_or_password_spraying.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_okta_brute_force_or_password_spraying.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_persistence_network_logon_provider_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_persistence_network_logon_provider_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_persistence_network_logon_provider_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_persistence_network_logon_provider_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_posh_minidump.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_posh_minidump.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_posh_minidump.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_posh_minidump.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_posh_request_ticket.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_posh_request_ticket.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_posh_request_ticket.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_posh_request_ticket.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce_root.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce_root.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce_root.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_linux_ssh_bruteforce_root.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_lsa_memdump_via_mirrordump.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_lsa_memdump_via_mirrordump.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_lsa_memdump_via_mirrordump.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_lsa_memdump_via_mirrordump.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_macos_ssh_bruteforce.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_macos_ssh_bruteforce.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_potential_macos_ssh_bruteforce.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_potential_macos_ssh_bruteforce.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_promt_for_pwd_via_osascript.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_promt_for_pwd_via_osascript.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_promt_for_pwd_via_osascript.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_promt_for_pwd_via_osascript.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_relay_ntlm_auth_via_http_spoolss.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_relay_ntlm_auth_via_http_spoolss.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_relay_ntlm_auth_via_http_spoolss.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_relay_ntlm_auth_via_http_spoolss.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_remote_sam_secretsdump.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_remote_sam_secretsdump.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_remote_sam_secretsdump.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_remote_sam_secretsdump.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_root_console_failure_brute_force.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_root_console_failure_brute_force.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_root_console_failure_brute_force.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_root_console_failure_brute_force.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_saved_creds_vault_winlog.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_saved_creds_vault_winlog.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_saved_creds_vault_winlog.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_saved_creds_vault_winlog.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_saved_creds_vaultcmd.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_saved_creds_vaultcmd.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_saved_creds_vaultcmd.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_saved_creds_vaultcmd.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_secretsmanager_getsecretvalue.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_secretsmanager_getsecretvalue.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_secretsmanager_getsecretvalue.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_secretsmanager_getsecretvalue.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_seenabledelegationprivilege_assigned_to_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_seenabledelegationprivilege_assigned_to_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_seenabledelegationprivilege_assigned_to_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_seenabledelegationprivilege_assigned_to_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_shadow_credentials.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_shadow_credentials.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_shadow_credentials.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_shadow_credentials.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_spn_attribute_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_spn_attribute_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_spn_attribute_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_spn_attribute_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ssh_backdoor_log.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ssh_backdoor_log.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_ssh_backdoor_log.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_ssh_backdoor_log.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_storage_account_key_regenerated.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_storage_account_key_regenerated.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_storage_account_key_regenerated.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_storage_account_key_regenerated.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_comsvcs_imageload.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_comsvcs_imageload.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_comsvcs_imageload.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_comsvcs_imageload.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_lsass_access_memdump.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_lsass_access_memdump.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_lsass_access_memdump.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_lsass_access_memdump.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_lsass_access_via_snapshot.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_lsass_access_via_snapshot.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_lsass_access_via_snapshot.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_lsass_access_via_snapshot.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_winreg_access_via_sebackup_priv.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_winreg_access_via_sebackup_priv.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_suspicious_winreg_access_via_sebackup_priv.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_suspicious_winreg_access_via_sebackup_priv.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_symbolic_link_to_shadow_copy_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_symbolic_link_to_shadow_copy_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_symbolic_link_to_shadow_copy_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_symbolic_link_to_shadow_copy_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_systemkey_dumping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_systemkey_dumping.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_systemkey_dumping.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_systemkey_dumping.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_user_excessive_sso_logon_errors.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_user_excessive_sso_logon_errors.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_user_excessive_sso_logon_errors.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_user_excessive_sso_logon_errors.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_user_impersonation_access.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_user_impersonation_access.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_user_impersonation_access.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_user_impersonation_access.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_via_snapshot_lsass_clone_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_via_snapshot_lsass_clone_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/credential_access_via_snapshot_lsass_clone_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/credential_access_via_snapshot_lsass_clone_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_adding_the_hidden_file_attribute_with_via_attribexe.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_adding_the_hidden_file_attribute_with_via_attribexe.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_adding_the_hidden_file_attribute_with_via_attribexe.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_adding_the_hidden_file_attribute_with_via_attribexe.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_agent_spoofing_mismatched_id.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_agent_spoofing_mismatched_id.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_agent_spoofing_mismatched_id.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_agent_spoofing_mismatched_id.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_agent_spoofing_multiple_hosts.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_agent_spoofing_multiple_hosts.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_agent_spoofing_multiple_hosts.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_agent_spoofing_multiple_hosts.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_amsienable_key_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_amsienable_key_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_amsienable_key_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_amsienable_key_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_apple_softupdates_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_apple_softupdates_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_apple_softupdates_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_apple_softupdates_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_application_removed_from_blocklist_in_google_workspace.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_application_removed_from_blocklist_in_google_workspace.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_application_removed_from_blocklist_in_google_workspace.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_application_removed_from_blocklist_in_google_workspace.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_del_quarantine_attrib.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_del_quarantine_attrib.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_del_quarantine_attrib.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_del_quarantine_attrib.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_deactivate_okta_network_zone.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_deactivate_okta_network_zone.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_deactivate_okta_network_zone.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_deactivate_okta_network_zone.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_delete_okta_network_zone.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_delete_okta_network_zone.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_delete_okta_network_zone.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_delete_okta_network_zone.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_disable_gatekeeper.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_disable_gatekeeper.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_disable_gatekeeper.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_disable_gatekeeper.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_disable_syslog_service.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_disable_syslog_service.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_attempt_to_disable_syslog_service.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_attempt_to_disable_syslog_service.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_application_credential_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_application_credential_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_application_credential_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_application_credential_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_automation_runbook_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_automation_runbook_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_automation_runbook_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_automation_runbook_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_blob_permissions_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_blob_permissions_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_blob_permissions_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_blob_permissions_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_diagnostic_settings_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_diagnostic_settings_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_diagnostic_settings_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_diagnostic_settings_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_service_principal_addition.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_service_principal_addition.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_azure_service_principal_addition.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_azure_service_principal_addition.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_base16_or_base32_encoding_or_decoding_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_base16_or_base32_encoding_or_decoding_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_base16_or_base32_encoding_or_decoding_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_base16_or_base32_encoding_or_decoding_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_chattr_immutable_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_chattr_immutable_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_chattr_immutable_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_chattr_immutable_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_clearing_windows_console_history.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_clearing_windows_console_history.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_clearing_windows_console_history.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_clearing_windows_console_history.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_clearing_windows_event_logs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_clearing_windows_event_logs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_clearing_windows_event_logs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_clearing_windows_event_logs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_clearing_windows_security_logs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_clearing_windows_security_logs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_clearing_windows_security_logs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_clearing_windows_security_logs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cloudtrail_logging_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cloudtrail_logging_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cloudtrail_logging_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cloudtrail_logging_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cloudtrail_logging_suspended.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cloudtrail_logging_suspended.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cloudtrail_logging_suspended.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cloudtrail_logging_suspended.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cloudwatch_alarm_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cloudwatch_alarm_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cloudwatch_alarm_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cloudwatch_alarm_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_config_service_rule_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_config_service_rule_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_config_service_rule_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_config_service_rule_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_configuration_recorder_stopped.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_configuration_recorder_stopped.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_configuration_recorder_stopped.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_configuration_recorder_stopped.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_create_mod_root_certificate.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_create_mod_root_certificate.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_create_mod_root_certificate.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_create_mod_root_certificate.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cve_2020_0601.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cve_2020_0601.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_cve_2020_0601.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_cve_2020_0601.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_defender_disabled_via_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_defender_disabled_via_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_defender_disabled_via_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_defender_disabled_via_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_defender_exclusion_via_powershell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_defender_exclusion_via_powershell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_defender_exclusion_via_powershell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_defender_exclusion_via_powershell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_delete_volume_usn_journal_with_fsutil.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_delete_volume_usn_journal_with_fsutil.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_delete_volume_usn_journal_with_fsutil.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_delete_volume_usn_journal_with_fsutil.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_deleting_websvr_access_logs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_deleting_websvr_access_logs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_deleting_websvr_access_logs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_deleting_websvr_access_logs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_deletion_of_bash_command_line_history.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_deletion_of_bash_command_line_history.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_deletion_of_bash_command_line_history.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_deletion_of_bash_command_line_history.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disable_posh_scriptblocklogging.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disable_posh_scriptblocklogging.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disable_posh_scriptblocklogging.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disable_posh_scriptblocklogging.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disable_selinux_attempt.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disable_selinux_attempt.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disable_selinux_attempt.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disable_selinux_attempt.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disable_windows_firewall_rules_with_netsh.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disable_windows_firewall_rules_with_netsh.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disable_windows_firewall_rules_with_netsh.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disable_windows_firewall_rules_with_netsh.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disabling_windows_defender_powershell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disabling_windows_defender_powershell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disabling_windows_defender_powershell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disabling_windows_defender_powershell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disabling_windows_logs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disabling_windows_logs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_disabling_windows_logs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_disabling_windows_logs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_dns_over_https_enabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_dns_over_https_enabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_dns_over_https_enabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_dns_over_https_enabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_domain_added_to_google_workspace_trusted_domains.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_domain_added_to_google_workspace_trusted_domains.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_domain_added_to_google_workspace_trusted_domains.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_domain_added_to_google_workspace_trusted_domains.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_dotnet_compiler_parent_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_dotnet_compiler_parent_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_dotnet_compiler_parent_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_dotnet_compiler_parent_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_ec2_flow_log_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_ec2_flow_log_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_ec2_flow_log_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_ec2_flow_log_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_ec2_network_acl_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_ec2_network_acl_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_ec2_network_acl_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_ec2_network_acl_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_elastic_agent_service_terminated.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_elastic_agent_service_terminated.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_elastic_agent_service_terminated.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_elastic_agent_service_terminated.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_elasticache_security_group_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_elasticache_security_group_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_elasticache_security_group_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_elasticache_security_group_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_elasticache_security_group_modified_or_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_elasticache_security_group_modified_or_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_elasticache_security_group_modified_or_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_elasticache_security_group_modified_or_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_enable_inbound_rdp_with_netsh.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_enable_inbound_rdp_with_netsh.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_enable_inbound_rdp_with_netsh.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_enable_inbound_rdp_with_netsh.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_enable_network_discovery_with_netsh.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_enable_network_discovery_with_netsh.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_enable_network_discovery_with_netsh.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_enable_network_discovery_with_netsh.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_event_hub_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_event_hub_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_event_hub_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_event_hub_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_control_panel_suspicious_args.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_control_panel_suspicious_args.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_control_panel_suspicious_args.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_control_panel_suspicious_args.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_lolbas_wuauclt.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_lolbas_wuauclt.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_lolbas_wuauclt.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_lolbas_wuauclt.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_by_office_app.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_by_office_app.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_by_office_app.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_by_office_app.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_by_script.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_by_script.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_by_script.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_by_script.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_by_system_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_by_system_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_by_system_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_by_system_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_renamed.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_renamed.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_renamed.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_renamed.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_unusal_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_unusal_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_msbuild_started_unusal_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_msbuild_started_unusal_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_suspicious_explorer_winword.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_suspicious_explorer_winword.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_suspicious_explorer_winword.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_suspicious_explorer_winword.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_windefend_unusual_path.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_windefend_unusual_path.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_execution_windefend_unusual_path.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_execution_windefend_unusual_path.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_file_creation_mult_extension.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_file_creation_mult_extension.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_file_creation_mult_extension.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_file_creation_mult_extension.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_file_deletion_via_shred.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_file_deletion_via_shred.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_file_deletion_via_shred.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_file_deletion_via_shred.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_file_mod_writable_dir.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_file_mod_writable_dir.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_file_mod_writable_dir.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_file_mod_writable_dir.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_firewall_policy_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_firewall_policy_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_firewall_policy_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_firewall_policy_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_from_unusual_directory.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_from_unusual_directory.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_from_unusual_directory.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_from_unusual_directory.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_frontdoor_firewall_policy_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_frontdoor_firewall_policy_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_frontdoor_firewall_policy_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_frontdoor_firewall_policy_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_firewall_rule_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_firewall_rule_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_firewall_rule_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_firewall_rule_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_firewall_rule_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_firewall_rule_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_firewall_rule_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_firewall_rule_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_firewall_rule_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_firewall_rule_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_firewall_rule_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_firewall_rule_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_logging_bucket_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_logging_bucket_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_logging_bucket_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_logging_bucket_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_logging_sink_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_logging_sink_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_logging_sink_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_logging_sink_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_pub_sub_subscription_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_pub_sub_subscription_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_pub_sub_subscription_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_pub_sub_subscription_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_pub_sub_topic_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_pub_sub_topic_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_pub_sub_topic_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_pub_sub_topic_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_storage_bucket_configuration_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_storage_bucket_configuration_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_storage_bucket_configuration_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_storage_bucket_configuration_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_storage_bucket_permissions_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_storage_bucket_permissions_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_storage_bucket_permissions_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_storage_bucket_permissions_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_network_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_network_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_network_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_network_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_gcp_virtual_private_cloud_route_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_google_workspace_bitlocker_setting_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_google_workspace_bitlocker_setting_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_google_workspace_bitlocker_setting_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_google_workspace_bitlocker_setting_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_google_workspace_restrictions_for_google_marketplace_changed_to_allow_any_app.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_google_workspace_restrictions_for_google_marketplace_changed_to_allow_any_app.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_google_workspace_restrictions_for_google_marketplace_changed_to_allow_any_app.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_google_workspace_restrictions_for_google_marketplace_changed_to_allow_any_app.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_guardduty_detector_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_guardduty_detector_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_guardduty_detector_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_guardduty_detector_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_hidden_file_dir_tmp.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_hidden_file_dir_tmp.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_hidden_file_dir_tmp.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_hidden_file_dir_tmp.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_hidden_shared_object.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_hidden_shared_object.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_hidden_shared_object.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_hidden_shared_object.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_hide_encoded_executable_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_hide_encoded_executable_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_hide_encoded_executable_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_hide_encoded_executable_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_iis_httplogging_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_iis_httplogging_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_iis_httplogging_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_iis_httplogging_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_injection_msbuild.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_injection_msbuild.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_injection_msbuild.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_injection_msbuild.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_install_root_certificate.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_install_root_certificate.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_install_root_certificate.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_install_root_certificate.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_installutil_beacon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_installutil_beacon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_installutil_beacon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_installutil_beacon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_kernel_module_removal.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_kernel_module_removal.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_kernel_module_removal.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_kernel_module_removal.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_kubernetes_events_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_kubernetes_events_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_kubernetes_events_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_kubernetes_events_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_log_files_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_log_files_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_log_files_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_log_files_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_as_elastic_endpoint_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_as_elastic_endpoint_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_as_elastic_endpoint_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_as_elastic_endpoint_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_renamed_autoit.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_renamed_autoit.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_renamed_autoit.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_renamed_autoit.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_suspicious_werfault_childproc.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_suspicious_werfault_childproc.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_suspicious_werfault_childproc.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_suspicious_werfault_childproc.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_trusted_directory.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_trusted_directory.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_trusted_directory.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_trusted_directory.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_werfault.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_werfault.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_masquerading_werfault.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_masquerading_werfault.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_dlp_policy_removed.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_dlp_policy_removed.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_dlp_policy_removed.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_dlp_policy_removed.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_policy_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_policy_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_policy_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_policy_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_rule_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_rule_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_rule_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_malware_filter_rule_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_safe_attach_rule_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_safe_attach_rule_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_exchange_safe_attach_rule_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_exchange_safe_attach_rule_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_mailboxauditbypassassociation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_mailboxauditbypassassociation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_365_mailboxauditbypassassociation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_365_mailboxauditbypassassociation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_defender_tampering.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_defender_tampering.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_microsoft_defender_tampering.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_microsoft_defender_tampering.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_misc_lolbin_connecting_to_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_misc_lolbin_connecting_to_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_misc_lolbin_connecting_to_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_misc_lolbin_connecting_to_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_modify_environment_launchctl.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_modify_environment_launchctl.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_modify_environment_launchctl.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_modify_environment_launchctl.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_ms_office_suspicious_regmod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_ms_office_suspicious_regmod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_ms_office_suspicious_regmod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_ms_office_suspicious_regmod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_msbuild_making_network_connections.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_msbuild_making_network_connections.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_msbuild_making_network_connections.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_msbuild_making_network_connections.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_mshta_beacon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_mshta_beacon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_mshta_beacon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_mshta_beacon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_msxsl_network.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_msxsl_network.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_msxsl_network.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_msxsl_network.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_network_connection_from_windows_binary.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_network_connection_from_windows_binary.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_network_connection_from_windows_binary.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_network_connection_from_windows_binary.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_network_watcher_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_network_watcher_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_network_watcher_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_network_watcher_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy_rule.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy_rule.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy_rule.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_deactivate_okta_policy_rule.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy_rule.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy_rule.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy_rule.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_delete_okta_policy_rule.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_network_zone.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_network_zone.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_network_zone.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_network_zone.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy_rule.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy_rule.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy_rule.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_okta_attempt_to_modify_okta_policy_rule.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_parent_process_pid_spoofing.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_parent_process_pid_spoofing.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_parent_process_pid_spoofing.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_parent_process_pid_spoofing.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_persistence_temp_scheduled_task.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_persistence_temp_scheduled_task.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_persistence_temp_scheduled_task.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_persistence_temp_scheduled_task.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_posh_assembly_load.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_posh_assembly_load.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_posh_assembly_load.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_posh_assembly_load.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_posh_compressed.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_posh_compressed.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_posh_compressed.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_posh_compressed.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_posh_process_injection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_posh_process_injection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_posh_process_injection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_posh_process_injection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_potential_processherpaderping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_potential_processherpaderping.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_potential_processherpaderping.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_potential_processherpaderping.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_powershell_windows_firewall_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_powershell_windows_firewall_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_powershell_windows_firewall_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_powershell_windows_firewall_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_privacy_controls_tcc_database_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_privacy_controls_tcc_database_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_privacy_controls_tcc_database_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_privacy_controls_tcc_database_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_privilege_escalation_privacy_pref_sshd_fulldiskaccess.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_privilege_escalation_privacy_pref_sshd_fulldiskaccess.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_privilege_escalation_privacy_pref_sshd_fulldiskaccess.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_privilege_escalation_privacy_pref_sshd_fulldiskaccess.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_process_termination_followed_by_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_process_termination_followed_by_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_process_termination_followed_by_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_process_termination_followed_by_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_proxy_execution_via_msdt.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_proxy_execution_via_msdt.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_proxy_execution_via_msdt.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_proxy_execution_via_msdt.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_rundll32_no_arguments.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_rundll32_no_arguments.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_rundll32_no_arguments.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_rundll32_no_arguments.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_s3_bucket_configuration_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_s3_bucket_configuration_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_s3_bucket_configuration_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_s3_bucket_configuration_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_safari_config_change.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_safari_config_change.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_safari_config_change.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_safari_config_change.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_sandboxed_office_app_suspicious_zip_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_sandboxed_office_app_suspicious_zip_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_sandboxed_office_app_suspicious_zip_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_sandboxed_office_app_suspicious_zip_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_scheduledjobs_at_protocol_enabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_scheduledjobs_at_protocol_enabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_scheduledjobs_at_protocol_enabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_scheduledjobs_at_protocol_enabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_sdelete_like_filename_rename.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_sdelete_like_filename_rename.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_sdelete_like_filename_rename.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_sdelete_like_filename_rename.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_sip_provider_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_sip_provider_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_sip_provider_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_sip_provider_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_solarwinds_backdoor_service_disabled_via_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_solarwinds_backdoor_service_disabled_via_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_solarwinds_backdoor_service_disabled_via_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_solarwinds_backdoor_service_disabled_via_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suppression_rule_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suppression_rule_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suppression_rule_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suppression_rule_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_certutil_commands.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_certutil_commands.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_certutil_commands.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_certutil_commands.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_execution_from_mounted_device.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_execution_from_mounted_device.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_execution_from_mounted_device.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_execution_from_mounted_device.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_managedcode_host_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_managedcode_host_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_managedcode_host_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_managedcode_host_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_okta_user_password_reset_or_unlock_attempts.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_okta_user_password_reset_or_unlock_attempts.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_okta_user_password_reset_or_unlock_attempts.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_okta_user_password_reset_or_unlock_attempts.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_process_access_direct_syscall.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_process_access_direct_syscall.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_process_access_direct_syscall.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_process_access_direct_syscall.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_process_creation_calltrace.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_process_creation_calltrace.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_process_creation_calltrace.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_process_creation_calltrace.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_scrobj_load.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_scrobj_load.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_scrobj_load.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_scrobj_load.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_short_program_name.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_short_program_name.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_short_program_name.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_short_program_name.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_wmi_script.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_wmi_script.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_wmi_script.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_wmi_script.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_zoom_child_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_zoom_child_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_suspicious_zoom_child_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_suspicious_zoom_child_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_system_critical_proc_abnormal_file_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_system_critical_proc_abnormal_file_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_system_critical_proc_abnormal_file_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_system_critical_proc_abnormal_file_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_tcc_bypass_mounted_apfs_access.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_tcc_bypass_mounted_apfs_access.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_tcc_bypass_mounted_apfs_access.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_tcc_bypass_mounted_apfs_access.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_timestomp_touch.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_timestomp_touch.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_timestomp_touch.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_timestomp_touch.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unload_endpointsecurity_kext.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unload_endpointsecurity_kext.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unload_endpointsecurity_kext.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unload_endpointsecurity_kext.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_ads_file_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_ads_file_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_ads_file_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_ads_file_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_dir_ads.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_dir_ads.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_dir_ads.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_dir_ads.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_network_connection_via_dllhost.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_network_connection_via_dllhost.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_network_connection_via_dllhost.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_network_connection_via_dllhost.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_network_connection_via_rundll32.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_network_connection_via_rundll32.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_network_connection_via_rundll32.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_network_connection_via_rundll32.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_process_network_connection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_process_network_connection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_process_network_connection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_process_network_connection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_system_vp_child_program.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_system_vp_child_program.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_unusual_system_vp_child_program.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_unusual_system_vp_child_program.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_via_filter_manager.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_via_filter_manager.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_via_filter_manager.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_via_filter_manager.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_waf_acl_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_waf_acl_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_waf_acl_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_waf_acl_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_waf_rule_or_rule_group_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_waf_rule_or_rule_group_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_waf_rule_or_rule_group_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_waf_rule_or_rule_group_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_workfolders_control_execution.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_workfolders_control_execution.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/defense_evasion_workfolders_control_execution.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/defense_evasion_workfolders_control_execution.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_adfind_command_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_adfind_command_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_adfind_command_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_adfind_command_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_admin_recon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_admin_recon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_admin_recon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_admin_recon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_blob_container_access_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_blob_container_access_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_blob_container_access_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_blob_container_access_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_command_system_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_command_system_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_command_system_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_command_system_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_denied_service_account_request.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_denied_service_account_request.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_denied_service_account_request.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_denied_service_account_request.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_enumerating_domain_trusts_via_nltest.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_enumerating_domain_trusts_via_nltest.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_enumerating_domain_trusts_via_nltest.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_enumerating_domain_trusts_via_nltest.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_kernel_module_enumeration.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_kernel_module_enumeration.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_kernel_module_enumeration.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_kernel_module_enumeration.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_linux_hping_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_linux_hping_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_linux_hping_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_linux_hping_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_linux_nping_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_linux_nping_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_linux_nping_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_linux_nping_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_information_discovery.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_information_discovery.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_information_discovery.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_information_discovery.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_network_configuration_discovery.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_network_configuration_discovery.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_network_configuration_discovery.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_network_configuration_discovery.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_network_connection_discovery.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_network_connection_discovery.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_network_connection_discovery.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_network_connection_discovery.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_process_discovery.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_process_discovery.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_process_discovery.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_process_discovery.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_user_discovery.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_user_discovery.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_ml_linux_system_user_discovery.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_ml_linux_system_user_discovery.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_net_view.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_net_view.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_net_view.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_net_view.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_peripheral_device.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_peripheral_device.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_peripheral_device.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_peripheral_device.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_posh_invoke_sharefinder.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_posh_invoke_sharefinder.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_posh_invoke_sharefinder.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_posh_invoke_sharefinder.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_posh_suspicious_api_functions.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_posh_suspicious_api_functions.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_posh_suspicious_api_functions.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_posh_suspicious_api_functions.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_post_exploitation_external_ip_lookup.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_post_exploitation_external_ip_lookup.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_post_exploitation_external_ip_lookup.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_post_exploitation_external_ip_lookup.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_privileged_localgroup_membership.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_privileged_localgroup_membership.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_privileged_localgroup_membership.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_privileged_localgroup_membership.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_remote_system_discovery_commands_windows.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_remote_system_discovery_commands_windows.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_remote_system_discovery_commands_windows.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_remote_system_discovery_commands_windows.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_security_software_grep.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_security_software_grep.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_security_software_grep.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_security_software_grep.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_security_software_wmic.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_security_software_wmic.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_security_software_wmic.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_security_software_wmic.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_suspicious_self_subject_review.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_suspicious_self_subject_review.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_suspicious_self_subject_review.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_suspicious_self_subject_review.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_users_domain_built_in_commands.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_users_domain_built_in_commands.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_users_domain_built_in_commands.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_users_domain_built_in_commands.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_virtual_machine_fingerprinting.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_virtual_machine_fingerprinting.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_virtual_machine_fingerprinting.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_virtual_machine_fingerprinting.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_virtual_machine_fingerprinting_grep.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_virtual_machine_fingerprinting_grep.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_virtual_machine_fingerprinting_grep.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_virtual_machine_fingerprinting_grep.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_whoami_command_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_whoami_command_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/discovery_whoami_command_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/discovery_whoami_command_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_adversary_behavior_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_adversary_behavior_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_adversary_behavior_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_adversary_behavior_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_malware_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_malware_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_malware_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_malware_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_malware_prevented.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_malware_prevented.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_malware_prevented.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_malware_prevented.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_ransomware_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_ransomware_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_ransomware_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_ransomware_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_ransomware_prevented.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_ransomware_prevented.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/endgame_ransomware_prevented.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/endgame_ransomware_prevented.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_abnormal_process_id_file_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_abnormal_process_id_file_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_abnormal_process_id_file_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_abnormal_process_id_file_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_apt_solarwinds_backdoor_child_cmd_powershell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_apt_solarwinds_backdoor_child_cmd_powershell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_apt_solarwinds_backdoor_child_cmd_powershell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_apt_solarwinds_backdoor_child_cmd_powershell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_apt_solarwinds_backdoor_unusual_child_processes.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_apt_solarwinds_backdoor_unusual_child_processes.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_apt_solarwinds_backdoor_unusual_child_processes.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_apt_solarwinds_backdoor_unusual_child_processes.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_com_object_xwizard.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_com_object_xwizard.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_com_object_xwizard.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_com_object_xwizard.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_prompt_connecting_to_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_prompt_connecting_to_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_prompt_connecting_to_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_prompt_connecting_to_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_shell_started_by_svchost.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_shell_started_by_svchost.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_shell_started_by_svchost.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_shell_started_by_svchost.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_shell_started_by_unusual_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_shell_started_by_unusual_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_shell_started_by_unusual_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_shell_started_by_unusual_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_shell_via_rundll32.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_shell_via_rundll32.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_shell_via_rundll32.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_shell_via_rundll32.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_virtual_machine.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_virtual_machine.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_command_virtual_machine.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_command_virtual_machine.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_defense_evasion_electron_app_childproc_node_js.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_defense_evasion_electron_app_childproc_node_js.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_defense_evasion_electron_app_childproc_node_js.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_defense_evasion_electron_app_childproc_node_js.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_endgame_exploit_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_endgame_exploit_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_endgame_exploit_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_endgame_exploit_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_endgame_exploit_prevented.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_endgame_exploit_prevented.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_endgame_exploit_prevented.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_endgame_exploit_prevented.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_enumeration_via_wmiprvse.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_enumeration_via_wmiprvse.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_enumeration_via_wmiprvse.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_enumeration_via_wmiprvse.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_from_unusual_path_cmdline.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_from_unusual_path_cmdline.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_from_unusual_path_cmdline.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_from_unusual_path_cmdline.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_html_help_executable_program_connecting_to_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_html_help_executable_program_connecting_to_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_html_help_executable_program_connecting_to_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_html_help_executable_program_connecting_to_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_initial_access_suspicious_browser_childproc.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_initial_access_suspicious_browser_childproc.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_initial_access_suspicious_browser_childproc.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_initial_access_suspicious_browser_childproc.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_installer_package_spawned_network_event.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_installer_package_spawned_network_event.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_installer_package_spawned_network_event.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_installer_package_spawned_network_event.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_linux_netcat_network_connection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_linux_netcat_network_connection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_linux_netcat_network_connection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_linux_netcat_network_connection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_ml_windows_anomalous_script.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_ml_windows_anomalous_script.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_ml_windows_anomalous_script.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_ml_windows_anomalous_script.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_ms_office_written_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_ms_office_written_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_ms_office_written_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_ms_office_written_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_pdf_written_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_pdf_written_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_pdf_written_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_pdf_written_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_pentest_eggshell_remote_admin_tool.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_pentest_eggshell_remote_admin_tool.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_pentest_eggshell_remote_admin_tool.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_pentest_eggshell_remote_admin_tool.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_perl_tty_shell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_perl_tty_shell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_perl_tty_shell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_perl_tty_shell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_posh_portable_executable.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_posh_portable_executable.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_posh_portable_executable.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_posh_portable_executable.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_posh_psreflect.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_posh_psreflect.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_posh_psreflect.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_posh_psreflect.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_process_started_from_process_id_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_process_started_from_process_id_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_process_started_from_process_id_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_process_started_from_process_id_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_process_started_in_shared_memory_directory.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_process_started_in_shared_memory_directory.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_process_started_in_shared_memory_directory.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_process_started_in_shared_memory_directory.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_psexec_lateral_movement_command.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_psexec_lateral_movement_command.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_psexec_lateral_movement_command.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_psexec_lateral_movement_command.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_python_tty_shell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_python_tty_shell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_python_tty_shell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_python_tty_shell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_register_server_program_connecting_to_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_register_server_program_connecting_to_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_register_server_program_connecting_to_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_register_server_program_connecting_to_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_revershell_via_shell_cmd.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_revershell_via_shell_cmd.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_revershell_via_shell_cmd.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_revershell_via_shell_cmd.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_scheduled_task_powershell_source.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_scheduled_task_powershell_source.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_scheduled_task_powershell_source.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_scheduled_task_powershell_source.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_script_via_automator_workflows.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_script_via_automator_workflows.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_script_via_automator_workflows.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_script_via_automator_workflows.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_scripting_osascript_exec_followed_by_netcon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_scripting_osascript_exec_followed_by_netcon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_scripting_osascript_exec_followed_by_netcon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_scripting_osascript_exec_followed_by_netcon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_shared_modules_local_sxs_dll.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_shared_modules_local_sxs_dll.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_shared_modules_local_sxs_dll.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_shared_modules_local_sxs_dll.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_shell_evasion_linux_binary.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_shell_evasion_linux_binary.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_shell_evasion_linux_binary.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_shell_evasion_linux_binary.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_shell_execution_via_apple_scripting.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_shell_execution_via_apple_scripting.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_shell_execution_via_apple_scripting.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_shell_execution_via_apple_scripting.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_cmd_wmi.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_cmd_wmi.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_cmd_wmi.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_cmd_wmi.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_image_load_wmi_ms_office.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_image_load_wmi_ms_office.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_image_load_wmi_ms_office.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_image_load_wmi_ms_office.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_jar_child_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_jar_child_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_jar_child_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_jar_child_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_java_netcon_childproc.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_java_netcon_childproc.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_java_netcon_childproc.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_java_netcon_childproc.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_pdf_reader.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_pdf_reader.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_pdf_reader.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_pdf_reader.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_powershell_imgload.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_powershell_imgload.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_powershell_imgload.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_powershell_imgload.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_psexesvc.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_psexesvc.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_suspicious_psexesvc.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_suspicious_psexesvc.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_tc_bpf_filter.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_tc_bpf_filter.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_tc_bpf_filter.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_tc_bpf_filter.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_user_exec_to_pod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_user_exec_to_pod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_user_exec_to_pod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_user_exec_to_pod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_via_compiled_html_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_via_compiled_html_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_via_compiled_html_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_via_compiled_html_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_via_hidden_shell_conhost.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_via_hidden_shell_conhost.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_via_hidden_shell_conhost.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_via_hidden_shell_conhost.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_via_xp_cmdshell_mssql_stored_procedure.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_via_xp_cmdshell_mssql_stored_procedure.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/execution_via_xp_cmdshell_mssql_stored_procedure.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/execution_via_xp_cmdshell_mssql_stored_procedure.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_ec2_full_network_packet_capture_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_ec2_full_network_packet_capture_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_ec2_full_network_packet_capture_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_ec2_full_network_packet_capture_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_ec2_snapshot_change_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_ec2_snapshot_change_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_ec2_snapshot_change_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_ec2_snapshot_change_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_ec2_vm_export_failure.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_ec2_vm_export_failure.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_ec2_vm_export_failure.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_ec2_vm_export_failure.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_gcp_logging_sink_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_gcp_logging_sink_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_gcp_logging_sink_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_gcp_logging_sink_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_microsoft_365_exchange_transport_rule_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_rds_snapshot_export.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_rds_snapshot_export.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_rds_snapshot_export.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_rds_snapshot_export.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_rds_snapshot_restored.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_rds_snapshot_restored.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/exfiltration_rds_snapshot_restored.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/exfiltration_rds_snapshot_restored.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/external_alerts.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/external_alerts.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/external_alerts.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/external_alerts.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_attempt_to_revoke_okta_api_token.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_attempt_to_revoke_okta_api_token.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_attempt_to_revoke_okta_api_token.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_attempt_to_revoke_okta_api_token.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_aws_eventbridge_rule_disabled_or_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_aws_eventbridge_rule_disabled_or_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_aws_eventbridge_rule_disabled_or_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_aws_eventbridge_rule_disabled_or_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_azure_service_principal_credentials_added.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_azure_service_principal_credentials_added.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_azure_service_principal_credentials_added.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_azure_service_principal_credentials_added.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_backup_file_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_backup_file_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_backup_file_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_backup_file_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_cloudtrail_logging_updated.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_cloudtrail_logging_updated.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_cloudtrail_logging_updated.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_cloudtrail_logging_updated.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_cloudwatch_log_group_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_cloudwatch_log_group_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_cloudwatch_log_group_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_cloudwatch_log_group_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_cloudwatch_log_stream_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_cloudwatch_log_stream_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_cloudwatch_log_stream_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_cloudwatch_log_stream_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_deleting_backup_catalogs_with_wbadmin.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_deleting_backup_catalogs_with_wbadmin.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_deleting_backup_catalogs_with_wbadmin.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_deleting_backup_catalogs_with_wbadmin.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_ec2_disable_ebs_encryption.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_ec2_disable_ebs_encryption.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_ec2_disable_ebs_encryption.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_ec2_disable_ebs_encryption.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_efs_filesystem_or_mount_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_efs_filesystem_or_mount_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_efs_filesystem_or_mount_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_efs_filesystem_or_mount_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_iam_role_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_iam_role_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_iam_role_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_iam_role_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_service_account_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_service_account_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_service_account_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_service_account_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_service_account_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_service_account_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_service_account_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_service_account_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_storage_bucket_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_storage_bucket_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_gcp_storage_bucket_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_gcp_storage_bucket_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_google_workspace_admin_role_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_google_workspace_admin_role_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_google_workspace_admin_role_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_google_workspace_admin_role_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_google_workspace_mfa_enforcement_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_google_workspace_mfa_enforcement_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_google_workspace_mfa_enforcement_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_google_workspace_mfa_enforcement_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_hosts_file_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_hosts_file_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_hosts_file_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_hosts_file_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_iam_deactivate_mfa_device.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_iam_deactivate_mfa_device.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_iam_deactivate_mfa_device.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_iam_deactivate_mfa_device.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_iam_group_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_iam_group_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_iam_group_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_iam_group_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_kubernetes_pod_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_kubernetes_pod_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_kubernetes_pod_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_kubernetes_pod_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_microsoft_365_potential_ransomware_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_microsoft_365_potential_ransomware_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_microsoft_365_potential_ransomware_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_microsoft_365_potential_ransomware_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_microsoft_365_unusual_volume_of_file_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_microsoft_365_unusual_volume_of_file_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_microsoft_365_unusual_volume_of_file_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_microsoft_365_unusual_volume_of_file_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_modification_of_boot_config.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_modification_of_boot_config.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_modification_of_boot_config.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_modification_of_boot_config.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_okta_attempt_to_deactivate_okta_application.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_okta_attempt_to_deactivate_okta_application.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_okta_attempt_to_deactivate_okta_application.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_okta_attempt_to_deactivate_okta_application.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_okta_attempt_to_delete_okta_application.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_okta_attempt_to_delete_okta_application.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_okta_attempt_to_delete_okta_application.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_okta_attempt_to_delete_okta_application.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_okta_attempt_to_modify_okta_application.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_okta_attempt_to_modify_okta_application.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_okta_attempt_to_modify_okta_application.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_okta_attempt_to_modify_okta_application.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_possible_okta_dos_attack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_possible_okta_dos_attack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_possible_okta_dos_attack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_possible_okta_dos_attack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_process_kill_threshold.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_process_kill_threshold.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_process_kill_threshold.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_process_kill_threshold.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_rds_group_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_rds_group_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_rds_group_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_rds_group_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_rds_instance_cluster_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_rds_instance_cluster_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_rds_instance_cluster_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_rds_instance_cluster_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_rds_instance_cluster_stoppage.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_rds_instance_cluster_stoppage.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_rds_instance_cluster_stoppage.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_rds_instance_cluster_stoppage.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_resource_group_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_resource_group_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_resource_group_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_resource_group_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_stop_process_service_threshold.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_stop_process_service_threshold.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_stop_process_service_threshold.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_stop_process_service_threshold.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_virtual_network_device_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_virtual_network_device_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_virtual_network_device_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_virtual_network_device_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_volume_shadow_copy_deletion_or_resized_via_vssadmin.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_volume_shadow_copy_deletion_or_resized_via_vssadmin.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_volume_shadow_copy_deletion_or_resized_via_vssadmin.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_volume_shadow_copy_deletion_or_resized_via_vssadmin.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_volume_shadow_copy_deletion_via_powershell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_volume_shadow_copy_deletion_via_powershell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_volume_shadow_copy_deletion_via_powershell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_volume_shadow_copy_deletion_via_powershell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_volume_shadow_copy_deletion_via_wmic.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_volume_shadow_copy_deletion_via_wmic.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/impact_volume_shadow_copy_deletion_via_wmic.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/impact_volume_shadow_copy_deletion_via_wmic.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/index.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/index.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/index.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_anonymous_request_authorized.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_anonymous_request_authorized.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_anonymous_request_authorized.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_anonymous_request_authorized.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin_atrisk_or_confirmed.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin_atrisk_or_confirmed.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin_atrisk_or_confirmed.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_azure_active_directory_high_risk_signin_atrisk_or_confirmed.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_azure_active_directory_powershell_signin.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_azure_active_directory_powershell_signin.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_azure_active_directory_powershell_signin.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_azure_active_directory_powershell_signin.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_consent_grant_attack_via_azure_registered_application.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_consent_grant_attack_via_azure_registered_application.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_consent_grant_attack_via_azure_registered_application.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_consent_grant_attack_via_azure_registered_application.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_console_login_root.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_console_login_root.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_console_login_root.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_console_login_root.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_evasion_suspicious_htm_file_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_evasion_suspicious_htm_file_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_evasion_suspicious_htm_file_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_evasion_suspicious_htm_file_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_external_guest_user_invite.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_external_guest_user_invite.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_external_guest_user_invite.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_external_guest_user_invite.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_gcp_iam_custom_role_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_gcp_iam_custom_role_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_gcp_iam_custom_role_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_gcp_iam_custom_role_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_policy_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_policy_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_policy_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_policy_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_rule_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_rule_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_rule_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_exchange_anti_phish_rule_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_exchange_safelinks_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_exchange_safelinks_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_exchange_safelinks_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_exchange_safelinks_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_user_restricted_from_sending_email.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_user_restricted_from_sending_email.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_microsoft_365_user_restricted_from_sending_email.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_microsoft_365_user_restricted_from_sending_email.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_auth_rare_hour_for_a_user_to_logon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_auth_rare_hour_for_a_user_to_logon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_auth_rare_hour_for_a_user_to_logon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_auth_rare_hour_for_a_user_to_logon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_auth_rare_source_ip_for_a_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_auth_rare_source_ip_for_a_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_auth_rare_source_ip_for_a_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_auth_rare_source_ip_for_a_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_auth_rare_user_logon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_auth_rare_user_logon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_auth_rare_user_logon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_auth_rare_user_logon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_linux_anomalous_user_name.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_linux_anomalous_user_name.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_linux_anomalous_user_name.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_linux_anomalous_user_name.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_windows_anomalous_user_name.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_windows_anomalous_user_name.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_windows_anomalous_user_name.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_windows_anomalous_user_name.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_windows_rare_user_type10_remote_login.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_windows_rare_user_type10_remote_login.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_ml_windows_rare_user_type10_remote_login.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_ml_windows_rare_user_type10_remote_login.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_o365_user_reported_phish_malware.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_o365_user_reported_phish_malware.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_o365_user_reported_phish_malware.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_o365_user_reported_phish_malware.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_okta_user_attempted_unauthorized_access.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_okta_user_attempted_unauthorized_access.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_okta_user_attempted_unauthorized_access.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_okta_user_attempted_unauthorized_access.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_password_recovery.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_password_recovery.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_password_recovery.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_password_recovery.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_rpc_remote_procedure_call_from_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_rpc_remote_procedure_call_from_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_rpc_remote_procedure_call_from_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_rpc_remote_procedure_call_from_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_rpc_remote_procedure_call_to_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_rpc_remote_procedure_call_to_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_rpc_remote_procedure_call_to_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_rpc_remote_procedure_call_to_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_script_executing_powershell.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_script_executing_powershell.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_script_executing_powershell.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_script_executing_powershell.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_scripts_process_started_via_wmi.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_scripts_process_started_via_wmi.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_scripts_process_started_via_wmi.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_scripts_process_started_via_wmi.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_smb_windows_file_sharing_activity_to_the_internet.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_smb_windows_file_sharing_activity_to_the_internet.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_smb_windows_file_sharing_activity_to_the_internet.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_smb_windows_file_sharing_activity_to_the_internet.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_activity_reported_by_okta_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_activity_reported_by_okta_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_activity_reported_by_okta_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_activity_reported_by_okta_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_mac_ms_office_child_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_mac_ms_office_child_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_mac_ms_office_child_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_mac_ms_office_child_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_exchange_files.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_exchange_files.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_exchange_files.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_exchange_files.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_exchange_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_exchange_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_exchange_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_exchange_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_exchange_worker_child_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_exchange_worker_child_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_exchange_worker_child_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_exchange_worker_child_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_office_child_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_office_child_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_office_child_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_office_child_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_outlook_child_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_outlook_child_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_suspicious_ms_outlook_child_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_suspicious_ms_outlook_child_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_unsecure_elasticsearch_node.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_unsecure_elasticsearch_node.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_unsecure_elasticsearch_node.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_unsecure_elasticsearch_node.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_unusual_dns_service_children.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_unusual_dns_service_children.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_unusual_dns_service_children.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_unusual_dns_service_children.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_unusual_dns_service_file_writes.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_unusual_dns_service_file_writes.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_unusual_dns_service_file_writes.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_unusual_dns_service_file_writes.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_via_explorer_suspicious_child_parent_args.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_via_explorer_suspicious_child_parent_args.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_via_explorer_suspicious_child_parent_args.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_via_explorer_suspicious_child_parent_args.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_via_system_manager.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_via_system_manager.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_via_system_manager.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_via_system_manager.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_zoom_meeting_with_no_passcode.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_zoom_meeting_with_no_passcode.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/initial_access_zoom_meeting_with_no_passcode.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/initial_access_zoom_meeting_with_no_passcode.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_cmd_service.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_cmd_service.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_cmd_service.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_cmd_service.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_credential_access_kerberos_bifrostconsole.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_credential_access_kerberos_bifrostconsole.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_credential_access_kerberos_bifrostconsole.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_credential_access_kerberos_bifrostconsole.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dcom_hta.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dcom_hta.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dcom_hta.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dcom_hta.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dcom_mmc20.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dcom_mmc20.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dcom_mmc20.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dcom_mmc20.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dcom_shellwindow_shellbrowserwindow.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dcom_shellwindow_shellbrowserwindow.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dcom_shellwindow_shellbrowserwindow.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dcom_shellwindow_shellbrowserwindow.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_defense_evasion_lanman_nullsessionpipe_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_defense_evasion_lanman_nullsessionpipe_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_defense_evasion_lanman_nullsessionpipe_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_defense_evasion_lanman_nullsessionpipe_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_direct_outbound_smb_connection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_direct_outbound_smb_connection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_direct_outbound_smb_connection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_direct_outbound_smb_connection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dns_server_overflow.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dns_server_overflow.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_dns_server_overflow.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_dns_server_overflow.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_evasion_rdp_shadowing.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_evasion_rdp_shadowing.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_evasion_rdp_shadowing.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_evasion_rdp_shadowing.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_executable_tool_transfer_smb.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_executable_tool_transfer_smb.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_executable_tool_transfer_smb.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_executable_tool_transfer_smb.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_execution_from_tsclient_mup.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_execution_from_tsclient_mup.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_execution_from_tsclient_mup.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_execution_from_tsclient_mup.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_execution_via_file_shares_sequence.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_execution_via_file_shares_sequence.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_execution_via_file_shares_sequence.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_execution_via_file_shares_sequence.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_incoming_winrm_shell_execution.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_incoming_winrm_shell_execution.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_incoming_winrm_shell_execution.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_incoming_winrm_shell_execution.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_incoming_wmi.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_incoming_wmi.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_incoming_wmi.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_incoming_wmi.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_malware_uploaded_onedrive.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_malware_uploaded_onedrive.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_malware_uploaded_onedrive.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_malware_uploaded_onedrive.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_malware_uploaded_sharepoint.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_malware_uploaded_sharepoint.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_malware_uploaded_sharepoint.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_malware_uploaded_sharepoint.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_mount_hidden_or_webdav_share_net.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_mount_hidden_or_webdav_share_net.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_mount_hidden_or_webdav_share_net.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_mount_hidden_or_webdav_share_net.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_mounting_smb_share.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_mounting_smb_share.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_mounting_smb_share.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_mounting_smb_share.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_powershell_remoting_target.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_powershell_remoting_target.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_powershell_remoting_target.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_powershell_remoting_target.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_rdp_enabled_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_rdp_enabled_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_rdp_enabled_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_rdp_enabled_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_rdp_sharprdp_target.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_rdp_sharprdp_target.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_rdp_sharprdp_target.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_rdp_sharprdp_target.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_file_copy_hidden_share.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_file_copy_hidden_share.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_file_copy_hidden_share.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_file_copy_hidden_share.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_services.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_services.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_services.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_services.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_ssh_login_enabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_ssh_login_enabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_ssh_login_enabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_ssh_login_enabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_task_creation_winlog.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_task_creation_winlog.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_remote_task_creation_winlog.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_remote_task_creation_winlog.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_scheduled_task_target.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_scheduled_task_target.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_scheduled_task_target.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_scheduled_task_target.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_service_control_spawned_script_int.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_service_control_spawned_script_int.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_service_control_spawned_script_int.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_service_control_spawned_script_int.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_suspicious_rdp_client_imageload.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_suspicious_rdp_client_imageload.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_suspicious_rdp_client_imageload.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_suspicious_rdp_client_imageload.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_telnet_network_activity_external.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_telnet_network_activity_external.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_telnet_network_activity_external.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_telnet_network_activity_external.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_telnet_network_activity_internal.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_telnet_network_activity_internal.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_telnet_network_activity_internal.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_telnet_network_activity_internal.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_via_startup_folder_rdp_smb.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_via_startup_folder_rdp_smb.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_via_startup_folder_rdp_smb.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_via_startup_folder_rdp_smb.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_vpn_connection_attempt.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_vpn_connection_attempt.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/lateral_movement_vpn_connection_attempt.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/lateral_movement_vpn_connection_attempt.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_error_message_spike.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_error_message_spike.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_error_message_spike.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_error_message_spike.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_error_code.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_error_code.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_error_code.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_error_code.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_method_by_city.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_method_by_city.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_method_by_city.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_method_by_city.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_method_by_country.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_method_by_country.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_method_by_country.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_method_by_country.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_method_by_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_method_by_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_cloudtrail_rare_method_by_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_cloudtrail_rare_method_by_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_high_count_network_denies.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_high_count_network_denies.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_high_count_network_denies.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_high_count_network_denies.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_high_count_network_events.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_high_count_network_events.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_high_count_network_events.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_high_count_network_events.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_linux_anomalous_network_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_linux_anomalous_network_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_linux_anomalous_network_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_linux_anomalous_network_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_linux_anomalous_network_port_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_linux_anomalous_network_port_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_linux_anomalous_network_port_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_linux_anomalous_network_port_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_packetbeat_rare_server_domain.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_packetbeat_rare_server_domain.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_packetbeat_rare_server_domain.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_packetbeat_rare_server_domain.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_rare_destination_country.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_rare_destination_country.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_rare_destination_country.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_rare_destination_country.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_spike_in_traffic_to_a_country.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_spike_in_traffic_to_a_country.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_spike_in_traffic_to_a_country.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_spike_in_traffic_to_a_country.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_windows_anomalous_network_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_windows_anomalous_network_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/ml_windows_anomalous_network_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/ml_windows_anomalous_network_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/notice.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/notice.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/notice.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/notice.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/okta_threat_detected_by_okta_threatinsight.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/okta_threat_detected_by_okta_threatinsight.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/okta_threat_detected_by_okta_threatinsight.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/okta_threat_detected_by_okta_threatinsight.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_account_creation_hide_at_logon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_account_creation_hide_at_logon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_account_creation_hide_at_logon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_account_creation_hide_at_logon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ad_adminsdholder.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ad_adminsdholder.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ad_adminsdholder.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ad_adminsdholder.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_administrator_privileges_assigned_to_okta_group.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_administrator_privileges_assigned_to_okta_group.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_administrator_privileges_assigned_to_okta_group.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_administrator_privileges_assigned_to_okta_group.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_administrator_role_assigned_to_okta_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_administrator_role_assigned_to_okta_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_administrator_role_assigned_to_okta_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_administrator_role_assigned_to_okta_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_adobe_hijack_persistence.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_adobe_hijack_persistence.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_adobe_hijack_persistence.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_adobe_hijack_persistence.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_app_compat_shim.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_app_compat_shim.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_app_compat_shim.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_app_compat_shim.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_appcertdlls_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_appcertdlls_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_appcertdlls_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_appcertdlls_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_appinitdlls_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_appinitdlls_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_appinitdlls_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_appinitdlls_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_application_added_to_google_workspace_domain.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_application_added_to_google_workspace_domain.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_application_added_to_google_workspace_domain.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_application_added_to_google_workspace_domain.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_attempt_to_create_okta_api_token.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_attempt_to_create_okta_api_token.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_attempt_to_create_okta_api_token.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_attempt_to_create_okta_api_token.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_attempt_to_deactivate_mfa_for_okta_user_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_attempt_to_deactivate_mfa_for_okta_user_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_attempt_to_deactivate_mfa_for_okta_user_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_attempt_to_deactivate_mfa_for_okta_user_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_automation_account_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_automation_account_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_automation_account_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_automation_account_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_automation_runbook_created_or_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_automation_runbook_created_or_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_automation_runbook_created_or_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_automation_runbook_created_or_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_automation_webhook_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_automation_webhook_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_automation_webhook_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_automation_webhook_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_conditional_access_policy_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_conditional_access_policy_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_conditional_access_policy_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_conditional_access_policy_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_global_administrator_role_assigned.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_global_administrator_role_assigned.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_global_administrator_role_assigned.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_global_administrator_role_assigned.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_pim_user_added_global_admin.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_pim_user_added_global_admin.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_pim_user_added_global_admin.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_pim_user_added_global_admin.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_privileged_identity_management_role_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_privileged_identity_management_role_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_azure_privileged_identity_management_role_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_azure_privileged_identity_management_role_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_chkconfig_service_add.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_chkconfig_service_add.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_chkconfig_service_add.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_chkconfig_service_add.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_creation_change_launch_agents_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_creation_change_launch_agents_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_creation_change_launch_agents_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_creation_change_launch_agents_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_creation_hidden_login_item_osascript.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_creation_hidden_login_item_osascript.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_creation_hidden_login_item_osascript.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_creation_hidden_login_item_osascript.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_creation_modif_launch_deamon_sequence.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_creation_modif_launch_deamon_sequence.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_creation_modif_launch_deamon_sequence.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_creation_modif_launch_deamon_sequence.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_credential_access_authorization_plugin_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_credential_access_authorization_plugin_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_credential_access_authorization_plugin_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_credential_access_authorization_plugin_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_credential_access_modify_auth_module_or_config.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_credential_access_modify_auth_module_or_config.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_credential_access_modify_auth_module_or_config.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_credential_access_modify_auth_module_or_config.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_credential_access_modify_ssh_binaries.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_credential_access_modify_ssh_binaries.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_credential_access_modify_ssh_binaries.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_credential_access_modify_ssh_binaries.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_crontab_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_crontab_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_crontab_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_crontab_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_defense_evasion_hidden_launch_agent_deamon_logonitem_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_defense_evasion_hidden_launch_agent_deamon_logonitem_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_defense_evasion_hidden_launch_agent_deamon_logonitem_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_defense_evasion_hidden_launch_agent_deamon_logonitem_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_directory_services_plugins_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_directory_services_plugins_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_directory_services_plugins_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_directory_services_plugins_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_docker_shortcuts_plist_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_docker_shortcuts_plist_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_docker_shortcuts_plist_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_docker_shortcuts_plist_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_dontexpirepasswd_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_dontexpirepasswd_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_dontexpirepasswd_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_dontexpirepasswd_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_dynamic_linker_backup.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_dynamic_linker_backup.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_dynamic_linker_backup.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_dynamic_linker_backup.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ec2_network_acl_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ec2_network_acl_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ec2_network_acl_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ec2_network_acl_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ec2_security_group_configuration_change_detection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ec2_security_group_configuration_change_detection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ec2_security_group_configuration_change_detection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ec2_security_group_configuration_change_detection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_emond_rules_file_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_emond_rules_file_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_emond_rules_file_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_emond_rules_file_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_emond_rules_process_execution.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_emond_rules_process_execution.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_emond_rules_process_execution.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_emond_rules_process_execution.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_enable_root_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_enable_root_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_enable_root_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_enable_root_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_etc_file_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_etc_file_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_etc_file_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_etc_file_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_hidden_launch_agent_deamon_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_hidden_launch_agent_deamon_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_hidden_launch_agent_deamon_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_hidden_launch_agent_deamon_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_hidden_local_account_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_hidden_local_account_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_hidden_local_account_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_hidden_local_account_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_registry_ifeo_injection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_registry_ifeo_injection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_registry_ifeo_injection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_registry_ifeo_injection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_registry_startup_shell_folder_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_registry_startup_shell_folder_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_evasion_registry_startup_shell_folder_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_evasion_registry_startup_shell_folder_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_exchange_suspicious_mailbox_right_delegation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_exchange_suspicious_mailbox_right_delegation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_exchange_suspicious_mailbox_right_delegation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_exchange_suspicious_mailbox_right_delegation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_exposed_service_created_with_type_nodeport.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_exposed_service_created_with_type_nodeport.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_exposed_service_created_with_type_nodeport.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_exposed_service_created_with_type_nodeport.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_finder_sync_plugin_pluginkit.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_finder_sync_plugin_pluginkit.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_finder_sync_plugin_pluginkit.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_finder_sync_plugin_pluginkit.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_folder_action_scripts_runtime.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_folder_action_scripts_runtime.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_folder_action_scripts_runtime.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_folder_action_scripts_runtime.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gcp_iam_service_account_key_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gcp_iam_service_account_key_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gcp_iam_service_account_key_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gcp_iam_service_account_key_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gcp_key_created_for_service_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gcp_key_created_for_service_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gcp_key_created_for_service_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gcp_key_created_for_service_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gcp_service_account_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gcp_service_account_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gcp_service_account_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gcp_service_account_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_2sv_policy_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_2sv_policy_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_2sv_policy_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_2sv_policy_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_admin_role_assigned_to_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_admin_role_assigned_to_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_admin_role_assigned_to_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_admin_role_assigned_to_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_api_access_granted_via_domain_wide_delegation_of_authority.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_api_access_granted_via_domain_wide_delegation_of_authority.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_api_access_granted_via_domain_wide_delegation_of_authority.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_api_access_granted_via_domain_wide_delegation_of_authority.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_custom_admin_role_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_custom_admin_role_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_custom_admin_role_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_custom_admin_role_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_policy_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_policy_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_policy_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_policy_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_role_modified.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_role_modified.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_role_modified.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_role_modified.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_user_group_access_modified_to_allow_external_access.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_user_group_access_modified_to_allow_external_access.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_user_group_access_modified_to_allow_external_access.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_user_group_access_modified_to_allow_external_access.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_user_organizational_unit_changed.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_user_organizational_unit_changed.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_google_workspace_user_organizational_unit_changed.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_google_workspace_user_organizational_unit_changed.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gpo_schtask_service_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gpo_schtask_service_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_gpo_schtask_service_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_gpo_schtask_service_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_iam_group_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_iam_group_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_iam_group_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_iam_group_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_insmod_kernel_module_load.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_insmod_kernel_module_load.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_insmod_kernel_module_load.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_insmod_kernel_module_load.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_kde_autostart_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_kde_autostart_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_kde_autostart_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_kde_autostart_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_local_scheduled_job_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_local_scheduled_job_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_local_scheduled_job_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_local_scheduled_job_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_local_scheduled_task_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_local_scheduled_task_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_local_scheduled_task_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_local_scheduled_task_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_local_scheduled_task_scripting.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_local_scheduled_task_scripting.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_local_scheduled_task_scripting.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_local_scheduled_task_scripting.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_login_logout_hooks_defaults.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_login_logout_hooks_defaults.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_login_logout_hooks_defaults.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_login_logout_hooks_defaults.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_loginwindow_plist_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_loginwindow_plist_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_loginwindow_plist_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_loginwindow_plist_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_mfa_disabled_for_azure_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_mfa_disabled_for_azure_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_mfa_disabled_for_azure_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_mfa_disabled_for_azure_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_mfa_disabled_for_google_workspace_organization.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_mfa_disabled_for_google_workspace_organization.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_mfa_disabled_for_google_workspace_organization.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_mfa_disabled_for_google_workspace_organization.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_exchange_dkim_signing_config_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_exchange_dkim_signing_config_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_exchange_dkim_signing_config_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_exchange_dkim_signing_config_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_exchange_management_role_assignment.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_exchange_management_role_assignment.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_exchange_management_role_assignment.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_exchange_management_role_assignment.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_global_administrator_role_assign.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_global_administrator_role_assign.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_global_administrator_role_assign.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_global_administrator_role_assign.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_teams_custom_app_interaction_allowed.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_teams_custom_app_interaction_allowed.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_teams_custom_app_interaction_allowed.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_teams_custom_app_interaction_allowed.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_teams_external_access_enabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_teams_external_access_enabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_teams_external_access_enabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_teams_external_access_enabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_teams_guest_access_enabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_teams_guest_access_enabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_microsoft_365_teams_guest_access_enabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_microsoft_365_teams_guest_access_enabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_linux_anomalous_process_all_hosts.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_linux_anomalous_process_all_hosts.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_linux_anomalous_process_all_hosts.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_linux_anomalous_process_all_hosts.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_rare_process_by_host_linux.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_rare_process_by_host_linux.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_rare_process_by_host_linux.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_rare_process_by_host_linux.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_rare_process_by_host_windows.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_rare_process_by_host_windows.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_rare_process_by_host_windows.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_rare_process_by_host_windows.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_path_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_path_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_path_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_path_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_process_all_hosts.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_process_all_hosts.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_process_all_hosts.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_process_all_hosts.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_process_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_process_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_process_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_process_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_service.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_service.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ml_windows_anomalous_service.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ml_windows_anomalous_service.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_modification_sublime_app_plugin_or_script.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_modification_sublime_app_plugin_or_script.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_modification_sublime_app_plugin_or_script.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_modification_sublime_app_plugin_or_script.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ms_office_addins_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ms_office_addins_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ms_office_addins_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ms_office_addins_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ms_outlook_vba_template.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ms_outlook_vba_template.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ms_outlook_vba_template.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ms_outlook_vba_template.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_msds_alloweddelegateto_krbtgt.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_msds_alloweddelegateto_krbtgt.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_msds_alloweddelegateto_krbtgt.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_msds_alloweddelegateto_krbtgt.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_okta_attempt_to_modify_or_delete_application_sign_on_policy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_okta_attempt_to_modify_or_delete_application_sign_on_policy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_okta_attempt_to_modify_or_delete_application_sign_on_policy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_okta_attempt_to_modify_or_delete_application_sign_on_policy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_periodic_tasks_file_mdofiy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_periodic_tasks_file_mdofiy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_periodic_tasks_file_mdofiy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_periodic_tasks_file_mdofiy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_powershell_exch_mailbox_activesync_add_device.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_powershell_exch_mailbox_activesync_add_device.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_powershell_exch_mailbox_activesync_add_device.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_powershell_exch_mailbox_activesync_add_device.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_priv_escalation_via_accessibility_features.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_priv_escalation_via_accessibility_features.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_priv_escalation_via_accessibility_features.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_priv_escalation_via_accessibility_features.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_rds_cluster_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_rds_cluster_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_rds_cluster_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_rds_cluster_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_rds_group_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_rds_group_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_rds_group_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_rds_group_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_rds_instance_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_rds_instance_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_rds_instance_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_rds_instance_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_redshift_instance_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_redshift_instance_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_redshift_instance_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_redshift_instance_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_registry_uncommon.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_registry_uncommon.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_registry_uncommon.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_registry_uncommon.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_remote_password_reset.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_remote_password_reset.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_remote_password_reset.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_remote_password_reset.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_53_domain_transfer_lock_disabled.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_53_domain_transfer_lock_disabled.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_53_domain_transfer_lock_disabled.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_53_domain_transfer_lock_disabled.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_53_domain_transferred_to_another_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_53_domain_transferred_to_another_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_53_domain_transferred_to_another_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_53_domain_transferred_to_another_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_53_hosted_zone_associated_with_a_vpc.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_53_hosted_zone_associated_with_a_vpc.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_53_hosted_zone_associated_with_a_vpc.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_53_hosted_zone_associated_with_a_vpc.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_table_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_table_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_table_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_table_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_table_modified_or_deleted.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_table_modified_or_deleted.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_route_table_modified_or_deleted.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_route_table_modified_or_deleted.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_run_key_and_startup_broad.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_run_key_and_startup_broad.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_run_key_and_startup_broad.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_run_key_and_startup_broad.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_runtime_run_key_startup_susp_procs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_runtime_run_key_startup_susp_procs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_runtime_run_key_startup_susp_procs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_runtime_run_key_startup_susp_procs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_scheduled_task_creation_winlog.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_scheduled_task_creation_winlog.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_scheduled_task_creation_winlog.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_scheduled_task_creation_winlog.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_scheduled_task_updated.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_scheduled_task_updated.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_scheduled_task_updated.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_scheduled_task_updated.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_screensaver_engine_unexpected_child_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_screensaver_engine_unexpected_child_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_screensaver_engine_unexpected_child_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_screensaver_engine_unexpected_child_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_screensaver_plist_file_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_screensaver_plist_file_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_screensaver_plist_file_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_screensaver_plist_file_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_sdprop_exclusion_dsheuristics.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_sdprop_exclusion_dsheuristics.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_sdprop_exclusion_dsheuristics.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_sdprop_exclusion_dsheuristics.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_services_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_services_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_services_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_services_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_shell_activity_by_web_server.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_shell_activity_by_web_server.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_shell_activity_by_web_server.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_shell_activity_by_web_server.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_shell_profile_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_shell_profile_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_shell_profile_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_shell_profile_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ssh_authorized_keys_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ssh_authorized_keys_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_ssh_authorized_keys_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_ssh_authorized_keys_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_startup_folder_file_written_by_suspicious_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_startup_folder_file_written_by_suspicious_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_startup_folder_file_written_by_suspicious_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_startup_folder_file_written_by_suspicious_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_startup_folder_file_written_by_unsigned_process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_startup_folder_file_written_by_unsigned_process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_startup_folder_file_written_by_unsigned_process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_startup_folder_file_written_by_unsigned_process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_startup_folder_scripts.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_startup_folder_scripts.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_startup_folder_scripts.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_startup_folder_scripts.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_calendar_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_calendar_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_calendar_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_calendar_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_com_hijack_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_com_hijack_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_com_hijack_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_com_hijack_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_image_load_scheduled_task_ms_office.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_image_load_scheduled_task_ms_office.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_image_load_scheduled_task_ms_office.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_image_load_scheduled_task_ms_office.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_scheduled_task_runtime.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_scheduled_task_runtime.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_scheduled_task_runtime.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_scheduled_task_runtime.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_service_created_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_service_created_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_suspicious_service_created_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_suspicious_service_created_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_system_shells_via_services.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_system_shells_via_services.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_system_shells_via_services.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_system_shells_via_services.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_time_provider_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_time_provider_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_time_provider_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_time_provider_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_account_added_to_privileged_group_ad.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_account_added_to_privileged_group_ad.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_account_added_to_privileged_group_ad.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_account_added_to_privileged_group_ad.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_account_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_account_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_account_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_account_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_added_as_owner_for_azure_application.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_added_as_owner_for_azure_application.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_added_as_owner_for_azure_application.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_added_as_owner_for_azure_application.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_added_as_owner_for_azure_service_principal.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_added_as_owner_for_azure_service_principal.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_user_added_as_owner_for_azure_service_principal.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_user_added_as_owner_for_azure_service_principal.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_application_shimming.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_application_shimming.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_application_shimming.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_application_shimming.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_atom_init_file_modification.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_atom_init_file_modification.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_atom_init_file_modification.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_atom_init_file_modification.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_bits_job_notify_command.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_bits_job_notify_command.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_bits_job_notify_command.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_bits_job_notify_command.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_hidden_run_key_valuename.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_hidden_run_key_valuename.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_hidden_run_key_valuename.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_hidden_run_key_valuename.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_lsa_security_support_provider_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_lsa_security_support_provider_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_lsa_security_support_provider_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_lsa_security_support_provider_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_telemetrycontroller_scheduledtask_hijack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_telemetrycontroller_scheduledtask_hijack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_telemetrycontroller_scheduledtask_hijack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_telemetrycontroller_scheduledtask_hijack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_update_orchestrator_service_hijack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_update_orchestrator_service_hijack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_update_orchestrator_service_hijack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_update_orchestrator_service_hijack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_windows_management_instrumentation_event_subscription.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_windows_management_instrumentation_event_subscription.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_windows_management_instrumentation_event_subscription.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_windows_management_instrumentation_event_subscription.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_wmi_stdregprov_run_services.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_wmi_stdregprov_run_services.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_via_wmi_stdregprov_run_services.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_via_wmi_stdregprov_run_services.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_webshell_detection.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_webshell_detection.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/persistence_webshell_detection.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/persistence_webshell_detection.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_applescript_with_admin_privs.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_applescript_with_admin_privs.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_applescript_with_admin_privs.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_applescript_with_admin_privs.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_aws_suspicious_saml_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_aws_suspicious_saml_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_aws_suspicious_saml_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_aws_suspicious_saml_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_azure_kubernetes_rolebinding_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_azure_kubernetes_rolebinding_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_azure_kubernetes_rolebinding_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_azure_kubernetes_rolebinding_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_create_process_as_different_user.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_create_process_as_different_user.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_create_process_as_different_user.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_create_process_as_different_user.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_cyberarkpas_error_audit_event_promotion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_cyberarkpas_error_audit_event_promotion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_cyberarkpas_error_audit_event_promotion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_cyberarkpas_error_audit_event_promotion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_cyberarkpas_recommended_events_to_monitor_promotion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_cyberarkpas_recommended_events_to_monitor_promotion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_cyberarkpas_recommended_events_to_monitor_promotion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_cyberarkpas_recommended_events_to_monitor_promotion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_disable_uac_registry.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_disable_uac_registry.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_disable_uac_registry.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_disable_uac_registry.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_echo_nopasswd_sudoers.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_echo_nopasswd_sudoers.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_echo_nopasswd_sudoers.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_echo_nopasswd_sudoers.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_prevented.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_prevented.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_prevented.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_cred_manipulation_prevented.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_permission_theft_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_permission_theft_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_permission_theft_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_permission_theft_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_permission_theft_prevented.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_permission_theft_prevented.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_permission_theft_prevented.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_permission_theft_prevented.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_process_injection_detected.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_process_injection_detected.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_process_injection_detected.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_process_injection_detected.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_process_injection_prevented.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_process_injection_prevented.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_endgame_process_injection_prevented.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_endgame_process_injection_prevented.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_explicit_creds_via_scripting.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_explicit_creds_via_scripting.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_explicit_creds_via_scripting.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_explicit_creds_via_scripting.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_exploit_adobe_acrobat_updater.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_exploit_adobe_acrobat_updater.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_exploit_adobe_acrobat_updater.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_exploit_adobe_acrobat_updater.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_gcp_kubernetes_rolebindings_created_or_patched.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_gcp_kubernetes_rolebindings_created_or_patched.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_gcp_kubernetes_rolebindings_created_or_patched.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_gcp_kubernetes_rolebindings_created_or_patched.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_group_policy_iniscript.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_group_policy_iniscript.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_group_policy_iniscript.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_group_policy_iniscript.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_group_policy_privileged_groups.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_group_policy_privileged_groups.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_group_policy_privileged_groups.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_group_policy_privileged_groups.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_group_policy_scheduled_task.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_group_policy_scheduled_task.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_group_policy_scheduled_task.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_group_policy_scheduled_task.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_installertakeover.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_installertakeover.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_installertakeover.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_installertakeover.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_krbrelayup_service_creation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_krbrelayup_service_creation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_krbrelayup_service_creation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_krbrelayup_service_creation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_ld_preload_shared_object_modif.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_ld_preload_shared_object_modif.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_ld_preload_shared_object_modif.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_ld_preload_shared_object_modif.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_local_user_added_to_admin.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_local_user_added_to_admin.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_local_user_added_to_admin.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_local_user_added_to_admin.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_lsa_auth_package.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_lsa_auth_package.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_lsa_auth_package.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_lsa_auth_package.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_ml_linux_anomalous_sudo_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_ml_linux_anomalous_sudo_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_ml_linux_anomalous_sudo_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_ml_linux_anomalous_sudo_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_ml_windows_rare_user_runas_event.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_ml_windows_rare_user_runas_event.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_ml_windows_rare_user_runas_event.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_ml_windows_rare_user_runas_event.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_named_pipe_impersonation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_named_pipe_impersonation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_named_pipe_impersonation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_named_pipe_impersonation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_new_or_modified_federation_domain.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_new_or_modified_federation_domain.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_new_or_modified_federation_domain.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_new_or_modified_federation_domain.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_persistence_phantom_dll.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_persistence_phantom_dll.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_persistence_phantom_dll.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_persistence_phantom_dll.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pkexec_envar_hijack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pkexec_envar_hijack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pkexec_envar_hijack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pkexec_envar_hijack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_hostipc.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_hostipc.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_hostipc.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_hostipc.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_hostnetwork.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_hostnetwork.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_hostnetwork.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_hostnetwork.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_hostpid.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_hostpid.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_hostpid.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_hostpid.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_sensitive_hospath_volume.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_sensitive_hospath_volume.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_pod_created_with_sensitive_hospath_volume.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_pod_created_with_sensitive_hospath_volume.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_port_monitor_print_pocessor_abuse.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_port_monitor_print_pocessor_abuse.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_port_monitor_print_pocessor_abuse.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_port_monitor_print_pocessor_abuse.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_posh_token_impersonation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_posh_token_impersonation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_posh_token_impersonation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_posh_token_impersonation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_registry_copyfiles.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_registry_copyfiles.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_registry_copyfiles.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_registry_copyfiles.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_service_suspicious_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_service_suspicious_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_service_suspicious_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_service_suspicious_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_suspicious_file_deletion.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_suspicious_file_deletion.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_suspicious_file_deletion.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_suspicious_file_deletion.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_suspicious_spl_file.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_suspicious_spl_file.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_printspooler_suspicious_spl_file.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_printspooler_suspicious_spl_file.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_privileged_pod_created.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_privileged_pod_created.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_privileged_pod_created.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_privileged_pod_created.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_rogue_windir_environment_var.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_rogue_windir_environment_var.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_rogue_windir_environment_var.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_rogue_windir_environment_var.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_root_crontab_filemod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_root_crontab_filemod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_root_crontab_filemod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_root_crontab_filemod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_root_login_without_mfa.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_root_login_without_mfa.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_root_login_without_mfa.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_root_login_without_mfa.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_samaccountname_spoofing_attack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_samaccountname_spoofing_attack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_samaccountname_spoofing_attack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_samaccountname_spoofing_attack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_setuid_setgid_bit_set_via_chmod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_setuid_setgid_bit_set_via_chmod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_setuid_setgid_bit_set_via_chmod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_setuid_setgid_bit_set_via_chmod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_shadow_file_read.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_shadow_file_read.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_shadow_file_read.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_shadow_file_read.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sts_assumerole_usage.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sts_assumerole_usage.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sts_assumerole_usage.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sts_assumerole_usage.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sts_getsessiontoken_abuse.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sts_getsessiontoken_abuse.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sts_getsessiontoken_abuse.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sts_getsessiontoken_abuse.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sudo_buffer_overflow.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sudo_buffer_overflow.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sudo_buffer_overflow.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sudo_buffer_overflow.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sudoers_file_mod.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sudoers_file_mod.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_sudoers_file_mod.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_sudoers_file_mod.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_suspicious_assignment_of_controller_service_account.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_suspicious_assignment_of_controller_service_account.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_suspicious_assignment_of_controller_service_account.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_suspicious_assignment_of_controller_service_account.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_suspicious_dnshostname_update.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_suspicious_dnshostname_update.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_suspicious_dnshostname_update.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_suspicious_dnshostname_update.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_com_clipup.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_com_clipup.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_com_clipup.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_com_clipup.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_com_ieinstal.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_com_ieinstal.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_com_ieinstal.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_com_ieinstal.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_com_interface_icmluautil.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_com_interface_icmluautil.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_com_interface_icmluautil.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_com_interface_icmluautil.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_diskcleanup_hijack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_diskcleanup_hijack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_diskcleanup_hijack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_diskcleanup_hijack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_dll_sideloading.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_dll_sideloading.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_dll_sideloading.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_dll_sideloading.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_event_viewer.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_event_viewer.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_event_viewer.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_event_viewer.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_mock_windir.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_mock_windir.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_mock_windir.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_mock_windir.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_winfw_mmc_hijack.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_winfw_mmc_hijack.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_uac_bypass_winfw_mmc_hijack.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_uac_bypass_winfw_mmc_hijack.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unshare_namesapce_manipulation.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unshare_namesapce_manipulation.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unshare_namesapce_manipulation.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unshare_namesapce_manipulation.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unusual_parentchild_relationship.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unusual_parentchild_relationship.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unusual_parentchild_relationship.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unusual_parentchild_relationship.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unusual_printspooler_childprocess.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unusual_printspooler_childprocess.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unusual_printspooler_childprocess.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unusual_printspooler_childprocess.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unusual_svchost_childproc_childless.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unusual_svchost_childproc_childless.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_unusual_svchost_childproc_childless.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_unusual_svchost_childproc_childless.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_updateassumerolepolicy.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_updateassumerolepolicy.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_updateassumerolepolicy.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_updateassumerolepolicy.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_via_rogue_named_pipe.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_via_rogue_named_pipe.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_via_rogue_named_pipe.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_via_rogue_named_pipe.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_windows_service_via_unusual_client.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_windows_service_via_unusual_client.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/privilege_escalation_windows_service_via_unusual_client.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/privilege_escalation_windows_service_via_unusual_client.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/resource_development_ml_linux_anomalous_compiler_activity.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/resource_development_ml_linux_anomalous_compiler_activity.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/resource_development_ml_linux_anomalous_compiler_activity.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/resource_development_ml_linux_anomalous_compiler_activity.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/threat_intel_filebeat8x.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/threat_intel_filebeat8x.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/threat_intel_filebeat8x.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/threat_intel_filebeat8x.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/threat_intel_fleet_integrations.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/threat_intel_fleet_integrations.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/threat_intel_fleet_integrations.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/threat_intel_fleet_integrations.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/README.md b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/README.md similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/README.md rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/README.md index 635839577fb2d..6b9638389e120 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/README.md +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/README.md @@ -6,7 +6,7 @@ 1. [Have the env params set up](https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/server/lib/detection_engine/README.md) -2. Create a new timelines template into `x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines` +2. Create a new timelines template into `x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines` ##### 2.a : Create a new template from UI and export it. @@ -14,7 +14,7 @@ 2. Go to timelines > templates > custom templates (a filter on the right) 3. Click `Create new timeline template` 4. Edit your template - 5. Export only **one** timeline template each time and put that in `x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines`. (For potential update requirement in the future, we put one timeline in each file to keep nice and clear) + 5. Export only **one** timeline template each time and put that in `x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines`. (For potential update requirement in the future, we put one timeline in each file to keep nice and clear) 6. Rename the file extension to `.json` 7. Check the chapter of `Fields to hightlight for on boarding a new prepackaged timeline` in this readme and update your template @@ -25,7 +25,7 @@ Please note that below template is just an example, please replace all your fields with whatever makes sense. Do check `Fields to hightlight for on boarding a new prepackaged timeline` to make sure the template can be created as expected. - cd x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines + cd x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines @@ -54,7 +54,7 @@ 4. ```sh ./timelines/regen_prepackage_timelines_index.sh``` -(this will update `x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/index.ndjson`) +(this will update `x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/index.ndjson`) @@ -83,7 +83,7 @@ sh ./timelines/find_timeline_by_filter.sh immutable template elastic ### How to update an existing prepackage timeline: -1. ```cd x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines``` +1. ```cd x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines``` 2. Open the json file you wish to update, and remember to bump the `templateTimelineVersion` diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/endpoint.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/endpoint.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/endpoint.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/endpoint.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/file_ex.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/file_ex.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/file_ex.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/file_ex.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/index.ndjson b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/index.ndjson similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/index.ndjson rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/index.ndjson diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/network.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/network.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/network.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/network.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/network_ex.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/network_ex.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/network_ex.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/network_ex.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/process.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/process.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/process.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/process.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/process_ex.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/process_ex.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/process_ex.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/process_ex.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/registry_ex.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/registry_ex.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/registry_ex.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/registry_ex.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/threat.json b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/threat.json similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/threat.json rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_timelines/threat.json diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/index.ts new file mode 100644 index 0000000000000..30a12c10bdb90 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { createPrepackagedRules } from './api/install_prebuilt_rules_and_timelines/route'; +export * from './api/register_routes'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/create_prebuilt_rules.ts similarity index 56% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/create_prebuilt_rules.ts index b43c2180a07e8..54554e50a7dd7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/create_prebuilt_rules.ts @@ -6,17 +6,14 @@ */ import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { MAX_RULES_TO_UPDATE_IN_PARALLEL } from '../../../../common/constants'; -import type { AddPrepackagedRulesSchema } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import { initPromisePool } from '../../../utils/promise_pool'; -import { withSecuritySpan } from '../../../utils/with_security_span'; -import { createRules } from './create_rules'; +import { MAX_RULES_TO_UPDATE_IN_PARALLEL } from '../../../../../common/constants'; +import type { PrebuiltRuleToInstall } from '../../../../../common/detection_engine/prebuilt_rules'; +import { initPromisePool } from '../../../../utils/promise_pool'; +import { withSecuritySpan } from '../../../../utils/with_security_span'; +import { createRules } from '../../rule_management/logic/crud/create_rules'; -export const installPrepackagedRules = ( - rulesClient: RulesClient, - rules: AddPrepackagedRulesSchema[] -) => - withSecuritySpan('installPrepackagedRules', async () => { +export const createPrebuiltRules = (rulesClient: RulesClient, rules: PrebuiltRuleToInstall[]) => + withSecuritySpan('createPrebuiltRules', async () => { const result = await initPromisePool({ concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL, items: rules, @@ -31,6 +28,6 @@ export const installPrepackagedRules = ( }); if (result.errors.length > 0) { - throw new AggregateError(result.errors, 'Error installing prepackaged rules'); + throw new AggregateError(result.errors, 'Error installing new prebuilt rules'); } }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_latest_prebuilt_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_latest_prebuilt_rules.test.ts new file mode 100644 index 0000000000000..7c3f69990486b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_latest_prebuilt_rules.test.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 { isEmpty } from 'lodash/fp'; +import type { PrebuiltRuleToInstall } from '../../../../../common/detection_engine/prebuilt_rules'; +import { getFilesystemRules } from './get_latest_prebuilt_rules'; + +describe('Get latest prebuilt rules', () => { + describe('getFilesystemRules', () => { + test('should not throw any errors with the existing checked in pre-packaged rules', () => { + expect(() => getFilesystemRules()).not.toThrow(); + }); + + test('no rule should have the same rule_id as another rule_id', () => { + const prebuiltRules = getFilesystemRules(); + let existingRuleIds: PrebuiltRuleToInstall[] = []; + prebuiltRules.forEach((rule) => { + const foundDuplicate = existingRuleIds.reduce((accum, existingRule) => { + if (existingRule.rule_id === rule.rule_id) { + return `Found duplicate rule_id of ${rule.rule_id} between these two rule names of "${rule.name}" and "${existingRule.name}"`; + } else { + return accum; + } + }, ''); + if (!isEmpty(foundDuplicate)) { + expect(foundDuplicate).toEqual(''); + } else { + existingRuleIds = [...existingRuleIds, rule]; + } + }); + }); + + test('should throw an exception if a pre-packaged rule is not valid', () => { + // @ts-expect-error intentionally invalid argument + expect(() => getFilesystemRules([{ not_valid_made_up_key: true }])).toThrow(); + }); + + test('should throw an exception with a message having rule_id and name in it', () => { + expect(() => + // @ts-expect-error intentionally invalid argument + getFilesystemRules([{ name: 'rule name', rule_id: 'id-123' }]) + ).toThrow(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_prepackaged_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_latest_prebuilt_rules.ts similarity index 60% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_prepackaged_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_latest_prebuilt_rules.ts index f01f6820b2687..f1218f031fff8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_prepackaged_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_latest_prebuilt_rules.ts @@ -5,37 +5,75 @@ * 2.0. */ -import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import { exactCheck, formatErrors } from '@kbn/securitysolution-io-ts-utils'; import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import type * as t from 'io-ts'; -import type { AddPrepackagedRulesSchema } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import { addPrepackagedRulesSchema } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import type { ConfigType } from '../../../config'; -import { withSecuritySpan } from '../../../utils/with_security_span'; + +import { BadRequestError } from '@kbn/securitysolution-es-utils'; +import { exactCheck, formatErrors } from '@kbn/securitysolution-io-ts-utils'; + +import { PrebuiltRuleToInstall } from '../../../../../common/detection_engine/prebuilt_rules'; +import type { ConfigType } from '../../../../config'; +import { withSecuritySpan } from '../../../../utils/with_security_span'; + // TODO: convert rules files to TS and add explicit type definitions -import { rawRules } from './prepackaged_rules'; -import type { RuleAssetSavedObjectsClient } from './rule_asset/rule_asset_saved_objects_client'; -import type { IRuleAssetSOAttributes } from './types'; +import { rawRules } from '../content/prepackaged_rules'; +import type { + RuleAssetSavedObjectsClient, + IRuleAssetSOAttributes, +} from './rule_asset/rule_asset_saved_objects_client'; + +export const getLatestPrebuiltRules = async ( + client: RuleAssetSavedObjectsClient, + prebuiltRulesFromFileSystem: ConfigType['prebuiltRulesFromFileSystem'], + prebuiltRulesFromSavedObjects: ConfigType['prebuiltRulesFromSavedObjects'] +): Promise> => + withSecuritySpan('getLatestPrebuiltRules', async () => { + // build a map of the most recent version of each rule + const prebuilt = prebuiltRulesFromFileSystem ? getFilesystemRules() : []; + const ruleMap = new Map(prebuilt.map((r) => [r.rule_id, r])); + + // check the rules installed via fleet and create/update if the version is newer + if (prebuiltRulesFromSavedObjects) { + const fleetRules = await getFleetRules(client); + fleetRules.forEach((fleetRule) => { + const fsRule = ruleMap.get(fleetRule.rule_id); + + if (fsRule == null || fsRule.version < fleetRule.version) { + // add the new or updated rules to the map + ruleMap.set(fleetRule.rule_id, fleetRule); + } + }); + } + + return ruleMap; + }); + +/** + * Retrieve and validate prebuilt rules from "file system" (content/prepackaged_rules). + */ +export const getFilesystemRules = ( + // @ts-expect-error mock data is too loosely typed + rules: PrebuiltRuleToInstall[] = rawRules +): PrebuiltRuleToInstall[] => { + return validateFilesystemRules(rules); +}; /** * Validate the rules from the file system and throw any errors indicating to the developer * that they are adding incorrect schema rules. Also this will auto-flush in all the default * aspects such as default interval of 5 minutes, default arrays, etc... */ -export const validateAllPrepackagedRules = ( - rules: AddPrepackagedRulesSchema[] -): AddPrepackagedRulesSchema[] => { +const validateFilesystemRules = (rules: PrebuiltRuleToInstall[]): PrebuiltRuleToInstall[] => { return rules.map((rule) => { - const decoded = addPrepackagedRulesSchema.decode(rule); + const decoded = PrebuiltRuleToInstall.decode(rule); const checked = exactCheck(rule, decoded); - const onLeft = (errors: t.Errors): AddPrepackagedRulesSchema => { + const onLeft = (errors: t.Errors): PrebuiltRuleToInstall => { 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 folder rules/prepackaged_rules ` + + `name: "${ruleName}", rule_id: "${ruleId}" within the folder content/prepackaged_rules ` + `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( @@ -44,24 +82,33 @@ export const validateAllPrepackagedRules = ( ); }; - const onRight = (schema: AddPrepackagedRulesSchema): AddPrepackagedRulesSchema => { - return schema as AddPrepackagedRulesSchema; + const onRight = (schema: PrebuiltRuleToInstall): PrebuiltRuleToInstall => { + return schema as PrebuiltRuleToInstall; }; return pipe(checked, fold(onLeft, onRight)); }); }; +/** + * Retrieve and validate prebuilt rules that were installed from Fleet as saved objects. + */ +const getFleetRules = async ( + client: RuleAssetSavedObjectsClient +): Promise => { + const fleetResponse = await client.all(); + const fleetRules = fleetResponse.map((so) => so.attributes); + return validateFleetRules(fleetRules); +}; + /** * Validate the rules from Saved Objects created by Fleet. */ -export const validateAllRuleSavedObjects = ( - rules: IRuleAssetSOAttributes[] -): AddPrepackagedRulesSchema[] => { +const validateFleetRules = (rules: IRuleAssetSOAttributes[]): PrebuiltRuleToInstall[] => { return rules.map((rule) => { - const decoded = addPrepackagedRulesSchema.decode(rule); + const decoded = PrebuiltRuleToInstall.decode(rule); const checked = exactCheck(rule, decoded); - const onLeft = (errors: t.Errors): AddPrepackagedRulesSchema => { + const onLeft = (errors: t.Errors): PrebuiltRuleToInstall => { const ruleName = rule.name ? rule.name : '(rule name unknown)'; const ruleId = rule.rule_id ? rule.rule_id : '(rule rule_id unknown)'; throw new BadRequestError( @@ -74,53 +121,9 @@ export const validateAllRuleSavedObjects = ( ); }; - const onRight = (schema: AddPrepackagedRulesSchema): AddPrepackagedRulesSchema => { - return schema as AddPrepackagedRulesSchema; + const onRight = (schema: PrebuiltRuleToInstall): PrebuiltRuleToInstall => { + return schema as PrebuiltRuleToInstall; }; return pipe(checked, fold(onLeft, onRight)); }); }; - -/** - * Retrieve and validate rules that were installed from Fleet as saved objects. - */ -export const getFleetInstalledRules = async ( - client: RuleAssetSavedObjectsClient -): Promise => { - const fleetResponse = await client.all(); - const fleetRules = fleetResponse.map((so) => so.attributes); - return validateAllRuleSavedObjects(fleetRules); -}; - -export const getPrepackagedRules = ( - // @ts-expect-error mock data is too loosely typed - rules: AddPrepackagedRulesSchema[] = rawRules -): AddPrepackagedRulesSchema[] => { - return validateAllPrepackagedRules(rules); -}; - -export const getLatestPrepackagedRules = async ( - client: RuleAssetSavedObjectsClient, - prebuiltRulesFromFileSystem: ConfigType['prebuiltRulesFromFileSystem'], - prebuiltRulesFromSavedObjects: ConfigType['prebuiltRulesFromSavedObjects'] -): Promise> => - withSecuritySpan('getLatestPrepackagedRules', async () => { - // build a map of the most recent version of each rule - const prepackaged = prebuiltRulesFromFileSystem ? getPrepackagedRules() : []; - const ruleMap = new Map(prepackaged.map((r) => [r.rule_id, r])); - - // check the rules installed via fleet and create/update if the version is newer - if (prebuiltRulesFromSavedObjects) { - const fleetRules = await getFleetInstalledRules(client); - fleetRules.forEach((fleetRule) => { - const fsRule = ruleMap.get(fleetRule.rule_id); - - if (fsRule == null || fsRule.version < fleetRule.version) { - // add the new or updated rules to the map - ruleMap.set(fleetRule.rule_id, fleetRule); - } - }); - } - - return ruleMap; - }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_install.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_install.test.ts similarity index 65% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_install.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_install.test.ts index 513d638afb2a7..b93ef2cc5178f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_install.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_install.test.ts @@ -6,73 +6,73 @@ */ import { getRulesToInstall } from './get_rules_to_install'; -import { getRuleMock } from '../routes/__mocks__/request_responses'; -import { getAddPrepackagedRulesSchemaMock } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; -import { prepackagedRulesToMap, rulesToMap } from './utils'; +import { getRuleMock } from '../../routes/__mocks__/request_responses'; +import { getPrebuiltRuleMock } from '../../../../../common/detection_engine/prebuilt_rules/mocks'; +import { getQueryRuleParams } from '../../rule_schema/mocks'; +import { prebuiltRulesToMap, rulesToMap } from './utils'; describe('get_rules_to_install', () => { test('should return empty array if both rule sets are empty', () => { - const update = getRulesToInstall(prepackagedRulesToMap([]), rulesToMap([])); + const update = getRulesToInstall(prebuiltRulesToMap([]), rulesToMap([])); expect(update).toEqual([]); }); test('should return empty array if the two rule ids match', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; const installedRule = getRuleMock(getQueryRuleParams()); installedRule.params.ruleId = 'rule-1'; const update = getRulesToInstall( - prepackagedRulesToMap([ruleFromFileSystem]), + prebuiltRulesToMap([ruleFromFileSystem]), rulesToMap([installedRule]) ); expect(update).toEqual([]); }); test('should return the rule to install if the id of the two rules do not match', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; const installedRule = getRuleMock(getQueryRuleParams()); installedRule.params.ruleId = 'rule-2'; const update = getRulesToInstall( - prepackagedRulesToMap([ruleFromFileSystem]), + prebuiltRulesToMap([ruleFromFileSystem]), rulesToMap([installedRule]) ); expect(update).toEqual([ruleFromFileSystem]); }); test('should return two rules to install if both the ids of the two rules do not match', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.rule_id = 'rule-1'; - const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem2 = getPrebuiltRuleMock(); ruleFromFileSystem2.rule_id = 'rule-2'; const installedRule = getRuleMock(getQueryRuleParams()); installedRule.params.ruleId = 'rule-3'; const update = getRulesToInstall( - prepackagedRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), + prebuiltRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), rulesToMap([installedRule]) ); expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]); }); test('should return two rules of three to install if both the ids of the two rules do not match but the third does', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.rule_id = 'rule-1'; - const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem2 = getPrebuiltRuleMock(); ruleFromFileSystem2.rule_id = 'rule-2'; - const ruleFromFileSystem3 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem3 = getPrebuiltRuleMock(); ruleFromFileSystem3.rule_id = 'rule-3'; const installedRule = getRuleMock(getQueryRuleParams()); installedRule.params.ruleId = 'rule-3'; const update = getRulesToInstall( - prepackagedRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2, ruleFromFileSystem3]), + prebuiltRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2, ruleFromFileSystem3]), rulesToMap([installedRule]) ); expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_install.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_install.ts similarity index 56% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_install.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_install.ts index aa7a257a171e0..69d76cdc98e4a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_install.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_install.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { AddPrepackagedRulesSchema } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import type { RuleAlertType } from './types'; +import type { PrebuiltRuleToInstall } from '../../../../../common/detection_engine/prebuilt_rules'; +import type { RuleAlertType } from '../../rule_schema'; export const getRulesToInstall = ( - latestPrePackagedRules: Map, + latestPrebuiltRules: Map, installedRules: Map ) => { - return Array.from(latestPrePackagedRules.values()).filter( + return Array.from(latestPrebuiltRules.values()).filter( (rule) => !installedRules.has(rule.rule_id) ); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_update.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_update.test.ts similarity index 85% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_update.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_update.test.ts index 7f48cca2078e1..bcf85d4095556 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_update.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_update.test.ts @@ -6,19 +6,19 @@ */ import { filterInstalledRules, getRulesToUpdate, mergeExceptionLists } from './get_rules_to_update'; -import { getRuleMock } from '../routes/__mocks__/request_responses'; -import { getAddPrepackagedRulesSchemaMock } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; -import { prepackagedRulesToMap, rulesToMap } from './utils'; +import { getRuleMock } from '../../routes/__mocks__/request_responses'; +import { getPrebuiltRuleMock } from '../../../../../common/detection_engine/prebuilt_rules/mocks'; +import { getQueryRuleParams } from '../../rule_schema/mocks'; +import { prebuiltRulesToMap, rulesToMap } from './utils'; describe('get_rules_to_update', () => { test('should return empty array if both rule sets are empty', () => { - const update = getRulesToUpdate(prepackagedRulesToMap([]), rulesToMap([])); + const update = getRulesToUpdate(prebuiltRulesToMap([]), rulesToMap([])); expect(update).toEqual([]); }); test('should return empty array if the rule_id of the two rules do not match', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 2; @@ -26,14 +26,14 @@ describe('get_rules_to_update', () => { installedRule.params.ruleId = 'rule-2'; installedRule.params.version = 1; const update = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem]), + prebuiltRulesToMap([ruleFromFileSystem]), rulesToMap([installedRule]) ); expect(update).toEqual([]); }); test('should return empty array if the version of file system rule is less than the installed version', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 1; @@ -41,14 +41,14 @@ describe('get_rules_to_update', () => { installedRule.params.ruleId = 'rule-1'; installedRule.params.version = 2; const update = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem]), + prebuiltRulesToMap([ruleFromFileSystem]), rulesToMap([installedRule]) ); expect(update).toEqual([]); }); test('should return empty array if the version of file system rule is the same as the installed version', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 1; @@ -56,14 +56,14 @@ describe('get_rules_to_update', () => { installedRule.params.ruleId = 'rule-1'; installedRule.params.version = 1; const update = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem]), + prebuiltRulesToMap([ruleFromFileSystem]), rulesToMap([installedRule]) ); expect(update).toEqual([]); }); test('should return the rule to update if the version of file system rule is greater than the installed version', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 2; @@ -73,14 +73,14 @@ describe('get_rules_to_update', () => { installedRule.params.exceptionsList = []; const update = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem]), + prebuiltRulesToMap([ruleFromFileSystem]), rulesToMap([installedRule]) ); expect(update).toEqual([ruleFromFileSystem]); }); test('should return 1 rule out of 2 to update if the version of file system rule is greater than the installed version of just one', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 2; @@ -95,18 +95,18 @@ describe('get_rules_to_update', () => { installedRule2.params.exceptionsList = []; const update = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem]), + prebuiltRulesToMap([ruleFromFileSystem]), rulesToMap([installedRule1, installedRule2]) ); expect(update).toEqual([ruleFromFileSystem]); }); test('should return 2 rules out of 2 to update if the version of file system rule is greater than the installed version of both', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.rule_id = 'rule-1'; ruleFromFileSystem1.version = 2; - const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem2 = getPrebuiltRuleMock(); ruleFromFileSystem2.rule_id = 'rule-2'; ruleFromFileSystem2.version = 2; @@ -121,14 +121,14 @@ describe('get_rules_to_update', () => { installedRule2.params.exceptionsList = []; const update = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), + prebuiltRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), rulesToMap([installedRule1, installedRule2]) ); expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]); }); test('should add back an exception_list if it was removed by the end user on an immutable rule during an upgrade', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = [ { id: 'endpoint_list', @@ -146,14 +146,14 @@ describe('get_rules_to_update', () => { installedRule1.params.exceptionsList = []; const [update] = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem1]), + prebuiltRulesToMap([ruleFromFileSystem1]), rulesToMap([installedRule1]) ); expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list); }); test('should not remove an additional exception_list if an additional one was added by the end user on an immutable rule during an upgrade', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = [ { id: 'endpoint_list', @@ -178,7 +178,7 @@ describe('get_rules_to_update', () => { ]; const [update] = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem1]), + prebuiltRulesToMap([ruleFromFileSystem1]), rulesToMap([installedRule1]) ); expect(update.exceptions_list).toEqual([ @@ -188,7 +188,7 @@ describe('get_rules_to_update', () => { }); test('should not remove an existing exception_list if they are the same between the current installed one and the upgraded one', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = [ { id: 'endpoint_list', @@ -213,14 +213,14 @@ describe('get_rules_to_update', () => { ]; const [update] = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem1]), + prebuiltRulesToMap([ruleFromFileSystem1]), rulesToMap([installedRule1]) ); expect(update.exceptions_list).toEqual(ruleFromFileSystem1.exceptions_list); }); test('should not remove an existing exception_list if the rule has an empty exceptions list', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = []; ruleFromFileSystem1.rule_id = 'rule-1'; ruleFromFileSystem1.version = 2; @@ -238,19 +238,19 @@ describe('get_rules_to_update', () => { ]; const [update] = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem1]), + prebuiltRulesToMap([ruleFromFileSystem1]), rulesToMap([installedRule1]) ); expect(update.exceptions_list).toEqual(installedRule1.params.exceptionsList); }); test('should not remove an existing exception_list if the rule has an empty exceptions list for multiple rules', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = []; ruleFromFileSystem1.rule_id = 'rule-1'; ruleFromFileSystem1.version = 2; - const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem2 = getPrebuiltRuleMock(); ruleFromFileSystem2.exceptions_list = []; ruleFromFileSystem2.rule_id = 'rule-2'; ruleFromFileSystem2.version = 2; @@ -279,7 +279,7 @@ describe('get_rules_to_update', () => { ]; const [update1, update2] = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), + prebuiltRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), rulesToMap([installedRule1, installedRule2]) ); expect(update1.exceptions_list).toEqual(installedRule1.params.exceptionsList); @@ -287,12 +287,12 @@ describe('get_rules_to_update', () => { }); test('should not remove an existing exception_list if the rule has an empty exceptions list for mixed rules', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = []; ruleFromFileSystem1.rule_id = 'rule-1'; ruleFromFileSystem1.version = 2; - const ruleFromFileSystem2 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem2 = getPrebuiltRuleMock(); ruleFromFileSystem2.exceptions_list = []; ruleFromFileSystem2.rule_id = 'rule-2'; ruleFromFileSystem2.version = 2; @@ -330,7 +330,7 @@ describe('get_rules_to_update', () => { ]; const [update1, update2] = getRulesToUpdate( - prepackagedRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), + prebuiltRulesToMap([ruleFromFileSystem1, ruleFromFileSystem2]), rulesToMap([installedRule1, installedRule2]) ); expect(update1.exceptions_list).toEqual(installedRule1.params.exceptionsList); @@ -343,7 +343,7 @@ describe('get_rules_to_update', () => { describe('filterInstalledRules', () => { test('should return "false" if the id of the two rules do not match', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 2; @@ -355,7 +355,7 @@ describe('filterInstalledRules', () => { }); test('should return "false" if the version of file system rule is less than the installed version', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 1; @@ -367,7 +367,7 @@ describe('filterInstalledRules', () => { }); test('should return "false" if the version of file system rule is the same as the installed version', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 1; @@ -379,7 +379,7 @@ describe('filterInstalledRules', () => { }); test('should return "true" to update if the version of file system rule is greater than the installed version', () => { - const ruleFromFileSystem = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem = getPrebuiltRuleMock(); ruleFromFileSystem.rule_id = 'rule-1'; ruleFromFileSystem.version = 2; @@ -395,7 +395,7 @@ describe('filterInstalledRules', () => { describe('mergeExceptionLists', () => { test('should add back an exception_list if it was removed by the end user on an immutable rule during an upgrade', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = [ { id: 'endpoint_list', @@ -417,7 +417,7 @@ describe('mergeExceptionLists', () => { }); test('should not remove an additional exception_list if an additional one was added by the end user on an immutable rule during an upgrade', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = [ { id: 'endpoint_list', @@ -449,7 +449,7 @@ describe('mergeExceptionLists', () => { }); test('should not remove an existing exception_list if they are the same between the current installed one and the upgraded one', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = [ { id: 'endpoint_list', @@ -478,7 +478,7 @@ describe('mergeExceptionLists', () => { }); test('should not remove an existing exception_list if the rule has an empty exceptions list', () => { - const ruleFromFileSystem1 = getAddPrepackagedRulesSchemaMock(); + const ruleFromFileSystem1 = getPrebuiltRuleMock(); ruleFromFileSystem1.exceptions_list = []; ruleFromFileSystem1.rule_id = 'rule-1'; ruleFromFileSystem1.version = 2; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_update.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_update.ts similarity index 60% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_update.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_update.ts index 8cfabf1889c7f..7547f16961cc1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_rules_to_update.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/get_rules_to_update.ts @@ -5,21 +5,21 @@ * 2.0. */ -import type { AddPrepackagedRulesSchema } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import type { RuleAlertType } from './types'; +import type { PrebuiltRuleToInstall } from '../../../../../common/detection_engine/prebuilt_rules'; +import type { RuleAlertType } from '../../rule_schema'; /** * Returns the rules to update by doing a compare to the rules from the file system against * the installed rules already. This also merges exception list items between the two since * exception list items can exist on both rules to update and already installed rules. - * @param latestPrePackagedRules The latest rules to check against installed + * @param latestPrebuiltRules The latest rules to check against installed * @param installedRules The installed rules */ export const getRulesToUpdate = ( - latestPrePackagedRules: Map, + latestPrebuiltRules: Map, installedRules: Map ) => { - return Array.from(latestPrePackagedRules.values()) + return Array.from(latestPrebuiltRules.values()) .filter((latestRule) => filterInstalledRules(latestRule, installedRules)) .map((latestRule) => mergeExceptionLists(latestRule, installedRules)); }; @@ -27,45 +27,44 @@ export const getRulesToUpdate = ( /** * Filters latest prepackaged rules that do not match the installed rules so you * only get back rules that are going to be updated - * @param latestPrePackagedRule The latest prepackaged rule version + * @param latestPrebuiltRule The latest prepackaged rule version * @param installedRules The installed rules to compare against for updates */ export const filterInstalledRules = ( - latestPrePackagedRule: AddPrepackagedRulesSchema, + latestPrebuiltRule: PrebuiltRuleToInstall, installedRules: Map ): boolean => { - const installedRule = installedRules.get(latestPrePackagedRule.rule_id); + const installedRule = installedRules.get(latestPrebuiltRule.rule_id); - return !!installedRule && installedRule.params.version < latestPrePackagedRule.version; + return !!installedRule && installedRule.params.version < latestPrebuiltRule.version; }; /** * Given a rule from the file system and the set of installed rules this will merge the exception lists * from the installed rules onto the rules from the file system. - * @param latestPrePackagedRule The latest prepackaged rule version that might have exceptions_lists + * @param latestPrebuiltRule The latest prepackaged rule version that might have exceptions_lists * @param installedRules The installed rules which might have user driven exceptions_lists */ export const mergeExceptionLists = ( - latestPrePackagedRule: AddPrepackagedRulesSchema, + latestPrebuiltRule: PrebuiltRuleToInstall, installedRules: Map -): AddPrepackagedRulesSchema => { - if (latestPrePackagedRule.exceptions_list != null) { - const installedRule = installedRules.get(latestPrePackagedRule.rule_id); +): PrebuiltRuleToInstall => { + if (latestPrebuiltRule.exceptions_list != null) { + const installedRule = installedRules.get(latestPrebuiltRule.rule_id); if (installedRule != null && installedRule.params.exceptionsList != null) { const installedExceptionList = installedRule.params.exceptionsList; - const fileSystemExceptions = latestPrePackagedRule.exceptions_list.filter( - (potentialDuplicate) => - installedExceptionList.every((item) => item.list_id !== potentialDuplicate.list_id) + const fileSystemExceptions = latestPrebuiltRule.exceptions_list.filter((potentialDuplicate) => + installedExceptionList.every((item) => item.list_id !== potentialDuplicate.list_id) ); return { - ...latestPrePackagedRule, + ...latestPrebuiltRule, exceptions_list: [...fileSystemExceptions, ...installedRule.params.exceptionsList], }; } else { - return latestPrePackagedRule; + return latestPrebuiltRule; } } else { - return latestPrePackagedRule; + return latestPrebuiltRule; } }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/rule_asset/rule_asset_saved_object_mappings.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_asset/rule_asset_saved_object_mappings.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/rule_asset/rule_asset_saved_object_mappings.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_asset/rule_asset_saved_object_mappings.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/rule_asset/rule_asset_saved_objects_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_asset/rule_asset_saved_objects_client.ts similarity index 80% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/rule_asset/rule_asset_saved_objects_client.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_asset/rule_asset_saved_objects_client.ts index de1ea7987e457..be963fb3dae9e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/rule_asset/rule_asset_saved_objects_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_asset/rule_asset_saved_objects_client.ts @@ -11,10 +11,22 @@ import type { SavedObjectsFindResponse, } from '@kbn/core/server'; import { ruleAssetSavedObjectType } from './rule_asset_saved_object_mappings'; -import type { IRuleAssetSavedObject } from '../types'; const DEFAULT_PAGE_SIZE = 100; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export interface IRuleAssetSOAttributes extends Record { + rule_id: string | null | undefined; + version: string | null | undefined; + name: string | null | undefined; +} + +export interface IRuleAssetSavedObject { + type: string; + id: string; + attributes: IRuleAssetSOAttributes; +} + export interface RuleAssetSavedObjectsClient { find: ( options?: Omit diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/update_prebuilt_rules.test.ts similarity index 73% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/update_prebuilt_rules.test.ts index 88d543cc77007..955d288068e33 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/update_prebuilt_rules.test.ts @@ -7,28 +7,30 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; import { savedObjectsClientMock } from '@kbn/core/server/mocks'; -import { getRuleMock, getFindResultWithSingleHit } from '../routes/__mocks__/request_responses'; -import { updatePrepackagedRules } from './update_prepacked_rules'; -import { patchRules } from './patch_rules'; +import { getRuleMock, getFindResultWithSingleHit } from '../../routes/__mocks__/request_responses'; +import { updatePrebuiltRules } from './update_prebuilt_rules'; +import { patchRules } from '../../rule_management/logic/crud/patch_rules'; import { - getAddPrepackagedRulesSchemaMock, - getAddPrepackagedThreatMatchRulesSchemaMock, -} from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock'; -import { ruleExecutionLogMock } from '../rule_monitoring/mocks'; -import { legacyMigrate } from './utils'; -import { getQueryRuleParams, getThreatRuleParams } from '../schemas/rule_schemas.mock'; + getPrebuiltRuleMock, + getPrebuiltThreatMatchRuleMock, +} from '../../../../../common/detection_engine/prebuilt_rules/mocks'; +import { ruleExecutionLogMock } from '../../rule_monitoring/mocks'; +import { legacyMigrate } from '../../rule_management'; +import { getQueryRuleParams, getThreatRuleParams } from '../../rule_schema/mocks'; -jest.mock('./patch_rules'); +jest.mock('../../rule_management/logic/crud/patch_rules'); -jest.mock('./utils', () => { - const actual = jest.requireActual('./utils'); +jest.mock('../../rule_management/logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual( + '../../rule_management/logic/rule_actions/legacy_action_migration' + ); return { ...actual, legacyMigrate: jest.fn(), }; }); -describe('updatePrepackagedRules', () => { +describe('updatePrebuiltRules', () => { let rulesClient: ReturnType; let savedObjectsClient: ReturnType; let ruleExecutionLog: ReturnType; @@ -50,10 +52,10 @@ describe('updatePrepackagedRules', () => { params: {}, }, ]; - const prepackagedRule = getAddPrepackagedRulesSchemaMock(); + const prepackagedRule = getPrebuiltRuleMock(); rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); - await updatePrepackagedRules( + await updatePrebuiltRules( rulesClient, savedObjectsClient, [{ ...prepackagedRule, actions }], @@ -83,14 +85,14 @@ describe('updatePrepackagedRules', () => { threat_indicator_path: 'test.path', threat_query: 'threat:*', }; - const prepackagedRule = getAddPrepackagedThreatMatchRulesSchemaMock(); + const prepackagedRule = getPrebuiltThreatMatchRuleMock(); rulesClient.find.mockResolvedValue({ ...getFindResultWithSingleHit(), data: [getRuleMock(getThreatRuleParams())], }); (legacyMigrate as jest.Mock).mockResolvedValue(getRuleMock(getThreatRuleParams())); - await updatePrepackagedRules( + await updatePrebuiltRules( rulesClient, savedObjectsClient, [{ ...prepackagedRule, ...updatedThreatParams }], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/update_prebuilt_rules.ts similarity index 73% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/update_prebuilt_rules.ts index aaee033dd8e96..341038097f448 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/update_prebuilt_rules.ts @@ -8,30 +8,34 @@ import { chunk } from 'lodash/fp'; import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { RulesClient, PartialRule } from '@kbn/alerting-plugin/server'; -import type { AddPrepackagedRulesSchema } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import { MAX_RULES_TO_UPDATE_IN_PARALLEL } from '../../../../common/constants'; -import { patchRules } from './patch_rules'; -import { readRules } from './read_rules'; -import type { RuleParams } from '../schemas/rule_schemas'; -import { legacyMigrate } from './utils'; -import { deleteRules } from './delete_rules'; -import { PrepackagedRulesError } from '../routes/rules/add_prepackaged_rules_route'; -import type { IRuleExecutionLogForRoutes } from '../rule_monitoring'; -import { createRules } from './create_rules'; -import { transformAlertToRuleAction } from '../../../../common/detection_engine/transform_actions'; + +import type { PrebuiltRuleToInstall } from '../../../../../common/detection_engine/prebuilt_rules'; +import { transformAlertToRuleAction } from '../../../../../common/detection_engine/transform_actions'; +import { MAX_RULES_TO_UPDATE_IN_PARALLEL } from '../../../../../common/constants'; + +import { legacyMigrate } from '../../rule_management'; +import { createRules } from '../../rule_management/logic/crud/create_rules'; +import { readRules } from '../../rule_management/logic/crud/read_rules'; +import { patchRules } from '../../rule_management/logic/crud/patch_rules'; +import { deleteRules } from '../../rule_management/logic/crud/delete_rules'; + +import type { IRuleExecutionLogForRoutes } from '../../rule_monitoring'; +import type { RuleParams } from '../../rule_schema'; + +import { PrepackagedRulesError } from '../api/install_prebuilt_rules_and_timelines/route'; /** - * Updates the prepackaged rules given a set of rules and output index. + * Updates existing prebuilt rules given a set of rules and output index. * This implements a chunked approach to not saturate network connections and * avoid being a "noisy neighbor". * @param rulesClient Alerting client * @param spaceId Current user spaceId * @param rules The rules to apply the update for */ -export const updatePrepackagedRules = async ( +export const updatePrebuiltRules = async ( rulesClient: RulesClient, savedObjectsClient: SavedObjectsClientContract, - rules: AddPrepackagedRulesSchema[], + rules: PrebuiltRuleToInstall[], ruleExecutionLog: IRuleExecutionLogForRoutes ): Promise => { const ruleChunks = chunk(MAX_RULES_TO_UPDATE_IN_PARALLEL, rules); @@ -53,10 +57,10 @@ export const updatePrepackagedRules = async ( * @param rules The rules to apply the update for * @returns Promise of what was updated. */ -export const createPromises = ( +const createPromises = ( rulesClient: RulesClient, savedObjectsClient: SavedObjectsClientContract, - rules: AddPrepackagedRulesSchema[], + rules: PrebuiltRuleToInstall[], ruleExecutionLog: IRuleExecutionLogForRoutes ): Array | null>> => { return rules.map(async (rule) => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/utils.ts new file mode 100644 index 0000000000000..09f231f51d4ac --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/utils.ts @@ -0,0 +1,27 @@ +/* + * 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 { PrebuiltRuleToInstall } from '../../../../../common/detection_engine/prebuilt_rules'; +import type { RuleAlertType } from '../../rule_schema'; + +/** + * Converts an array of prebuilt rules to a Map with rule IDs as keys + * + * @param rules Array of prebuilt rules + * @returns Map + */ +export const prebuiltRulesToMap = (rules: PrebuiltRuleToInstall[]) => + new Map(rules.map((rule) => [rule.rule_id, rule])); + +/** + * Converts an array of rules to a Map with rule IDs as keys + * + * @param rules Array of rules + * @returns Map + */ +export const rulesToMap = (rules: RuleAlertType[]) => + new Map(rules.map((rule) => [rule.params.ruleId, rule])); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 9f2f576313531..7b6c85d486638 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -6,17 +6,16 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { SavedObjectsFindResponse, SavedObjectsFindResult } from '@kbn/core/server'; import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; import { ruleTypeMappings } from '@kbn/securitysolution-rules'; - -import type { SavedObjectsFindResponse, SavedObjectsFindResult } from '@kbn/core/server'; +import type { SanitizedRule, ResolvedSanitizedRule } from '@kbn/alerting-plugin/common'; import { DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_SIGNALS_STATUS_URL, DETECTION_ENGINE_PRIVILEGES_URL, DETECTION_ENGINE_QUERY_SIGNALS_URL, - DETECTION_ENGINE_PREPACKAGED_URL, DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL, DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL, DETECTION_ENGINE_RULES_BULK_ACTION, @@ -25,24 +24,31 @@ import { DETECTION_ENGINE_RULES_BULK_CREATE, DETECTION_ENGINE_RULES_URL_FIND, } from '../../../../../common/constants'; -import type { RuleAlertType, HapiReadableStream } from '../../rules/types'; -import { requestMock } from './request'; + +import { + PREBUILT_RULES_STATUS_URL, + PREBUILT_RULES_URL, +} from '../../../../../common/detection_engine/prebuilt_rules'; +import { + getPerformBulkActionSchemaMock, + getPerformBulkActionEditSchemaMock, +} from '../../../../../common/detection_engine/rule_management/mocks'; +import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/rule_schema/mocks'; import type { QuerySignalsSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/query_signals_index_schema'; import type { SetSignalsStatusSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/set_signal_status_schema'; -import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; import { getFinalizeSignalsMigrationSchemaMock } from '../../../../../common/detection_engine/schemas/request/finalize_signals_migration_schema.mock'; import { getSignalsMigrationStatusSchemaMock } from '../../../../../common/detection_engine/schemas/request/get_signals_migration_status_schema.mock'; -import type { RuleParams } from '../../schemas/rule_schemas'; -import type { SanitizedRule, ResolvedSanitizedRule } from '@kbn/alerting-plugin/common'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { - getPerformBulkActionSchemaMock, - getPerformBulkActionEditSchemaMock, -} from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema.mock'; -// eslint-disable-next-line no-restricted-imports -import type { LegacyRuleNotificationAlertType } from '../../notifications/legacy_types'; + // eslint-disable-next-line no-restricted-imports -import type { LegacyIRuleActionsAttributes } from '../../rule_actions/legacy_types'; +import type { + LegacyRuleNotificationAlertType, + LegacyIRuleActionsAttributes, +} from '../../rule_actions_legacy'; +import type { HapiReadableStream } from '../../rule_management/logic/import/hapi_readable_stream'; +import type { RuleAlertType, RuleParams } from '../../rule_schema'; +import { getQueryRuleParams } from '../../rule_schema/mocks'; + +import { requestMock } from './request'; export const typicalSetStatusSignalByIdsPayload = (): SetSignalsStatusSchemaDecoded => ({ signal_ids: ['somefakeid1', 'somefakeid2'], @@ -174,13 +180,13 @@ export const getPrivilegeRequest = (options: { auth?: { isAuthenticated: boolean export const addPrepackagedRulesRequest = () => requestMock.create({ method: 'put', - path: DETECTION_ENGINE_PREPACKAGED_URL, + path: PREBUILT_RULES_URL, }); export const getPrepackagedRulesStatusRequest = () => requestMock.create({ method: 'get', - path: `${DETECTION_ENGINE_PREPACKAGED_URL}/_status`, + path: PREBUILT_RULES_STATUS_URL, }); export interface FindHit { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts index 3ed486d9d9a1b..67462232a22ba 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts @@ -7,10 +7,10 @@ import { Readable } from 'stream'; -import type { HapiReadableStream } from '../../rules/types'; import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; -import type { FullResponseSchema } from '../../../../../common/detection_engine/schemas/request'; +import type { RuleResponse } from '../../../../../common/detection_engine/rule_schema'; +import type { HapiReadableStream } from '../../rule_management/logic/import/hapi_readable_stream'; /** * Given a string, builds a hapi stream as our @@ -34,7 +34,7 @@ export const buildHapiStream = (string: string, filename = 'file.ndjson'): HapiR return stream; }; -export const getOutputRuleAlertForRest = (): FullResponseSchema => ({ +export const getOutputRuleAlertForRest = (): RuleResponse => ({ author: ['Elastic'], actions: [], building_block_type: 'default', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts deleted file mode 100644 index 92a854b2540fe..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts +++ /dev/null @@ -1,107 +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 { transformError } from '@kbn/securitysolution-es-utils'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; -import type { PrePackagedRulesAndTimelinesStatusSchema } from '../../../../../common/detection_engine/schemas/response/prepackaged_rules_status_schema'; -import { prePackagedRulesAndTimelinesStatusSchema } from '../../../../../common/detection_engine/schemas/response/prepackaged_rules_status_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_PREPACKAGED_URL } from '../../../../../common/constants'; -import { buildSiemResponse } from '../utils'; - -import { getRulesToInstall } from '../../rules/get_rules_to_install'; -import { getRulesToUpdate } from '../../rules/get_rules_to_update'; -import { findRules } from '../../rules/find_rules'; -import { getLatestPrepackagedRules } from '../../rules/get_prepackaged_rules'; -import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules'; -import { ruleAssetSavedObjectsClientFactory } from '../../rules/rule_asset/rule_asset_saved_objects_client'; -import { buildFrameworkRequest } from '../../../timeline/utils/common'; -import type { ConfigType } from '../../../../config'; -import type { SetupPlugins } from '../../../../plugin'; -import { - checkTimelinesStatus, - checkTimelineStatusRt, -} from '../../../timeline/utils/check_timelines_status'; -import { rulesToMap } from '../../rules/utils'; - -export const getPrepackagedRulesStatusRoute = ( - router: SecuritySolutionPluginRouter, - config: ConfigType, - security: SetupPlugins['security'] -) => { - router.get( - { - path: `${DETECTION_ENGINE_PREPACKAGED_URL}/_status`, - validate: false, - options: { - tags: ['access:securitySolution'], - }, - }, - async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - const ctx = await context.resolve(['core', 'alerting']); - const savedObjectsClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); - const ruleAssetsClient = ruleAssetSavedObjectsClientFactory(savedObjectsClient); - - try { - const latestPrepackagedRules = await getLatestPrepackagedRules( - ruleAssetsClient, - config.prebuiltRulesFromFileSystem, - config.prebuiltRulesFromSavedObjects - ); - const customRules = await findRules({ - rulesClient, - perPage: 1, - page: 1, - sortField: 'enabled', - sortOrder: 'desc', - filter: 'alert.attributes.params.immutable: false', - fields: undefined, - }); - const frameworkRequest = await buildFrameworkRequest(context, security, request); - const installedPrePackagedRules = rulesToMap( - await getExistingPrepackagedRules({ rulesClient }) - ); - - const rulesToInstall = getRulesToInstall(latestPrepackagedRules, installedPrePackagedRules); - const rulesToUpdate = getRulesToUpdate(latestPrepackagedRules, installedPrePackagedRules); - const prepackagedTimelineStatus = await checkTimelinesStatus(frameworkRequest); - const [validatedPrepackagedTimelineStatus] = validate( - prepackagedTimelineStatus, - checkTimelineStatusRt - ); - - const prepackagedRulesStatus: PrePackagedRulesAndTimelinesStatusSchema = { - rules_custom_installed: customRules.total, - rules_installed: installedPrePackagedRules.size, - rules_not_installed: rulesToInstall.length, - rules_not_updated: rulesToUpdate.length, - timelines_installed: validatedPrepackagedTimelineStatus?.prepackagedTimelines.length ?? 0, - timelines_not_installed: - validatedPrepackagedTimelineStatus?.timelinesToInstall.length ?? 0, - timelines_not_updated: validatedPrepackagedTimelineStatus?.timelinesToUpdate.length ?? 0, - }; - const [validated, errors] = validate( - prepackagedRulesStatus, - prePackagedRulesAndTimelinesStatusSchema - ); - if (errors != null) { - return siemResponse.error({ statusCode: 500, body: errors }); - } else { - return response.ok({ body: validated ?? {} }); - } - } catch (err) { - const error = transformError(err); - return siemResponse.error({ - body: error.message, - statusCode: error.statusCode, - }); - } - } - ); -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/legacy_create_legacy_notification.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts similarity index 90% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/legacy_create_legacy_notification.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts index e6d98ed4f8195..5b20d410db8ce 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/legacy_create_legacy_notification.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts @@ -8,15 +8,15 @@ import { schema } from '@kbn/config-schema'; import type { Logger } from '@kbn/core/server'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; // eslint-disable-next-line no-restricted-imports -import { legacyUpdateOrCreateRuleActionsSavedObject } from '../../rule_actions/legacy_update_or_create_rule_actions_saved_object'; +import { legacyUpdateOrCreateRuleActionsSavedObject } from '../../logic/rule_actions/legacy_update_or_create_rule_actions_saved_object'; // eslint-disable-next-line no-restricted-imports -import { legacyReadNotifications } from '../../notifications/legacy_read_notifications'; +import { legacyReadNotifications } from '../../logic/notifications/legacy_read_notifications'; // eslint-disable-next-line no-restricted-imports -import type { LegacyRuleNotificationAlertTypeParams } from '../../notifications/legacy_types'; +import type { LegacyRuleNotificationAlertTypeParams } from '../../logic/notifications/legacy_types'; // eslint-disable-next-line no-restricted-imports -import { legacyCreateNotifications } from '../../notifications/legacy_create_notifications'; +import { legacyCreateNotifications } from '../../logic/notifications/legacy_create_notifications'; /** * Given an "alert_id" and a valid "action_id" this will create a legacy notification. This is for testing diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/register_routes.ts new file mode 100644 index 0000000000000..aa4010691a71b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/register_routes.ts @@ -0,0 +1,20 @@ +/* + * 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 { Logger } from '@kbn/core/server'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; + +// eslint-disable-next-line no-restricted-imports +import { legacyCreateLegacyNotificationRoute } from './create_legacy_notification/route'; + +export const registerLegacyRuleActionsRoutes = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + // Once we no longer have the legacy notifications system/"side car actions" this should be removed. + legacyCreateLegacyNotificationRoute(router, logger); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/index.ts new file mode 100644 index 0000000000000..22d3c347eef85 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/index.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +export * from './api/register_routes'; + +// eslint-disable-next-line no-restricted-imports +export { legacyRulesNotificationAlertType } from './logic/notifications/legacy_rules_notification_alert_type'; +// eslint-disable-next-line no-restricted-imports +export { legacyIsNotificationAlertExecutor } from './logic/notifications/legacy_types'; +// eslint-disable-next-line no-restricted-imports +export type { + LegacyRuleNotificationAlertType, + LegacyRuleNotificationAlertTypeParams, +} from './logic/notifications/legacy_types'; +export type { NotificationRuleTypeParams } from './logic/notifications/schedule_notification_actions'; +export { scheduleNotificationActions } from './logic/notifications/schedule_notification_actions'; +export { scheduleThrottledNotificationActions } from './logic/notifications/schedule_throttle_notification_actions'; +export { getNotificationResultsLink } from './logic/notifications/utils'; + +// eslint-disable-next-line no-restricted-imports +export { legacyGetBulkRuleActionsSavedObject } from './logic/rule_actions/legacy_get_bulk_rule_actions_saved_object'; +// eslint-disable-next-line no-restricted-imports +export type { LegacyRulesActionsSavedObject } from './logic/rule_actions/legacy_get_rule_actions_saved_object'; +// eslint-disable-next-line no-restricted-imports +export { legacyGetRuleActionsSavedObject } from './logic/rule_actions/legacy_get_rule_actions_saved_object'; +// eslint-disable-next-line no-restricted-imports +export { + legacyType, + legacyRuleActionsSavedObjectType, +} from './logic/rule_actions/legacy_saved_object_mappings'; +// eslint-disable-next-line no-restricted-imports +export type { + LegacyRuleActions, + LegacyRuleAlertAction, + LegacyIRuleActionsAttributes, + LegacyRuleAlertSavedObjectAction, + LegacyIRuleActionsAttributesSavedObjectAttributes, +} from './logic/rule_actions/legacy_types'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/build_signals_query.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/build_signals_query.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/build_signals_query.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/build_signals_query.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/build_signals_query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/build_signals_query.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/build_signals_query.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/build_signals_query.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/get_signals.ts similarity index 92% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/get_signals.ts index ab202170e5764..5963cc0cb2211 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/get_signals.ts @@ -6,7 +6,7 @@ */ import type { ElasticsearchClient } from '@kbn/core/server'; -import type { SignalSearchResponse, SignalSource } from '../signals/types'; +import type { SignalSearchResponse, SignalSource } from '../../../signals/types'; import { buildSignalsSearchQuery } from './build_signals_query'; interface GetSignalsParams { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.ts index 5db2759ad88da..983519404b222 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.ts @@ -6,7 +6,7 @@ */ import type { SanitizedRule } from '@kbn/alerting-plugin/common'; -import { SERVER_APP_ID, LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants'; +import { SERVER_APP_ID, LEGACY_NOTIFICATIONS_ID } from '../../../../../../common/constants'; // eslint-disable-next-line no-restricted-imports import type { CreateNotificationParams, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_find_notifications.test.ts similarity index 91% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_find_notifications.test.ts index 32a1b0eacd55b..d5ebddf4d2b63 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_find_notifications.test.ts @@ -7,7 +7,7 @@ // eslint-disable-next-line no-restricted-imports import { legacyGetFilter } from './legacy_find_notifications'; -import { LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants'; +import { LEGACY_NOTIFICATIONS_ID } from '../../../../../../common/constants'; describe('legacyFind_notifications', () => { test('it returns a full filter with an AND if sent down', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_find_notifications.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_find_notifications.ts index ba2f3e54dd9dc..0f981e6c6a005 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_find_notifications.ts @@ -6,7 +6,7 @@ */ import type { RuleTypeParams, FindResult } from '@kbn/alerting-plugin/server'; -import { LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants'; +import { LEGACY_NOTIFICATIONS_ID } from '../../../../../../common/constants'; // eslint-disable-next-line no-restricted-imports import type { LegacyFindNotificationParams } from './legacy_types'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.test.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.test.ts index 0980159d67882..f39881ac63250 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.test.ts @@ -11,7 +11,7 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; import { legacyGetNotificationResult, legacyGetFindNotificationsResultWithSingleHit, -} from '../routes/__mocks__/request_responses'; +} from '../../../routes/__mocks__/request_responses'; class LegacyTestError extends Error { constructor() { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.test.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.test.ts index b79e8ac4cbbdb..ddfca67279074 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.test.ts @@ -9,7 +9,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import type { RuleExecutorServicesMock } from '@kbn/alerting-plugin/server/mocks'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; -import { getRuleMock } from '../routes/__mocks__/request_responses'; +import { getRuleMock } from '../../../routes/__mocks__/request_responses'; // eslint-disable-next-line no-restricted-imports import { legacyRulesNotificationAlertType } from './legacy_rules_notification_alert_type'; import { buildSignalsSearchQuery } from './build_signals_query'; @@ -19,9 +19,9 @@ import { sampleDocSearchResultsNoSortIdNoVersion, sampleDocSearchResultsWithSortId, sampleEmptyDocSearchResults, -} from '../signals/__mocks__/es_results'; -import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../common/constants'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; +} from '../../../signals/__mocks__/es_results'; +import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../../../common/constants'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; jest.mock('./build_signals_query'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts similarity index 96% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts index 880882df04af2..7e76c2c1158d2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts @@ -11,14 +11,14 @@ import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE, LEGACY_NOTIFICATIONS_ID, SERVER_APP_ID, -} from '../../../../common/constants'; +} from '../../../../../../common/constants'; // eslint-disable-next-line no-restricted-imports import type { LegacyNotificationAlertTypeDefinition } from './legacy_types'; // eslint-disable-next-line no-restricted-imports import { legacyRulesNotificationParams } from './legacy_types'; -import type { AlertAttributes } from '../signals/types'; -import { siemRuleActionGroups } from '../signals/siem_rule_action_groups'; +import type { AlertAttributes } from '../../../signals/types'; +import { siemRuleActionGroups } from '../../../signals/siem_rule_action_groups'; import { scheduleNotificationActions } from './schedule_notification_actions'; import { getNotificationResultsLink } from './utils'; import { getSignals } from './get_signals'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/README.md b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/README.md similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/README.md rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/README.md diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_references.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_references.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_references.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_rule_id.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_rule_id.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_rule_id.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_rule_id.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_rule_id.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_rule_id.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_extract_rule_id.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_rule_id.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_references.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_references.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_references.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_references.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_inject_rule_id_references.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_types.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_types.ts index a3516d2caa7f0..2aea76d8c51e1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_types.ts @@ -19,7 +19,7 @@ import type { RuleExecutorOptions, } from '@kbn/alerting-plugin/server'; import type { Rule, RuleAction } from '@kbn/alerting-plugin/common'; -import { LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants'; +import { LEGACY_NOTIFICATIONS_ID } from '../../../../../../common/constants'; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.test.ts index 05741547241a3..b82136e33acf2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.test.ts @@ -7,9 +7,9 @@ import type { RuleExecutorServicesMock } from '@kbn/alerting-plugin/server/mocks'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; -import type { DetectionAlert } from '../../../../common/detection_engine/schemas/alerts'; -import { ALERT_THRESHOLD_RESULT_COUNT } from '../../../../common/field_maps/field_names'; -import { sampleThresholdAlert } from '../rule_types/__mocks__/threshold'; +import type { DetectionAlert } from '../../../../../../common/detection_engine/schemas/alerts'; +import { ALERT_THRESHOLD_RESULT_COUNT } from '../../../../../../common/field_maps/field_names'; +import { sampleThresholdAlert } from '../../../rule_types/__mocks__/threshold'; import type { NotificationRuleTypeParams } from './schedule_notification_actions'; import { formatAlertsForNotificationActions, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.ts similarity index 81% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.ts index 7783ca0e1ede8..8ca2bc0a4fb01 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.ts @@ -9,13 +9,13 @@ import { mapKeys, snakeCase } from 'lodash/fp'; import type { Alert } from '@kbn/alerting-plugin/server'; import { ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; import { flattenWithPrefix } from '@kbn/securitysolution-rules'; -import { ALERT_THRESHOLD_RESULT } from '../../../../common/field_maps/field_names'; -import { isThresholdRule } from '../../../../common/detection_engine/utils'; -import { expandDottedObject } from '../../../../common/utils/expand_dotted'; -import type { RuleParams } from '../schemas/rule_schemas'; -import aadFieldConversion from '../routes/index/signal_aad_mapping.json'; -import { isDetectionAlert } from '../signals/utils'; -import type { DetectionAlert } from '../../../../common/detection_engine/schemas/alerts'; +import { ALERT_THRESHOLD_RESULT } from '../../../../../../common/field_maps/field_names'; +import { isThresholdRule } from '../../../../../../common/detection_engine/utils'; +import { expandDottedObject } from '../../../../../../common/utils/expand_dotted'; +import type { RuleParams } from '../../../rule_schema'; +import aadFieldConversion from '../../../routes/index/signal_aad_mapping.json'; +import { isDetectionAlert } from '../../../signals/utils'; +import type { DetectionAlert } from '../../../../../../common/detection_engine/schemas/alerts'; export type NotificationRuleTypeParams = RuleParams & { id: string; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_throttle_notification_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_throttle_notification_actions.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_throttle_notification_actions.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_throttle_notification_actions.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_throttle_notification_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_throttle_notification_actions.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_throttle_notification_actions.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_throttle_notification_actions.ts index 90bc88a7ccb56..98f5ee9d42557 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_throttle_notification_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_throttle_notification_actions.ts @@ -8,13 +8,13 @@ import type { ElasticsearchClient, SavedObject, Logger } from '@kbn/core/server'; import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; import type { Alert } from '@kbn/alerting-plugin/server'; -import type { RuleParams } from '../schemas/rule_schemas'; +import type { RuleParams } from '../../../rule_schema'; import { deconflictSignalsAndResults, getNotificationResultsLink } from './utils'; -import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../common/constants'; +import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../../../common/constants'; import { getSignals } from './get_signals'; import type { NotificationRuleTypeParams } from './schedule_notification_actions'; import { scheduleNotificationActions } from './schedule_notification_actions'; -import type { AlertAttributes } from '../signals/types'; +import type { AlertAttributes } from '../../../signals/types'; interface ScheduleThrottledNotificationActionsOptions { id: SavedObject['id']; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/utils.test.ts similarity index 99% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/utils.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/utils.test.ts index d281cc9ae977b..cb3c4e0d4bd41 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/utils.test.ts @@ -7,7 +7,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -import type { SignalSource } from '../signals/types'; +import type { SignalSource } from '../../../signals/types'; import { deconflictSignalsAndResults, getNotificationResultsLink } from './utils'; describe('utils', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/utils.ts similarity index 95% rename from x-pack/plugins/security_solution/server/lib/detection_engine/notifications/utils.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/utils.ts index 560ec11cbef19..9eef538efe859 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/utils.ts @@ -6,8 +6,8 @@ */ import type { Logger } from '@kbn/core/server'; -import { APP_PATH } from '../../../../common/constants'; -import type { SignalSearchResponse } from '../signals/types'; +import { APP_PATH } from '../../../../../../common/constants'; +import type { SignalSearchResponse } from '../../../signals/types'; export const getNotificationResultsLink = ({ kibanaSiemAppUrl = APP_PATH, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_create_rule_actions_saved_object.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_create_rule_actions_saved_object.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_create_rule_actions_saved_object.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_create_rule_actions_saved_object.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_bulk_rule_actions_saved_object.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_bulk_rule_actions_saved_object.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts index e827bd4fe14e5..300d5307c1773 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts @@ -17,7 +17,7 @@ import type { LegacyIRuleActionsAttributesSavedObjectAttributes } from './legacy import { legacyGetRuleActionsFromSavedObject } from './legacy_utils'; // eslint-disable-next-line no-restricted-imports import type { LegacyRulesActionsSavedObject } from './legacy_get_rule_actions_saved_object'; -import { initPromisePool } from '../../../utils/promise_pool'; +import { initPromisePool } from '../../../../../utils/promise_pool'; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_rule_actions_saved_object.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_rule_actions_saved_object.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_rule_actions_saved_object.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_get_rule_actions_saved_object.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_saved_object_mappings.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_saved_object_mappings.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_update_rule_actions_saved_object.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_rule_actions_saved_object.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_update_rule_actions_saved_object.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_utils.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_utils.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_utils.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_utils.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.test.ts index a65d165f9e109..ab7efc936a58a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.test.ts @@ -7,11 +7,11 @@ import { getDetectionsExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { getRuleMock, resolveRuleMock } from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { createRuleExceptionsRoute } from './create_rule_exceptions_route'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../common/constants'; +import { getRuleMock, resolveRuleMock } from '../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, requestMock } from '../../../routes/__mocks__'; +import { createRuleExceptionsRoute } from './route'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; const getMockExceptionItem = () => ({ description: 'Exception item for rule default exception list', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.ts similarity index 86% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.ts index 8b5c3e1b044f2..9a13833e08437 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.ts @@ -27,35 +27,38 @@ import { formatErrors, validate } from '@kbn/securitysolution-io-ts-utils'; import type { SanitizedRule } from '@kbn/alerting-plugin/common'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; import type { RulesClient } from '@kbn/alerting-plugin/server'; + import type { - CreateRuleExceptionSchemaDecoded, - QueryRuleByIdSchemaDecoded, -} from '../../../../../common/detection_engine/schemas/request'; + CreateRuleExceptionsRequestBodyDecoded, + CreateRuleExceptionsRequestParamsDecoded, +} from '../../../../../../common/detection_engine/rule_exceptions'; import { - createRuleExceptionsSchema, - queryRuleByIdSchema, -} from '../../../../../common/detection_engine/schemas/request'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { buildSiemResponse } from '../utils'; -import { patchRules } from '../../rules/patch_rules'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { readRules } from '../../rules/read_rules'; -import type { RuleParams } from '../../schemas/rule_schemas'; -import { checkDefaultRuleExceptionListReferences } from './utils/check_for_default_rule_exception_list'; + CREATE_RULE_EXCEPTIONS_URL, + CreateRuleExceptionsRequestBody, + CreateRuleExceptionsRequestParams, +} from '../../../../../../common/detection_engine/rule_exceptions'; + +import { readRules } from '../../../rule_management/logic/crud/read_rules'; +import { patchRules } from '../../../rule_management/logic/crud/patch_rules'; +import { checkDefaultRuleExceptionListReferences } from '../../../rule_management/logic/exceptions/check_for_default_rule_exception_list'; +import type { RuleParams } from '../../../rule_schema'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; +import { buildSiemResponse } from '../../../routes/utils'; +import { buildRouteValidation } from '../../../../../utils/build_validation/route_validation'; export const createRuleExceptionsRoute = (router: SecuritySolutionPluginRouter) => { router.post( { - path: `${DETECTION_ENGINE_RULES_URL}/{id}/exceptions`, + path: CREATE_RULE_EXCEPTIONS_URL, validate: { - params: buildRouteValidation( - queryRuleByIdSchema - ), + params: buildRouteValidation< + typeof CreateRuleExceptionsRequestParams, + CreateRuleExceptionsRequestParamsDecoded + >(CreateRuleExceptionsRequestParams), body: buildRouteValidation< - typeof createRuleExceptionsSchema, - CreateRuleExceptionSchemaDecoded - >(createRuleExceptionsSchema), + typeof CreateRuleExceptionsRequestBody, + CreateRuleExceptionsRequestBodyDecoded + >(CreateRuleExceptionsRequestBody), }, options: { tags: ['access:securitySolution'], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.test.ts similarity index 95% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.test.ts index 39d2dca25f050..33e66bb6405f8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.test.ts @@ -5,16 +5,18 @@ * 2.0. */ -import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '../../../../../common/constants'; +import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; + +import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '../../../../../../common/detection_engine/rule_exceptions'; + import { getEmptyFindResult, getFindResultWithSingleHit, getRuleMock, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { findRuleExceptionReferencesRoute } from './find_rule_exceptions_route'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; +} from '../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, requestMock } from '../../../routes/__mocks__'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; +import { findRuleExceptionReferencesRoute } from './route'; describe('findRuleExceptionReferencesRoute', () => { let server: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.ts similarity index 75% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.ts index 531a33b253084..a9643989a3a3b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.ts @@ -9,16 +9,22 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { validate } from '@kbn/securitysolution-io-ts-utils'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '../../../../../common/constants'; -import { buildSiemResponse } from '../utils'; -import { enrichFilterWithRuleTypeMapping } from '../../rules/enrich_filter_with_rule_type_mappings'; -import type { FindExceptionReferencesOnRuleSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/find_exception_list_references_schema'; -import { findExceptionReferencesOnRuleSchema } from '../../../../../common/detection_engine/schemas/request/find_exception_list_references_schema'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { RuleReferencesSchema } from '../../../../../common/detection_engine/schemas/response/find_exception_list_references_schema'; -import { rulesReferencedByExceptionListsSchema } from '../../../../../common/detection_engine/schemas/response/find_exception_list_references_schema'; -import type { RuleParams } from '../../schemas/rule_schemas'; +import { buildRouteValidation } from '../../../../../utils/build_validation/route_validation'; +import { buildSiemResponse } from '../../../routes/utils'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; + +import type { + FindExceptionReferencesOnRuleSchemaDecoded, + RuleReferencesSchema, +} from '../../../../../../common/detection_engine/rule_exceptions'; +import { + DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL, + findExceptionReferencesOnRuleSchema, + rulesReferencedByExceptionListsSchema, +} from '../../../../../../common/detection_engine/rule_exceptions'; + +import { enrichFilterWithRuleTypeMapping } from '../../../rule_management/logic/search/enrich_filter_with_rule_type_mappings'; +import type { RuleParams } from '../../../rule_schema'; export const findRuleExceptionReferencesRoute = (router: SecuritySolutionPluginRouter) => { router.get( @@ -56,14 +62,18 @@ export const findRuleExceptionReferencesRoute = (router: SecuritySolutionPluginR } const fetchExact = ids != null && listIds != null; - const foundExceptionLists = await listsClient?.findExceptionList({ filter: fetchExact ? `(${listIds - .map((listId) => `exception-list.attributes.list_id:${listId}`) + .map( + (listId, index) => + `${getSavedObjectType({ + namespaceType: namespaceTypes[index], + })}.attributes.list_id:${listId}` + ) .join(' OR ')})` : undefined, - namespaceType: ['agnostic', 'single'], + namespaceType: namespaceTypes, page: 1, perPage: 10000, sortField: undefined, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/register_routes.ts new file mode 100644 index 0000000000000..4d65f13c94ee2 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/register_routes.ts @@ -0,0 +1,16 @@ +/* + * 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 { SecuritySolutionPluginRouter } from '../../../../types'; + +import { createRuleExceptionsRoute } from './create_rule_exceptions/route'; +import { findRuleExceptionReferencesRoute } from './find_exception_references/route'; + +export const registerRuleExceptionsRoutes = (router: SecuritySolutionPluginRouter) => { + createRuleExceptionsRoute(router); + findRuleExceptionReferencesRoute(router); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/index.ts new file mode 100644 index 0000000000000..c0123e587d9bf --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './api/register_routes'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/deprecation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/deprecation.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/deprecation.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/deprecation.ts index 314d7db33fcef..8e956e0e48aa6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/deprecation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/deprecation.ts @@ -7,7 +7,7 @@ import { getDocLinks } from '@kbn/doc-links'; import type { Logger } from '@kbn/core/server'; -import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../../common/constants'; +import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants'; /** * Helper method for building deprecation messages diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts new file mode 100644 index 0000000000000..90a37a7dbe7da --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts @@ -0,0 +1,59 @@ +/* + * 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 { Logger } from '@kbn/core/server'; +import type { ConfigType } from '../../../../config'; +import type { SetupPlugins } from '../../../../plugin_contract'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; + +import { performBulkActionRoute } from './rules/bulk_actions/route'; +import { bulkCreateRulesRoute } from './rules/bulk_create_rules/route'; +import { bulkDeleteRulesRoute } from './rules/bulk_delete_rules/route'; +import { bulkPatchRulesRoute } from './rules/bulk_patch_rules/route'; +import { bulkUpdateRulesRoute } from './rules/bulk_update_rules/route'; +import { createRuleRoute } from './rules/create_rule/route'; +import { deleteRuleRoute } from './rules/delete_rule/route'; +import { exportRulesRoute } from './rules/export_rules/route'; +import { findRulesRoute } from './rules/find_rules/route'; +import { importRulesRoute } from './rules/import_rules/route'; +import { patchRuleRoute } from './rules/patch_rule/route'; +import { readRuleRoute } from './rules/read_rule/route'; +import { updateRuleRoute } from './rules/update_rule/route'; +import { readTagsRoute } from './tags/read_tags/route'; + +export const registerRuleManagementRoutes = ( + router: SecuritySolutionPluginRouter, + config: ConfigType, + ml: SetupPlugins['ml'], + logger: Logger +) => { + // Rules CRUD + createRuleRoute(router, ml); + readRuleRoute(router, logger); + updateRuleRoute(router, ml); + patchRuleRoute(router, ml); + deleteRuleRoute(router); + + // Rules bulk CRUD + bulkCreateRulesRoute(router, ml, logger); + bulkUpdateRulesRoute(router, ml, logger); + bulkPatchRulesRoute(router, ml, logger); + bulkDeleteRulesRoute(router, logger); + + // Rules bulk actions + performBulkActionRoute(router, ml, logger); + + // Rules export/import + exportRulesRoute(router, config, logger); + importRulesRoute(router, config, ml); + + // Rules search + findRulesRoute(router, logger); + + // Rule tags + readTagsRoute(router); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.test.ts index 1438905a5c079..f64de099dfcbe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.test.ts @@ -8,9 +8,9 @@ import { DETECTION_ENGINE_RULES_BULK_ACTION, BulkActionsDryRunErrCode, -} from '../../../../../common/constants'; -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; +} from '../../../../../../../common/constants'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { getEmptyFindResult, getBulkActionRequest, @@ -18,30 +18,31 @@ import { getFindResultWithSingleHit, getFindResultWithMultiHits, getRuleMock, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { performBulkActionRoute } from './perform_bulk_action_route'; +} from '../../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; +import { performBulkActionRoute } from './route'; import { getPerformBulkActionEditSchemaMock, getPerformBulkActionSchemaMock, -} from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema.mock'; +} from '../../../../../../../common/detection_engine/rule_management/mocks'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { readRules } from '../../rules/read_rules'; -import { legacyMigrate } from '../../rules/utils'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +import { readRules } from '../../../logic/crud/read_rules'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); -jest.mock('../../rules/read_rules', () => ({ readRules: jest.fn() })); +jest.mock('../../../../../machine_learning/authz'); +jest.mock('../../../logic/crud/read_rules', () => ({ readRules: jest.fn() })); -jest.mock('../../rules/utils', () => { - const actual = jest.requireActual('../../rules/utils'); +jest.mock('../../../logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual('../../../logic/rule_actions/legacy_action_migration'); return { ...actual, legacyMigrate: jest.fn(), }; }); -describe('perform_bulk_action', () => { +describe('Perform bulk action route', () => { const readRulesMock = readRules as jest.Mock; let server: ReturnType; let { clients, context } = requestContextMock.createTools(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts similarity index 90% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts index 56d93a1ed0336..67a9a233eb807 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts @@ -13,43 +13,43 @@ import type { KibanaResponseFactory, Logger, SavedObjectsClientContract } from ' import type { RulesClient, BulkEditError } from '@kbn/alerting-plugin/server'; import type { SanitizedRule } from '@kbn/alerting-plugin/common'; import { AbortError } from '@kbn/kibana-utils-plugin/common'; -import type { RuleAlertType } from '../../rules/types'; +import type { RuleAlertType, RuleParams } from '../../../../rule_schema'; -import type { BulkActionsDryRunErrCode } from '../../../../../common/constants'; +import type { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; import { DETECTION_ENGINE_RULES_BULK_ACTION, MAX_RULES_TO_UPDATE_IN_PARALLEL, RULES_TABLE_MAX_PAGE_SIZE, -} from '../../../../../common/constants'; +} from '../../../../../../../common/constants'; import { - performBulkActionSchema, - performBulkActionQuerySchema, BulkAction, -} from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { SetupPlugins } from '../../../../plugin'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { routeLimitedConcurrencyTag } from '../../../../utils/route_limited_concurrency_tag'; -import type { PromisePoolError, PromisePoolOutcome } from '../../../../utils/promise_pool'; -import { initPromisePool } from '../../../../utils/promise_pool'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { deleteRules } from '../../rules/delete_rules'; -import { duplicateRule } from '../../rules/duplicate_rule'; -import { findRules } from '../../rules/find_rules'; -import { readRules } from '../../rules/read_rules'; -import { bulkEditRules } from '../../rules/bulk_edit_rules'; -import { getExportByObjectIds } from '../../rules/get_export_by_object_ids'; -import { buildSiemResponse } from '../utils'; -import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; -import { legacyMigrate } from '../../rules/utils'; -import type { DryRunError } from '../../rules/bulk_actions/dry_run'; + PerformBulkActionRequestBody, + PerformBulkActionRequestQuery, +} from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { SetupPlugins } from '../../../../../../plugin'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { routeLimitedConcurrencyTag } from '../../../../../../utils/route_limited_concurrency_tag'; +import type { PromisePoolError, PromisePoolOutcome } from '../../../../../../utils/promise_pool'; +import { initPromisePool } from '../../../../../../utils/promise_pool'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { deleteRules } from '../../../logic/crud/delete_rules'; +import { duplicateRule } from '../../../logic/actions/duplicate_rule'; +import { findRules } from '../../../logic/search/find_rules'; +import { readRules } from '../../../logic/crud/read_rules'; +import { getExportByObjectIds } from '../../../logic/export/get_export_by_object_ids'; +import { buildSiemResponse } from '../../../../routes/utils'; +import { internalRuleToAPIResponse } from '../../../normalization/rule_converters'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { bulkEditRules } from '../../../logic/bulk_actions/bulk_edit_rules'; +import type { DryRunError } from '../../../logic/bulk_actions/dry_run'; import { validateBulkEnableRule, validateBulkDisableRule, validateBulkDuplicateRule, dryRunValidateBulkEditRule, -} from '../../rules/bulk_actions/validations'; -import type { RuleParams } from '../../schemas/rule_schemas'; +} from '../../../logic/bulk_actions/validations'; const MAX_RULES_TO_PROCESS_TOTAL = 10000; const MAX_ERROR_MESSAGE_LENGTH = 1000; @@ -267,10 +267,8 @@ export const performBulkActionRoute = ( { path: DETECTION_ENGINE_RULES_BULK_ACTION, validate: { - body: buildRouteValidation(performBulkActionSchema), - query: buildRouteValidation( - performBulkActionQuerySchema - ), + body: buildRouteValidation(PerformBulkActionRequestBody), + query: buildRouteValidation(PerformBulkActionRequestQuery), }, options: { tags: ['access:securitySolution', routeLimitedConcurrencyTag(MAX_ROUTE_CONCURRENCY)], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/get_duplicates.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/get_duplicates.test.ts new file mode 100644 index 0000000000000..bc15b93639cdb --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/get_duplicates.test.ts @@ -0,0 +1,43 @@ +/* + * 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 { BulkCreateRulesRequestBody } from '../../../../../../../common/detection_engine/rule_management'; +import { getDuplicates } from './get_duplicates'; + +describe('getDuplicates', () => { + test("returns array of ruleIds showing the duplicate keys of 'value2' and 'value3'", () => { + const output = getDuplicates( + [ + { rule_id: 'value1' }, + { rule_id: 'value2' }, + { rule_id: 'value2' }, + { rule_id: 'value3' }, + { rule_id: 'value3' }, + {}, + {}, + ] as BulkCreateRulesRequestBody, + 'rule_id' + ); + const expected = ['value2', 'value3']; + expect(output).toEqual(expected); + }); + + test('returns null when given a map of no duplicates', () => { + const output = getDuplicates( + [ + { rule_id: 'value1' }, + { rule_id: 'value2' }, + { rule_id: 'value3' }, + {}, + {}, + ] as BulkCreateRulesRequestBody, + 'rule_id' + ); + const expected: string[] = []; + expect(output).toEqual(expected); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/get_duplicates.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/get_duplicates.ts new file mode 100644 index 0000000000000..3d537bbd25c46 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/get_duplicates.ts @@ -0,0 +1,24 @@ +/* + * 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 { countBy } from 'lodash/fp'; +import type { BulkCreateRulesRequestBody } from '../../../../../../../common/detection_engine/rule_management'; + +export const getDuplicates = ( + ruleDefinitions: BulkCreateRulesRequestBody, + by: 'rule_id' +): string[] => { + const mappedDuplicates = countBy( + by, + ruleDefinitions.filter((r) => r[by] != null) + ); + const hasDuplicates = Object.values(mappedDuplicates).some((i) => i > 1); + if (hasDuplicates) { + return Object.keys(mappedDuplicates).filter((key) => mappedDuplicates[key] > 1); + } + return []; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts similarity index 90% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts index c845f2e0a381c..1dcb5e885d72b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../common/constants'; -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; +import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../../../common/constants'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { getReadBulkRequest, getFindResultWithSingleHit, @@ -16,17 +16,17 @@ import { createBulkMlRuleRequest, getBasicEmptySearchResponse, getBasicNoShardsSearchResponse, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { createRulesBulkRoute } from './create_rules_bulk_route'; -import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; +} from '../../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; +import { bulkCreateRulesRoute } from './route'; +import { getCreateRulesSchemaMock } from '../../../../../../../common/detection_engine/rule_schema/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); +jest.mock('../../../../../machine_learning/authz'); -describe('create_rules_bulk', () => { +describe('Bulk create rules route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType; @@ -43,7 +43,7 @@ describe('create_rules_bulk', () => { context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse()) ); - createRulesBulkRoute(server.router, ml, logger); + bulkCreateRulesRoute(server.router, ml, logger); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts similarity index 73% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts index b6bdba6fca3bd..960ddb15c5301 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts @@ -5,29 +5,37 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { Logger } from '@kbn/core/server'; -import { createRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/create_rules_type_dependents'; -import { createRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/create_rules_bulk_schema'; -import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../common/constants'; -import type { SetupPlugins } from '../../../../plugin'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; -import { readRules } from '../../rules/read_rules'; -import { getDuplicates } from './utils'; -import { transformValidateBulkError } from './validate'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { validate } from '@kbn/securitysolution-io-ts-utils'; + +import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../../../common/constants'; +import { + BulkCreateRulesRequestBody, + validateCreateRuleProps, + BulkCrudRulesResponse, +} from '../../../../../../../common/detection_engine/rule_management'; + +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import type { SetupPlugins } from '../../../../../../plugin'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../../machine_learning/validation'; +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 { transformBulkError, createBulkErrorObject, buildSiemResponse } from '../utils'; -import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from './utils/deprecation'; -import { createRules } from '../../rules/create_rules'; +import { + transformBulkError, + createBulkErrorObject, + buildSiemResponse, +} from '../../../../routes/utils'; +import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from '../../deprecation'; /** * @deprecated since version 8.2.0. Use the detection_engine/rules/_bulk_action API instead */ -export const createRulesBulkRoute = ( +export const bulkCreateRulesRoute = ( router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml'], logger: Logger @@ -36,7 +44,7 @@ export const createRulesBulkRoute = ( { path: DETECTION_ENGINE_RULES_BULK_CREATE, validate: { - body: buildRouteValidation(createRulesBulkSchema), + body: buildRouteValidation(BulkCreateRulesRequestBody), }, options: { tags: ['access:securitySolution'], @@ -82,7 +90,7 @@ export const createRulesBulkRoute = ( } try { - const validationErrors = createRuleValidateTypeDependents(payloadRule); + const validationErrors = validateCreateRuleProps(payloadRule); if (validationErrors.length) { return createBulkErrorObject({ ruleId: payloadRule.rule_id, @@ -117,7 +125,7 @@ export const createRulesBulkRoute = ( }) ), ]; - const [validated, errors] = validate(rulesBulk, rulesBulkSchema); + const [validated, errors] = validate(rulesBulk, BulkCrudRulesResponse); if (errors != null) { return siemResponse.error({ statusCode: 500, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.test.ts similarity index 95% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.test.ts index 01683599e4cf6..750419c464b2a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DETECTION_ENGINE_RULES_BULK_DELETE } from '../../../../../common/constants'; +import { DETECTION_ENGINE_RULES_BULK_DELETE } from '../../../../../../../common/constants'; import { getEmptyFindResult, getFindResultWithSingleHit, @@ -14,12 +14,12 @@ import { getDeleteAsPostBulkRequest, getDeleteAsPostBulkRequestById, getEmptySavedObjectsResponse, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { deleteRulesBulkRoute } from './delete_rules_bulk_route'; +} from '../../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; +import { bulkDeleteRulesRoute } from './route'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -describe('delete_rules', () => { +describe('Bulk delete rules route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); @@ -32,7 +32,7 @@ describe('delete_rules', () => { clients.rulesClient.delete.mockResolvedValue({}); // successful deletion clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); // rule status request - deleteRulesBulkRoute(server.router, logger); + bulkDeleteRulesRoute(server.router, logger); }); describe('status codes with actionClient and alertClient', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts similarity index 68% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts index 2a459dd7c2941..399b12ded105e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts @@ -5,32 +5,40 @@ * 2.0. */ +import type { RouteConfig, RequestHandler, Logger } from '@kbn/core/server'; import { validate } from '@kbn/securitysolution-io-ts-utils'; -import type { RouteConfig, RequestHandler, Logger } from '@kbn/core/server'; -import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { QueryRulesBulkSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/query_rules_bulk_schema'; -import { queryRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/query_rules_bulk_schema'; -import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema'; +import { DETECTION_ENGINE_RULES_BULK_DELETE } from '../../../../../../../common/constants'; +import { + BulkDeleteRulesRequestBody, + validateQueryRuleByIds, + BulkCrudRulesResponse, +} from '../../../../../../../common/detection_engine/rule_management'; + +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter, SecuritySolutionRequestHandlerContext, -} from '../../../../types'; -import { DETECTION_ENGINE_RULES_BULK_DELETE } from '../../../../../common/constants'; -import { getIdBulkError } from './utils'; -import { transformValidateBulkError } from './validate'; -import { transformBulkError, buildSiemResponse, createBulkErrorObject } from '../utils'; -import { deleteRules } from '../../rules/delete_rules'; -import { readRules } from '../../rules/read_rules'; -import { legacyMigrate } from '../../rules/utils'; -import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from './utils/deprecation'; +} from '../../../../../../types'; + +import { getIdBulkError } from '../../../utils/utils'; +import { transformValidateBulkError } from '../../../utils/validate'; +import { + transformBulkError, + buildSiemResponse, + createBulkErrorObject, +} from '../../../../routes/utils'; +import { deleteRules } from '../../../logic/crud/delete_rules'; +import { readRules } from '../../../logic/crud/read_rules'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from '../../deprecation'; -type Config = RouteConfig; +type Config = RouteConfig; type Handler = RequestHandler< unknown, unknown, - QueryRulesBulkSchemaDecoded, + BulkDeleteRulesRequestBody, SecuritySolutionRequestHandlerContext, 'delete' | 'post' >; @@ -38,12 +46,10 @@ type Handler = RequestHandler< /** * @deprecated since version 8.2.0. Use the detection_engine/rules/_bulk_action API instead */ -export const deleteRulesBulkRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { +export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { const config: Config = { validate: { - body: buildRouteValidation( - queryRulesBulkSchema - ), + body: buildRouteValidation(BulkDeleteRulesRequestBody), }, path: DETECTION_ENGINE_RULES_BULK_DELETE, options: { @@ -65,7 +71,7 @@ export const deleteRulesBulkRoute = (router: SecuritySolutionPluginRouter, logge request.body.map(async (payloadRule) => { const { id, rule_id: ruleId } = payloadRule; const idOrRuleIdOrUnknown = id ?? ruleId ?? '(unknown id)'; - const validationErrors = queryRuleValidateTypeDependents(payloadRule); + const validationErrors = validateQueryRuleByIds(payloadRule); if (validationErrors.length) { return createBulkErrorObject({ ruleId: idOrRuleIdOrUnknown, @@ -103,7 +109,7 @@ export const deleteRulesBulkRoute = (router: SecuritySolutionPluginRouter, logge } }) ); - const [validated, errors] = validate(rules, rulesBulkSchema); + const [validated, errors] = validate(rules, BulkCrudRulesResponse); if (errors != null) { return siemResponse.error({ statusCode: 500, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts index da2808e572cf3..2082aa51815fd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts @@ -8,34 +8,35 @@ import { DETECTION_ENGINE_RULES_BULK_UPDATE, DETECTION_ENGINE_RULES_URL, -} from '../../../../../common/constants'; -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; +} from '../../../../../../../common/constants'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { getEmptyFindResult, getFindResultWithSingleHit, getPatchBulkRequest, getRuleMock, typicalMlRulePayload, -} from '../__mocks__/request_responses'; -import { serverMock, requestContextMock, requestMock } from '../__mocks__'; -import { patchRulesBulkRoute } from './patch_rules_bulk_route'; -import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { getMlRuleParams, getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +} from '../../../../routes/__mocks__/request_responses'; +import { serverMock, requestContextMock, requestMock } from '../../../../routes/__mocks__'; +import { bulkPatchRulesRoute } from './route'; +import { getCreateRulesSchemaMock } from '../../../../../../../common/detection_engine/rule_schema/mocks'; +import { getMlRuleParams, getQueryRuleParams } from '../../../../rule_schema/mocks'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { legacyMigrate } from '../../rules/utils'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); +jest.mock('../../../../../machine_learning/authz'); -jest.mock('../../rules/utils', () => { - const actual = jest.requireActual('../../rules/utils'); +jest.mock('../../../logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual('../../../logic/rule_actions/legacy_action_migration'); return { ...actual, legacyMigrate: jest.fn(), }; }); -describe('patch_rules_bulk', () => { +describe('Bulk patch rules route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType; @@ -51,7 +52,7 @@ describe('patch_rules_bulk', () => { (legacyMigrate as jest.Mock).mockResolvedValue(getRuleMock(getQueryRuleParams())); - patchRulesBulkRoute(server.router, ml, logger); + bulkPatchRulesRoute(server.router, ml, logger); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts similarity index 73% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts index f80a5ffb94e5c..1bbba63daa846 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts @@ -7,26 +7,31 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { Logger } from '@kbn/core/server'; -import { patchRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/patch_rules_bulk_schema'; -import { buildRouteValidationNonExact } from '../../../../utils/build_validation/route_validation'; -import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../common/constants'; -import type { SetupPlugins } from '../../../../plugin'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; -import { transformBulkError, buildSiemResponse } from '../utils'; -import { getIdBulkError } from './utils'; -import { transformValidateBulkError } from './validate'; -import { patchRules } from '../../rules/patch_rules'; -import { readRules } from '../../rules/read_rules'; -import { legacyMigrate } from '../../rules/utils'; -import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from './utils/deprecation'; + +import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../../../common/constants'; +import { + BulkPatchRulesRequestBody, + BulkCrudRulesResponse, +} from '../../../../../../../common/detection_engine/rule_management'; + +import { buildRouteValidationNonExact } from '../../../../../../utils/build_validation/route_validation'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import type { SetupPlugins } from '../../../../../../plugin'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../../machine_learning/validation'; +import { transformBulkError, buildSiemResponse } from '../../../../routes/utils'; +import { getIdBulkError } from '../../../utils/utils'; +import { transformValidateBulkError } from '../../../utils/validate'; +import { patchRules } from '../../../logic/crud/patch_rules'; +import { readRules } from '../../../logic/crud/read_rules'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from '../../deprecation'; /** * @deprecated since version 8.2.0. Use the detection_engine/rules/_bulk_action API instead */ -export const patchRulesBulkRoute = ( +export const bulkPatchRulesRoute = ( router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml'], logger: Logger @@ -35,7 +40,7 @@ export const patchRulesBulkRoute = ( { path: DETECTION_ENGINE_RULES_BULK_UPDATE, validate: { - body: buildRouteValidationNonExact(patchRulesBulkSchema), + body: buildRouteValidationNonExact(BulkPatchRulesRequestBody), }, options: { tags: ['access:securitySolution'], @@ -101,7 +106,7 @@ export const patchRulesBulkRoute = ( }) ); - const [validated, errors] = validate(rules, rulesBulkSchema); + const [validated, errors] = validate(rules, BulkCrudRulesResponse); if (errors != null) { return siemResponse.error({ statusCode: 500, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.test.ts similarity index 85% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.test.ts index 09e4dacec09de..5c8433b3e87fb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.test.ts @@ -5,35 +5,36 @@ * 2.0. */ -import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../common/constants'; -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; +import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../../../common/constants'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { getEmptyFindResult, getRuleMock, getFindResultWithSingleHit, getUpdateBulkRequest, typicalMlRulePayload, -} from '../__mocks__/request_responses'; -import { serverMock, requestContextMock, requestMock } from '../__mocks__'; -import { updateRulesBulkRoute } from './update_rules_bulk_route'; -import type { BulkError } from '../utils'; -import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +} from '../../../../routes/__mocks__/request_responses'; +import { serverMock, requestContextMock, requestMock } from '../../../../routes/__mocks__'; +import { bulkUpdateRulesRoute } from './route'; +import type { BulkError } from '../../../../routes/utils'; +import { getCreateRulesSchemaMock } from '../../../../../../../common/detection_engine/rule_schema/mocks'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { legacyMigrate } from '../../rules/utils'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); +jest.mock('../../../../../machine_learning/authz'); -jest.mock('../../rules/utils', () => { - const actual = jest.requireActual('../../rules/utils'); +jest.mock('../../../logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual('../../../logic/rule_actions/legacy_action_migration'); return { ...actual, legacyMigrate: jest.fn(), }; }); -describe('update_rules_bulk', () => { +describe('Bulk update rules route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType; @@ -51,7 +52,7 @@ describe('update_rules_bulk', () => { (legacyMigrate as jest.Mock).mockResolvedValue(getRuleMock(getQueryRuleParams())); - updateRulesBulkRoute(server.router, ml, logger); + bulkUpdateRulesRoute(server.router, ml, logger); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts similarity index 71% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts index d949a4bb9f5f9..5e22fc4d41c20 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts @@ -5,29 +5,38 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { Logger } from '@kbn/core/server'; -import { updateRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/update_rules_type_dependents'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { updateRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/update_rules_bulk_schema'; -import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../common/constants'; -import type { SetupPlugins } from '../../../../plugin'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; -import { getIdBulkError } from './utils'; -import { transformValidateBulkError } from './validate'; -import { transformBulkError, buildSiemResponse, createBulkErrorObject } from '../utils'; -import { updateRules } from '../../rules/update_rules'; -import { legacyMigrate } from '../../rules/utils'; -import { readRules } from '../../rules/read_rules'; -import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from './utils/deprecation'; +import { validate } from '@kbn/securitysolution-io-ts-utils'; + +import { + BulkUpdateRulesRequestBody, + validateUpdateRuleProps, + BulkCrudRulesResponse, +} from '../../../../../../../common/detection_engine/rule_management'; + +import { buildRouteValidation } 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'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../../machine_learning/validation'; +import { getIdBulkError } from '../../../utils/utils'; +import { transformValidateBulkError } from '../../../utils/validate'; +import { + transformBulkError, + buildSiemResponse, + createBulkErrorObject, +} from '../../../../routes/utils'; +import { updateRules } from '../../../logic/crud/update_rules'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { readRules } from '../../../logic/crud/read_rules'; +import { getDeprecatedBulkEndpointHeader, logDeprecatedBulkEndpoint } from '../../deprecation'; /** * @deprecated since version 8.2.0. Use the detection_engine/rules/_bulk_action API instead */ -export const updateRulesBulkRoute = ( +export const bulkUpdateRulesRoute = ( router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml'], logger: Logger @@ -36,7 +45,7 @@ export const updateRulesBulkRoute = ( { path: DETECTION_ENGINE_RULES_BULK_UPDATE, validate: { - body: buildRouteValidation(updateRulesBulkSchema), + body: buildRouteValidation(BulkUpdateRulesRequestBody), }, options: { tags: ['access:securitySolution'], @@ -64,7 +73,7 @@ export const updateRulesBulkRoute = ( request.body.map(async (payloadRule) => { const idOrRuleIdOrUnknown = payloadRule.id ?? payloadRule.rule_id ?? '(unknown id)'; try { - const validationErrors = updateRuleValidateTypeDependents(payloadRule); + const validationErrors = validateUpdateRuleProps(payloadRule); if (validationErrors.length) { return createBulkErrorObject({ ruleId: payloadRule.rule_id, @@ -104,7 +113,7 @@ export const updateRulesBulkRoute = ( }) ); - const [validated, errors] = validate(rules, rulesBulkSchema); + const [validated, errors] = validate(rules, BulkCrudRulesResponse); if (errors != null) { return siemResponse.error({ statusCode: 500, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts index f3c4a698d83d2..5c333cf240e2d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import { getEmptyFindResult, getRuleMock, @@ -13,18 +13,18 @@ import { getFindResultWithSingleHit, createMlRuleRequest, getBasicEmptySearchResponse, -} from '../__mocks__/request_responses'; -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { createRulesRoute } from './create_rules_route'; -import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; +} from '../../../../routes/__mocks__/request_responses'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; +import { createRuleRoute } from './route'; +import { getCreateRulesSchemaMock } from '../../../../../../../common/detection_engine/rule_schema/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); +jest.mock('../../../../../machine_learning/authz'); -describe('create_rules', () => { +describe('Create rule route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType; @@ -40,7 +40,7 @@ describe('create_rules', () => { context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse()) ); - createRulesRoute(server.router, ml); + createRuleRoute(server.router, ml); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts similarity index 69% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts index 6e76de5aa420d..cfea8ec27a5a7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts @@ -6,22 +6,24 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import type { SetupPlugins } from '../../../../plugin'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; -import { readRules } from '../../rules/read_rules'; -import { buildSiemResponse } from '../utils'; -import { createRulesSchema } from '../../../../../common/detection_engine/schemas/request'; -import { transformValidate } from './validate'; -import { createRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/create_rules_type_dependents'; -import { createRules } from '../../rules/create_rules'; -import { checkDefaultRuleExceptionListReferences } from './utils/check_for_default_rule_exception_list'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { validateCreateRuleProps } from '../../../../../../../common/detection_engine/rule_management'; +import { RuleCreateProps } from '../../../../../../../common/detection_engine/rule_schema'; -export const createRulesRoute = ( +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import type { SetupPlugins } from '../../../../../../plugin'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../../machine_learning/validation'; +import { readRules } from '../../../logic/crud/read_rules'; +import { buildSiemResponse } from '../../../../routes/utils'; + +import { createRules } from '../../../logic/crud/create_rules'; +import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list'; +import { transformValidate } from '../../../utils/validate'; + +export const createRuleRoute = ( router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml'] ): void => { @@ -29,7 +31,7 @@ export const createRulesRoute = ( { path: DETECTION_ENGINE_RULES_URL, validate: { - body: buildRouteValidation(createRulesSchema), + body: buildRouteValidation(RuleCreateProps), }, options: { tags: ['access:securitySolution'], @@ -37,7 +39,7 @@ export const createRulesRoute = ( }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const validationErrors = createRuleValidateTypeDependents(request.body); + const validationErrors = validateCreateRuleProps(request.body); if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.test.ts similarity index 83% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.test.ts index 85c324008856c..5f5e81a6c3960 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import { getEmptyFindResult, resolveRuleMock, @@ -14,21 +14,22 @@ import { getDeleteRequestById, getEmptySavedObjectsResponse, getRuleMock, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { deleteRulesRoute } from './delete_rules_route'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { legacyMigrate } from '../../rules/utils'; +} from '../../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; +import { deleteRuleRoute } from './route'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; -jest.mock('../../rules/utils', () => { - const actual = jest.requireActual('../../rules/utils'); +jest.mock('../../../logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual('../../../logic/rule_actions/legacy_action_migration'); return { ...actual, legacyMigrate: jest.fn(), }; }); -describe('delete_rules', () => { +describe('Delete rule route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); @@ -41,7 +42,7 @@ describe('delete_rules', () => { (legacyMigrate as jest.Mock).mockResolvedValue(getRuleMock(getQueryRuleParams())); - deleteRulesRoute(server.router); + deleteRuleRoute(server.router); }); describe('status codes with actionClient and alertClient', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts similarity index 65% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts index 2ad26472b699a..f5dfb61cd32ef 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts @@ -6,27 +6,29 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; -import type { QueryRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/query_rules_schema'; -import { queryRulesSchema } from '../../../../../common/detection_engine/schemas/request/query_rules_schema'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { deleteRules } from '../../rules/delete_rules'; -import { getIdError, transform } from './utils'; -import { buildSiemResponse } from '../utils'; -import { readRules } from '../../rules/read_rules'; -import { legacyMigrate } from '../../rules/utils'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { + QueryRuleByIds, + validateQueryRuleByIds, +} from '../../../../../../../common/detection_engine/rule_management'; -export const deleteRulesRoute = (router: SecuritySolutionPluginRouter) => { +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import { buildRouteValidation } 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'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { getIdError, transform } from '../../../utils/utils'; + +export const deleteRuleRoute = (router: SecuritySolutionPluginRouter) => { router.delete( { path: DETECTION_ENGINE_RULES_URL, validate: { - query: buildRouteValidation( - queryRulesSchema - ), + query: buildRouteValidation(QueryRuleByIds), }, options: { tags: ['access:securitySolution'], @@ -34,7 +36,7 @@ export const deleteRulesRoute = (router: SecuritySolutionPluginRouter) => { }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const validationErrors = queryRuleValidateTypeDependents(request.query); + const validationErrors = validateQueryRuleByIds(request.query); if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/export_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts similarity index 71% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/export_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts index 145ab6217d2ab..ec96f38f5f86e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/export_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts @@ -7,22 +7,21 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import type { Logger } from '@kbn/core/server'; -import type { - ExportRulesQuerySchemaDecoded, - ExportRulesSchemaDecoded, -} from '../../../../../common/detection_engine/schemas/request/export_rules_schema'; + +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import type { ExportRulesRequestQueryDecoded } from '../../../../../../../common/detection_engine/rule_management'; import { - exportRulesQuerySchema, - exportRulesSchema, -} from '../../../../../common/detection_engine/schemas/request/export_rules_schema'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import type { ConfigType } from '../../../../config'; -import { getNonPackagedRulesCount } from '../../rules/get_existing_prepackaged_rules'; -import { getExportByObjectIds } from '../../rules/get_export_by_object_ids'; -import { getExportAll } from '../../rules/get_export_all'; -import { buildSiemResponse } from '../utils'; + ExportRulesRequestBody, + ExportRulesRequestQuery, +} from '../../../../../../../common/detection_engine/rule_management'; + +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import type { ConfigType } from '../../../../../../config'; +import { getNonPackagedRulesCount } from '../../../logic/search/get_existing_prepackaged_rules'; +import { getExportByObjectIds } from '../../../logic/export/get_export_by_object_ids'; +import { getExportAll } from '../../../logic/export/get_export_all'; +import { buildSiemResponse } from '../../../../routes/utils'; export const exportRulesRoute = ( router: SecuritySolutionPluginRouter, @@ -33,12 +32,10 @@ export const exportRulesRoute = ( { path: `${DETECTION_ENGINE_RULES_URL}/_export`, validate: { - query: buildRouteValidation( - exportRulesQuerySchema - ), - body: buildRouteValidation( - exportRulesSchema + query: buildRouteValidation( + ExportRulesRequestQuery ), + body: buildRouteValidation(ExportRulesRequestBody), }, options: { tags: ['access:securitySolution'], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.test.ts similarity index 91% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.test.ts index b1f1ec8ead8ac..e34dff9733794 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.test.ts @@ -6,18 +6,18 @@ */ import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { DETECTION_ENGINE_RULES_URL_FIND } from '../../../../../common/constants'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { requestContextMock, requestMock, serverMock } from '../__mocks__'; +import { DETECTION_ENGINE_RULES_URL_FIND } from '../../../../../../../common/constants'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; +import { requestContextMock, requestMock, serverMock } from '../../../../routes/__mocks__'; import { getRuleMock, getFindRequest, getFindResultWithSingleHit, getEmptySavedObjectsResponse, -} from '../__mocks__/request_responses'; -import { findRulesRoute } from './find_rules_route'; +} from '../../../../routes/__mocks__/request_responses'; +import { findRulesRoute } from './route'; -describe('find_rules', () => { +describe('Find rules route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let logger: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts similarity index 70% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts index fa28a16e7bd4b..34117ca07f817 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts @@ -5,28 +5,32 @@ * 2.0. */ -import { transformError } from '@kbn/securitysolution-es-utils'; import type { Logger } from '@kbn/core/server'; -import { findRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/find_rules_type_dependents'; -import type { FindRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/find_rules_schema'; -import { findRulesSchema } from '../../../../../common/detection_engine/schemas/request/find_rules_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL_FIND } from '../../../../../common/constants'; -import { findRules } from '../../rules/find_rules'; -import { buildSiemResponse } from '../utils'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { transformFindAlerts } from './utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; + +import { DETECTION_ENGINE_RULES_URL_FIND } from '../../../../../../../common/constants'; +import type { FindRulesRequestQueryDecoded } from '../../../../../../../common/detection_engine/rule_management'; +import { + FindRulesRequestQuery, + validateFindRulesRequestQuery, +} from '../../../../../../../common/detection_engine/rule_management'; + +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import { findRules } from '../../../logic/search/find_rules'; +import { buildSiemResponse } from '../../../../routes/utils'; +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { transformFindAlerts } from '../../../utils/utils'; // eslint-disable-next-line no-restricted-imports -import { legacyGetBulkRuleActionsSavedObject } from '../../rule_actions/legacy_get_bulk_rule_actions_saved_object'; +import { legacyGetBulkRuleActionsSavedObject } from '../../../../rule_actions_legacy'; export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { router.get( { path: DETECTION_ENGINE_RULES_URL_FIND, validate: { - query: buildRouteValidation( - findRulesSchema + query: buildRouteValidation( + FindRulesRequestQuery ), }, options: { @@ -36,7 +40,7 @@ export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Log async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const validationErrors = findRuleValidateTypeDependents(request.query); + const validationErrors = validateFindRulesRequestQuery(request.query); if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts similarity index 95% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts index bf83471631a8c..3d466d2505074 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts @@ -5,7 +5,20 @@ * 2.0. */ -import { buildHapiStream } from '../__mocks__/utils'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; + +import { + getImportRulesWithIdSchemaMock, + ruleIdsToNdJsonString, + rulesToNdJsonString, +} from '../../../../../../../common/detection_engine/rule_management/mocks'; + +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; + +import type { requestMock } from '../../../../routes/__mocks__'; +import { createMockConfig, requestContextMock, serverMock } from '../../../../routes/__mocks__'; +import { buildHapiStream } from '../../../../routes/__mocks__/utils'; import { getImportRulesRequest, getImportRulesRequestOverwriteTrue, @@ -13,24 +26,15 @@ import { getRuleMock, getFindResultWithSingleHit, getBasicEmptySearchResponse, -} from '../__mocks__/request_responses'; -import type { requestMock } from '../__mocks__'; -import { createMockConfig, requestContextMock, serverMock } from '../__mocks__'; -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { importRulesRoute } from './import_rules_route'; -import * as createRulesAndExceptionsStreamFromNdJson from '../../rules/create_rules_stream_from_ndjson'; -import { - getImportRulesWithIdSchemaMock, - ruleIdsToNdJsonString, - rulesToNdJsonString, -} from '../../../../../common/detection_engine/schemas/request/import_rules_schema.mock'; -import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +} from '../../../../routes/__mocks__/request_responses'; + +import * as createRulesAndExceptionsStreamFromNdJson from '../../../logic/import/create_rules_stream_from_ndjson'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; +import { importRulesRoute } from './route'; -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); +jest.mock('../../../../../machine_learning/authz'); -describe('import_rules_route', () => { +describe('Import rules route', () => { let config: ReturnType; let server: ReturnType; let request: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts similarity index 79% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts index 958993b34c03b..e306caac12194 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts @@ -15,29 +15,29 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { ImportQuerySchemaDecoded } from '@kbn/securitysolution-io-ts-types'; import { importQuerySchema } from '@kbn/securitysolution-io-ts-types'; -import type { ImportRulesSchema as ImportRulesResponseSchema } from '../../../../../common/detection_engine/schemas/response/import_rules_schema'; -import { importRulesSchema as importRulesResponseSchema } from '../../../../../common/detection_engine/schemas/response/import_rules_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import type { ConfigType } from '../../../../config'; -import type { SetupPlugins } from '../../../../plugin'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import type { ImportRuleResponse, BulkError } from '../utils'; -import { isBulkError, isImportRegular, buildSiemResponse } from '../utils'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import type { RuleToImport } from '../../../../../../../common/detection_engine/rule_management'; +import { ImportRulesResponse } from '../../../../../../../common/detection_engine/rule_management'; + +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import type { ConfigType } from '../../../../../../config'; +import type { SetupPlugins } from '../../../../../../plugin'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import type { ImportRuleResponse, BulkError } from '../../../../routes/utils'; +import { isBulkError, isImportRegular, buildSiemResponse } from '../../../../routes/utils'; import { getTupleDuplicateErrorsAndUniqueRules, getInvalidConnectors, migrateLegacyActionsIds, -} from './utils'; -import { createRulesAndExceptionsStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { HapiReadableStream } from '../../rules/types'; -import type { RuleExceptionsPromiseFromStreams } from './utils/import_rules_utils'; -import { importRules as importRulesHelper } from './utils/import_rules_utils'; -import { getReferencedExceptionLists } from './utils/gather_referenced_exceptions'; -import { importRuleExceptions } from './utils/import_rule_exceptions'; -import type { ImportRulesSchema } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; +} from '../../../utils/utils'; +import { createRulesAndExceptionsStreamFromNdJson } from '../../../logic/import/create_rules_stream_from_ndjson'; +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import type { RuleExceptionsPromiseFromStreams } from '../../../logic/import/import_rules_utils'; +import { importRules as importRulesHelper } from '../../../logic/import/import_rules_utils'; +import { getReferencedExceptionLists } from '../../../logic/import/gather_referenced_exceptions'; +import { importRuleExceptions } from '../../../logic/import/import_rule_exceptions'; +import type { HapiReadableStream } from '../../../logic/import/hapi_readable_stream'; const CHUNK_PARSED_OBJECT_SIZE = 50; @@ -131,9 +131,7 @@ export const importRulesRoute = ( let parsedRules; let actionErrors: BulkError[] = []; - const actualRules = rules.filter( - (rule): rule is ImportRulesSchema => !(rule instanceof Error) - ); + const actualRules = rules.filter((rule): rule is RuleToImport => !(rule instanceof Error)); if (actualRules.some((rule) => rule.actions && rule.actions.length > 0)) { const [nonExistentActionErrors, uniqueParsedObjects] = await getInvalidConnectors( @@ -173,7 +171,7 @@ export const importRulesRoute = ( return false; } }); - const importRules: ImportRulesResponseSchema = { + const importRules: ImportRulesResponse = { success: errorsResp.length === 0, success_count: successes.length, rules_count: rules.length, @@ -183,7 +181,7 @@ export const importRulesRoute = ( exceptions_success_count: exceptionsSuccessCount, }; - const [validated, errors] = validate(importRules, importRulesResponseSchema); + const [validated, errors] = validate(importRules, ImportRulesResponse); if (errors != null) { return siemResponse.error({ statusCode: 500, body: errors }); } else { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts index 743fdefa7947f..07ae6a84df003 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts @@ -5,9 +5,13 @@ * 2.0. */ -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { getPatchRulesSchemaMock } from '../../../../../../../common/detection_engine/rule_management/mocks'; + +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; + +import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; import { getEmptyFindResult, getRuleMock, @@ -15,24 +19,25 @@ import { getFindResultWithSingleHit, nonRuleFindResult, typicalMlRulePayload, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { patchRulesRoute } from './patch_rules_route'; -import { getPatchRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/patch_rules_schema.mock'; -import { getMlRuleParams, getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { legacyMigrate } from '../../rules/utils'; +} from '../../../../routes/__mocks__/request_responses'; + +import { getMlRuleParams, getQueryRuleParams } from '../../../../rule_schema/mocks'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; + +import { patchRuleRoute } from './route'; -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); +jest.mock('../../../../../machine_learning/authz'); -jest.mock('../../rules/utils', () => { - const actual = jest.requireActual('../../rules/utils'); +jest.mock('../../../logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual('../../../logic/rule_actions/legacy_action_migration'); return { ...actual, legacyMigrate: jest.fn(), }; }); -describe('patch_rules', () => { +describe('Patch rule route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType; @@ -48,7 +53,7 @@ describe('patch_rules', () => { (legacyMigrate as jest.Mock).mockResolvedValue(getRuleMock(getQueryRuleParams())); - patchRulesRoute(server.router, ml); + patchRuleRoute(server.router, ml); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts similarity index 69% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts index aac618529c3bb..0e15e73b5e34d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts @@ -6,23 +6,29 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { patchRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/patch_rules_type_dependents'; -import { buildRouteValidationNonExact } from '../../../../utils/build_validation/route_validation'; -import { patchRulesSchema } from '../../../../../common/detection_engine/schemas/request/patch_rules_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import type { SetupPlugins } from '../../../../plugin'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; -import { patchRules } from '../../rules/patch_rules'; -import { buildSiemResponse } from '../utils'; -import { checkDefaultRuleExceptionListReferences } from './utils/check_for_default_rule_exception_list'; -import { getIdError } from './utils'; -import { transformValidate } from './validate'; -import { readRules } from '../../rules/read_rules'; -import { legacyMigrate } from '../../rules/utils'; -export const patchRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { + PatchRuleRequestBody, + validatePatchRuleRequestBody, +} from '../../../../../../../common/detection_engine/rule_management'; + +import { buildRouteValidationNonExact } from '../../../../../../utils/build_validation/route_validation'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import type { SetupPlugins } from '../../../../../../plugin'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../../machine_learning/validation'; +import { buildSiemResponse } from '../../../../routes/utils'; + +import { readRules } from '../../../logic/crud/read_rules'; +import { patchRules } from '../../../logic/crud/patch_rules'; +import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { getIdError } from '../../../utils/utils'; +import { transformValidate } from '../../../utils/validate'; + +export const patchRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { router.patch( { path: DETECTION_ENGINE_RULES_URL, @@ -30,7 +36,7 @@ export const patchRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupP // 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(patchRulesSchema), + body: buildRouteValidationNonExact(PatchRuleRequestBody), }, options: { tags: ['access:securitySolution'], @@ -38,7 +44,7 @@ export const patchRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupP }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const validationErrors = patchRuleValidateTypeDependents(request.body); + const validationErrors = validatePatchRuleRequestBody(request.body); if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.test.ts similarity index 92% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.test.ts index 368a2b50cd962..573a85cc97b16 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.test.ts @@ -7,8 +7,8 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { readRulesRoute } from './read_rules_route'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { readRuleRoute } from './route'; import { getEmptyFindResult, getReadRequest, @@ -17,11 +17,11 @@ import { nonRuleFindResult, getEmptySavedObjectsResponse, resolveRuleMock, -} from '../__mocks__/request_responses'; -import { requestMock, requestContextMock, serverMock } from '../__mocks__'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +} from '../../../../routes/__mocks__/request_responses'; +import { requestMock, requestContextMock, serverMock } from '../../../../routes/__mocks__'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; -describe('read_rules', () => { +describe('Read rule route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let logger: ReturnType; @@ -41,7 +41,7 @@ describe('read_rules', () => { }), id: myFakeId, }); - readRulesRoute(server.router, logger); + readRuleRoute(server.router, logger); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts similarity index 65% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts index b19e94b6f0484..eaa58bf00a1be 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts @@ -5,29 +5,30 @@ * 2.0. */ -import { transformError } from '@kbn/securitysolution-es-utils'; import type { Logger } from '@kbn/core/server'; -import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; -import type { QueryRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/query_rules_schema'; -import { queryRulesSchema } from '../../../../../common/detection_engine/schemas/request/query_rules_schema'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { getIdError, transform } from './utils'; -import { buildSiemResponse } from '../utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; + +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { + QueryRuleByIds, + validateQueryRuleByIds, +} from '../../../../../../../common/detection_engine/rule_management'; + +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildSiemResponse } from '../../../../routes/utils'; +import { getIdError, transform } from '../../../utils/utils'; -import { readRules } from '../../rules/read_rules'; +import { readRules } from '../../../logic/crud/read_rules'; // eslint-disable-next-line no-restricted-imports -import { legacyGetRuleActionsSavedObject } from '../../rule_actions/legacy_get_rule_actions_saved_object'; +import { legacyGetRuleActionsSavedObject } from '../../../../rule_actions_legacy'; -export const readRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { +export const readRuleRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { router.get( { path: DETECTION_ENGINE_RULES_URL, validate: { - query: buildRouteValidation( - queryRulesSchema - ), + query: buildRouteValidation(QueryRuleByIds), }, options: { tags: ['access:securitySolution'], @@ -35,7 +36,7 @@ export const readRulesRoute = (router: SecuritySolutionPluginRouter, logger: Log }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const validationErrors = queryRuleValidateTypeDependents(request.query); + const validationErrors = validateQueryRuleByIds(request.query); if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts similarity index 86% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts index ad7a7d1fe5365..4502e08fb950d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../machine_learning/mocks'; -import { buildMlAuthz } from '../../../machine_learning/authz'; +import { mlServicesMock } from '../../../../../machine_learning/mocks'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { getEmptyFindResult, getRuleMock, @@ -14,25 +14,26 @@ import { getFindResultWithSingleHit, nonRuleFindResult, typicalMlRulePayload, -} from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { updateRulesRoute } from './update_rules_route'; -import { getUpdateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { legacyMigrate } from '../../rules/utils'; - -jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); - -jest.mock('../../rules/utils', () => { - const actual = jest.requireActual('../../rules/utils'); +} from '../../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { updateRuleRoute } from './route'; +import { getUpdateRulesSchemaMock } from '../../../../../../../common/detection_engine/rule_schema/mocks'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; + +jest.mock('../../../../../machine_learning/authz'); + +jest.mock('../../../logic/rule_actions/legacy_action_migration', () => { + const actual = jest.requireActual('../../../logic/rule_actions/legacy_action_migration'); return { ...actual, legacyMigrate: jest.fn(), }; }); -describe('update_rules', () => { +describe('Update rule route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType; @@ -49,7 +50,7 @@ describe('update_rules', () => { (legacyMigrate as jest.Mock).mockResolvedValue(getRuleMock(getQueryRuleParams())); - updateRulesRoute(server.router, ml); + updateRuleRoute(server.router, ml); }); describe('status codes', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts similarity index 64% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts index 8fa4f372fd597..8d24dd03d9d01 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts @@ -6,29 +6,31 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { updateRulesSchema } from '../../../../../common/detection_engine/schemas/request'; -import { updateRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/update_rules_type_dependents'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import type { SetupPlugins } from '../../../../plugin'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; -import { buildSiemResponse } from '../utils'; -import { getIdError } from './utils'; -import { transformValidate } from './validate'; -import { updateRules } from '../../rules/update_rules'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { legacyMigrate } from '../../rules/utils'; -import { readRules } from '../../rules/read_rules'; -import { checkDefaultRuleExceptionListReferences } from './utils/check_for_default_rule_exception_list'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; +import { validateUpdateRuleProps } from '../../../../../../../common/detection_engine/rule_management'; +import { RuleUpdateProps } from '../../../../../../../common/detection_engine/rule_schema'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import type { SetupPlugins } from '../../../../../../plugin'; +import { buildMlAuthz } from '../../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../../machine_learning/validation'; +import { buildSiemResponse } from '../../../../routes/utils'; -export const updateRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { +import { getIdError } from '../../../utils/utils'; +import { transformValidate } from '../../../utils/validate'; +import { updateRules } from '../../../logic/crud/update_rules'; +import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../../../logic/rule_actions/legacy_action_migration'; +import { readRules } from '../../../logic/crud/read_rules'; +import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list'; + +export const updateRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { router.put( { path: DETECTION_ENGINE_RULES_URL, validate: { - body: buildRouteValidation(updateRulesSchema), + body: buildRouteValidation(RuleUpdateProps), }, options: { tags: ['access:securitySolution'], @@ -36,7 +38,7 @@ export const updateRulesRoute = (router: SecuritySolutionPluginRouter, ml: Setup }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const validationErrors = updateRuleValidateTypeDependents(request.body); + const validationErrors = validateUpdateRuleProps(request.body); if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/tags/read_tags.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/detection_engine/tags/read_tags.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts index 2154e672e0089..ba9b00c01e3cf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/tags/read_tags.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts @@ -6,9 +6,12 @@ */ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { getRuleMock, getFindResultWithMultiHits } from '../routes/__mocks__/request_responses'; +import { + getRuleMock, + getFindResultWithMultiHits, +} from '../../../../routes/__mocks__/request_responses'; +import { getQueryRuleParams } from '../../../../rule_schema/mocks'; import { readTags, convertTagsToSet, convertToTags, isTags } from './read_tags'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; describe('read_tags', () => { afterEach(() => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/tags/read_tags.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts similarity index 96% rename from x-pack/plugins/security_solution/server/lib/detection_engine/tags/read_tags.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts index 72a886cd3e3a1..8819d95f366d8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/tags/read_tags.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts @@ -7,7 +7,7 @@ import { has } from 'lodash/fp'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { findRules } from '../rules/find_rules'; +import { findRules } from '../../../logic/search/find_rules'; export interface TagType { id: string; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/tags/read_tags_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/route.ts similarity index 81% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/tags/read_tags_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/route.ts index 508495cdeb9ef..c7cca7e443bd3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/tags/read_tags_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/route.ts @@ -6,11 +6,11 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_TAGS_URL } from '../../../../../common/constants'; -import { buildSiemResponse } from '../utils'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import { DETECTION_ENGINE_TAGS_URL } from '../../../../../../../common/constants'; +import { buildSiemResponse } from '../../../../routes/utils'; -import { readTags } from '../../tags/read_tags'; +import { readTags } from './read_tags'; export const readTagsRoute = (router: SecuritySolutionPluginRouter) => { router.get( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/index.ts new file mode 100644 index 0000000000000..f2a694c8df046 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export * from './api/register_routes'; + +// TODO: https://github.com/elastic/kibana/pull/142950 +// eslint-disable-next-line no-restricted-imports +export { legacyMigrate } from './logic/rule_actions/legacy_action_migration'; + +// TODO: https://github.com/elastic/kibana/pull/142950 +// TODO: Revisit and consider moving to the rule_schema subdomain +export { + commonParamsCamelToSnake, + typeSpecificCamelToSnake, + convertCreateAPIToInternalSchema, +} from './normalization/rule_converters'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts similarity index 99% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts index 29cc718379c96..8637236f654d2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts @@ -7,7 +7,7 @@ import uuid from 'uuid'; import type { SanitizedRule } from '@kbn/alerting-plugin/common'; -import type { RuleParams } from '../schemas/rule_schemas'; +import type { RuleParams } from '../../../rule_schema'; import { duplicateRule } from './duplicate_rule'; jest.mock('uuid', () => ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.ts similarity index 91% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.ts index de077ef91b168..5f15a2ed81d1f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.ts @@ -6,13 +6,12 @@ */ import uuid from 'uuid'; - import { i18n } from '@kbn/i18n'; import { ruleTypeMappings } from '@kbn/securitysolution-rules'; - import type { SanitizedRule } from '@kbn/alerting-plugin/common'; -import { SERVER_APP_ID } from '../../../../common/constants'; -import type { InternalRuleCreate, RuleParams } from '../schemas/rule_schemas'; + +import { SERVER_APP_ID } from '../../../../../../common/constants'; +import type { InternalRuleCreate, RuleParams } from '../../../rule_schema'; const DUPLICATE_TITLE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.cloneRule.duplicateTitle', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.test.ts similarity index 91% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.test.ts index 8627a5efeca2e..e48f0b4cbd3c4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; - +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { bulkEditActionToRulesClientOperation } from './action_to_rules_client_operation'; describe('bulkEditActionToRulesClientOperation', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.ts index 550f624ed9351..f767a5c246056 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.ts @@ -7,11 +7,11 @@ import type { BulkEditOperation } from '@kbn/alerting-plugin/server'; -import type { BulkActionEditForRuleAttributes } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { assertUnreachable } from '../../../../../common/utility_types'; +import type { BulkActionEditForRuleAttributes } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { assertUnreachable } from '../../../../../../common/utility_types'; -import { transformToAlertThrottle, transformToNotifyWhen } from '../utils'; +import { transformToAlertThrottle, transformToNotifyWhen } from '../../normalization/rule_actions'; const getThrottleOperation = (throttle: string) => ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/bulk_edit_rules.ts similarity index 80% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/bulk_edit_rules.ts index 75c7db48333c3..85610fcddb436 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/bulk_edit_rules.ts @@ -7,24 +7,28 @@ import type { BulkEditError, RulesClient } from '@kbn/alerting-plugin/server'; import pMap from 'p-map'; -import type { - BulkActionEditPayload, - BulkActionEditPayloadRuleActions, -} from '../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { enrichFilterWithRuleTypeMapping } from './enrich_filter_with_rule_type_mappings'; -import type { MlAuthz } from '../../machine_learning/authz'; -import { ruleParamsModifier } from './bulk_actions/rule_params_modifier'; -import { splitBulkEditActions } from './bulk_actions/split_bulk_edit_actions'; -import { validateBulkEditRule } from './bulk_actions/validations'; -import { bulkEditActionToRulesClientOperation } from './bulk_actions/action_to_rules_client_operation'; -import type { RuleAlertType } from './types'; import { MAX_RULES_TO_UPDATE_IN_PARALLEL, NOTIFICATION_THROTTLE_NO_ACTIONS, -} from '../../../../common/constants'; -import { readRules } from './read_rules'; +} from '../../../../../../common/constants'; + +import type { + BulkActionEditPayload, + BulkActionEditPayloadRuleActions, +} from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; + +import type { MlAuthz } from '../../../../machine_learning/authz'; + +import { enrichFilterWithRuleTypeMapping } from '../search/enrich_filter_with_rule_type_mappings'; +import { readRules } from '../crud/read_rules'; +import type { RuleAlertType } from '../../../rule_schema'; + +import { ruleParamsModifier } from './rule_params_modifier'; +import { splitBulkEditActions } from './split_bulk_edit_actions'; +import { validateBulkEditRule } from './validations'; +import { bulkEditActionToRulesClientOperation } from './action_to_rules_client_operation'; export interface BulkEditRulesArguments { rulesClient: RulesClient; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/dry_run.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/dry_run.ts similarity index 93% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/dry_run.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/dry_run.ts index 608324e5bb280..fa05b1fc822d2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/dry_run.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/dry_run.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { BulkActionsDryRunErrCode } from '../../../../../common/constants'; +import type { BulkActionsDryRunErrCode } from '../../../../../../common/constants'; /** * Error instance that has properties: errorCode & statusCode to use within run_dry diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.test.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.test.ts index 5c194cc6c4614..b7763f20eec9c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.test.ts @@ -6,8 +6,8 @@ */ import { addItemsToArray, deleteItemsFromArray, ruleParamsModifier } from './rule_params_modifier'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { RuleAlertType } from '../types'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { RuleAlertType } from '../../../rule_schema'; describe('addItemsToArray', () => { test('should add single item to array', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.ts similarity index 92% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.ts index 6831668258554..9f5f252b9fd86 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.ts @@ -9,10 +9,10 @@ import moment from 'moment'; import { parseInterval } from '@kbn/data-plugin/common/search/aggs/utils/date_interval_utils'; -import type { RuleAlertType } from '../types'; -import type { BulkActionEditForRuleParams } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { invariant } from '../../../../../common/utils/invariant'; +import type { RuleAlertType } from '../../../rule_schema'; +import type { BulkActionEditForRuleParams } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { invariant } from '../../../../../../common/utils/invariant'; export const addItemsToArray = (arr: T[], items: T[]): T[] => Array.from(new Set([...arr, ...items])); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.test.ts similarity index 87% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.test.ts index 46205c060be78..33f1e0e4ad15e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { splitBulkEditActions } from './split_bulk_edit_actions'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.ts similarity index 85% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.ts index c752ca6653ad6..b6441d46c5ebd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import type { BulkActionEditPayload, BulkActionEditForRuleAttributes, BulkActionEditForRuleParams, -} from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +} from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; /** * Split bulk edit actions in 2 chunks: actions applied to params and diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/utils.ts similarity index 84% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/utils.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/utils.ts index 91cfe9544d550..993750cfc0964 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/utils.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; /** * helper utility that defines whether bulk edit action is related to index patterns, i.e. one of: diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts similarity index 84% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts index 5252fd1982ff3..ce9b084679a5b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts @@ -6,16 +6,16 @@ */ import type { Type as RuleType } from '@kbn/securitysolution-io-ts-alerting-types'; -import { invariant } from '../../../../../common/utils/invariant'; -import { isMlRule } from '../../../../../common/machine_learning/helpers'; -import { BulkActionsDryRunErrCode } from '../../../../../common/constants'; -import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { RuleAlertType } from '../types'; +import { invariant } from '../../../../../../common/utils/invariant'; +import { isMlRule } from '../../../../../../common/machine_learning/helpers'; +import { BulkActionsDryRunErrCode } from '../../../../../../common/constants'; +import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import { BulkActionEditType } from '../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; +import type { RuleAlertType } from '../../../rule_schema'; import { isIndexPatternsBulkEditAction } from './utils'; import { throwDryRunError } from './dry_run'; -import type { MlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; +import type { MlAuthz } from '../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../machine_learning/validation'; interface BulkActionsValidationArgs { rule: RuleAlertType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.test.ts index fb62434563183..8b59effd9c910 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.test.ts @@ -7,11 +7,11 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; import { createRules } from './create_rules'; -import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../common/constants'; +import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../../common/constants'; import { getCreateMachineLearningRulesSchemaMock, getCreateThreatMatchRulesSchemaMock, -} from '../../../../common/detection_engine/schemas/request/rule_schemas.mock'; +} from '../../../../../../common/detection_engine/rule_schema/mocks'; describe('createRules', () => { it('calls the rulesClient with legacy ML params', async () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts similarity index 60% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts index 5405fed52b79b..f621542fe433f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts @@ -6,10 +6,20 @@ */ import type { SanitizedRule } from '@kbn/alerting-plugin/common'; -import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../common/constants'; -import type { CreateRulesOptions } from './types'; -import { convertCreateAPIToInternalSchema } from '../schemas/rule_converters'; -import type { RuleParams } from '../schemas/rule_schemas'; +import type { RulesClient } from '@kbn/alerting-plugin/server'; + +import type { RuleCreateProps } from '../../../../../../common/detection_engine/rule_schema'; +import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../common/constants'; +import { convertCreateAPIToInternalSchema } from '../../normalization/rule_converters'; +import type { RuleParams } from '../../../rule_schema'; + +export interface CreateRulesOptions { + rulesClient: RulesClient; + params: T; + id?: string; + immutable?: boolean; + defaultEnabled?: boolean; +} export const createRules = async ({ rulesClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/delete_rules.test.ts similarity index 89% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/delete_rules.test.ts index 0c7edae7022c7..e7176b8d51af0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/delete_rules.test.ts @@ -6,9 +6,9 @@ */ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { ruleExecutionLogMock } from '../rule_monitoring/mocks'; +import { ruleExecutionLogMock } from '../../../rule_monitoring/mocks'; +import type { DeleteRuleOptions } from './delete_rules'; import { deleteRules } from './delete_rules'; -import type { DeleteRuleOptions } from './types'; describe('deleteRules', () => { let rulesClient: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/delete_rules.ts similarity index 55% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/delete_rules.ts index e0ab62df17c37..a1190d8827c0d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/delete_rules.ts @@ -5,7 +5,15 @@ * 2.0. */ -import type { DeleteRuleOptions } from './types'; +import type { RulesClient } from '@kbn/alerting-plugin/server'; +import type { RuleObjectId } from '../../../../../../common/detection_engine/rule_schema'; +import type { IRuleExecutionLogForRoutes } from '../../../rule_monitoring'; + +export interface DeleteRuleOptions { + ruleId: RuleObjectId; + rulesClient: RulesClient; + ruleExecutionLog: IRuleExecutionLogForRoutes; +} export const deleteRules = async ({ ruleId, rulesClient, ruleExecutionLog }: DeleteRuleOptions) => { await rulesClient.delete({ id: ruleId }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.test.ts similarity index 96% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.test.ts index e99f7f85df156..cfb051273255a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.test.ts @@ -8,12 +8,12 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/rules_client.mock'; import { patchRules } from './patch_rules'; -import { getRuleMock } from '../routes/__mocks__/request_responses'; -import { getMlRuleParams, getQueryRuleParams } from '../schemas/rule_schemas.mock'; +import { getRuleMock } from '../../../routes/__mocks__/request_responses'; +import { getMlRuleParams, getQueryRuleParams } from '../../../rule_schema/mocks'; import { getCreateMachineLearningRulesSchemaMock, getCreateRulesSchemaMock, -} from '../../../../common/detection_engine/schemas/request/rule_schemas.mock'; +} from '../../../../../../common/detection_engine/rule_schema/mocks'; describe('patchRules', () => { it('should call rulesClient.disable if the rule was enabled and enabled is false', async () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.ts similarity index 70% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.ts index 0a8342ae265a0..656366ec9f92b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.ts @@ -5,11 +5,18 @@ * 2.0. */ -import type { PartialRule } from '@kbn/alerting-plugin/server'; -import type { RuleParams } from '../schemas/rule_schemas'; -import type { PatchRulesOptions } from './types'; -import { maybeMute } from './utils'; -import { convertPatchAPIToInternalSchema } from '../schemas/rule_converters'; +import type { PartialRule, RulesClient } from '@kbn/alerting-plugin/server'; + +import type { PatchRuleRequestBody } from '../../../../../../common/detection_engine/rule_management'; +import type { RuleAlertType, RuleParams } from '../../../rule_schema'; +import { convertPatchAPIToInternalSchema } from '../../normalization/rule_converters'; +import { maybeMute } from '../rule_actions/muting'; + +export interface PatchRulesOptions { + rulesClient: RulesClient; + nextParams: PatchRuleRequestBody; + existingRule: RuleAlertType | null | undefined; +} export const patchRules = async ({ rulesClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.test.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.test.ts index dd0d1ff7090c7..fa6ccba511833 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.test.ts @@ -11,8 +11,8 @@ import { resolveRuleMock, getRuleMock, getFindResultWithSingleHit, -} from '../routes/__mocks__/request_responses'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; +} from '../../../routes/__mocks__/request_responses'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; export class TestError extends Error { constructor() { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.ts similarity index 80% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.ts index 1e853084a3635..76969b31aab66 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.ts @@ -6,11 +6,22 @@ */ import type { ResolvedSanitizedRule, SanitizedRule } from '@kbn/alerting-plugin/common'; -import { withSecuritySpan } from '../../../utils/with_security_span'; -import type { RuleParams } from '../schemas/rule_schemas'; -import { findRules } from './find_rules'; -import type { ReadRuleOptions } from './types'; -import { isAlertType } from './types'; +import type { RulesClient } from '@kbn/alerting-plugin/server'; + +import type { + RuleObjectId, + RuleSignatureId, +} from '../../../../../../common/detection_engine/rule_schema'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import type { RuleParams } from '../../../rule_schema'; +import { isAlertType } from '../../../rule_schema'; +import { findRules } from '../search/find_rules'; + +export interface ReadRuleOptions { + rulesClient: RulesClient; + id: RuleObjectId | undefined; + ruleId: RuleSignatureId | undefined; +} /** * This reads the rules through a cascade try of what is fastest to what is slowest. diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.mock.ts similarity index 78% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.mock.ts index bdaf757cb086e..3e3da2e6f5530 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.mock.ts @@ -9,9 +9,9 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; import { getUpdateMachineLearningSchemaMock, getUpdateRulesSchemaMock, -} from '../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { getRuleMock } from '../routes/__mocks__/request_responses'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; +} from '../../../../../../common/detection_engine/rule_schema/mocks'; +import { getRuleMock } from '../../../routes/__mocks__/request_responses'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; export const getUpdateRulesOptionsMock = () => ({ rulesClient: rulesClientMock.create(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.test.ts similarity index 93% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.test.ts index 453a305d2e1ec..6abba4dba0ab9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.test.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { getRuleMock, resolveRuleMock } from '../routes/__mocks__/request_responses'; +import type { RulesClientMock } from '@kbn/alerting-plugin/server/rules_client.mock'; +import { getRuleMock, resolveRuleMock } from '../../../routes/__mocks__/request_responses'; +import { getMlRuleParams, getQueryRuleParams } from '../../../rule_schema/mocks'; import { updateRules } from './update_rules'; import { getUpdateRulesOptionsMock, getUpdateMlRulesOptionsMock } from './update_rules.mock'; -import type { RulesClientMock } from '@kbn/alerting-plugin/server/rules_client.mock'; -import { getMlRuleParams, getQueryRuleParams } from '../schemas/rule_schemas.mock'; // Failing with rule registry enabled describe('updateRules', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.ts similarity index 80% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.ts index c75e7534417e9..625204efbe4f6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.ts @@ -6,14 +6,21 @@ */ /* eslint-disable complexity */ -import type { PartialRule } from '@kbn/alerting-plugin/server'; -import { DEFAULT_MAX_SIGNALS } from '../../../../common/constants'; -import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; +import type { PartialRule, RulesClient } from '@kbn/alerting-plugin/server'; +import { DEFAULT_MAX_SIGNALS } from '../../../../../../common/constants'; +import type { RuleUpdateProps } from '../../../../../../common/detection_engine/rule_schema'; +import { transformRuleToAlertAction } from '../../../../../../common/detection_engine/transform_actions'; -import type { UpdateRulesOptions } from './types'; -import { typeSpecificSnakeToCamel } from '../schemas/rule_converters'; -import type { InternalRuleUpdate, RuleParams } from '../schemas/rule_schemas'; -import { maybeMute, transformToAlertThrottle, transformToNotifyWhen } from './utils'; +import type { InternalRuleUpdate, RuleParams, RuleAlertType } from '../../../rule_schema'; +import { transformToAlertThrottle, transformToNotifyWhen } from '../../normalization/rule_actions'; +import { typeSpecificSnakeToCamel } from '../../normalization/rule_converters'; +import { maybeMute } from '../rule_actions/muting'; + +export interface UpdateRulesOptions { + rulesClient: RulesClient; + existingRule: RuleAlertType | null | undefined; + ruleUpdate: RuleUpdateProps; +} export const updateRules = async ({ rulesClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_for_default_rule_exception_list.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/exceptions/check_for_default_rule_exception_list.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_for_default_rule_exception_list.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/exceptions/check_for_default_rule_exception_list.test.ts index b95007d834b09..222badf14dfa6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_for_default_rule_exception_list.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/exceptions/check_for_default_rule_exception_list.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { checkDefaultRuleExceptionListReferences } from './check_for_default_rule_exception_list'; import type { ListArray } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { checkDefaultRuleExceptionListReferences } from './check_for_default_rule_exception_list'; describe('checkDefaultRuleExceptionListReferences', () => { it('returns undefined if "exceptionLists" is undefined', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_for_default_rule_exception_list.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/exceptions/check_for_default_rule_exception_list.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_for_default_rule_exception_list.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/exceptions/check_for_default_rule_exception_list.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts index 25818c30f387b..b7395236a2152 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts @@ -5,25 +5,25 @@ * 2.0. */ -import type { FindHit } from '../routes/__mocks__/request_responses'; +import type { FindHit } from '../../../routes/__mocks__/request_responses'; import { getRuleMock, getFindResultWithSingleHit, getEmptySavedObjectsResponse, -} from '../routes/__mocks__/request_responses'; +} from '../../../routes/__mocks__/request_responses'; import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; import { getExportAll } from './get_export_all'; -import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; -import { getThreatMock } from '../../../../common/detection_engine/schemas/types/threat.mock'; +import { getListArrayMock } from '../../../../../../common/detection_engine/schemas/types/lists.mock'; +import { getThreatMock } from '../../../../../../common/detection_engine/schemas/types/threat.mock'; import { getOutputDetailsSampleWithExceptions, getSampleDetailsAsNdjson, -} from '../../../../common/detection_engine/schemas/response/export_rules_details_schema.mock'; +} from '../../../../../../common/detection_engine/rule_management/mocks'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; import { getExceptionListClientMock } from '@kbn/lists-plugin/server/services/exception_lists/exception_list_client.mock'; import type { loggingSystemMock } from '@kbn/core/server/mocks'; -import { requestContextMock } from '../routes/__mocks__/request_context'; +import { requestContextMock } from '../../../routes/__mocks__/request_context'; const exceptionsClient = getExceptionListClientMock(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts similarity index 87% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts index 60d75fdd64709..058559de7db59 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts @@ -10,13 +10,13 @@ import { transformDataToNdjson } from '@kbn/securitysolution-utils'; import type { Logger } from '@kbn/core/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; import type { RulesClient, RuleExecutorServices } from '@kbn/alerting-plugin/server'; -import { getNonPackagedRules } from './get_existing_prepackaged_rules'; +import { getNonPackagedRules } from '../search/get_existing_prepackaged_rules'; import { getExportDetailsNdjson } from './get_export_details_ndjson'; -import { transformAlertsToRules } from '../routes/rules/utils'; +import { transformAlertsToRules } from '../../utils/utils'; import { getRuleExceptionsForExport } from './get_export_rule_exceptions'; // eslint-disable-next-line no-restricted-imports -import { legacyGetBulkRuleActionsSavedObject } from '../rule_actions/legacy_get_bulk_rule_actions_saved_object'; +import { legacyGetBulkRuleActionsSavedObject } from '../../../rule_actions_legacy'; export const getExportAll = async ( rulesClient: RulesClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts index b890315bf1977..0242f17509a99 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts @@ -7,25 +7,25 @@ import type { RulesErrors } from './get_export_by_object_ids'; import { getExportByObjectIds, getRulesFromObjects } from './get_export_by_object_ids'; -import type { FindHit } from '../routes/__mocks__/request_responses'; +import type { FindHit } from '../../../routes/__mocks__/request_responses'; import { getRuleMock, getFindResultWithSingleHit, getEmptySavedObjectsResponse, -} from '../routes/__mocks__/request_responses'; +} from '../../../routes/__mocks__/request_responses'; import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; -import { getThreatMock } from '../../../../common/detection_engine/schemas/types/threat.mock'; +import { getListArrayMock } from '../../../../../../common/detection_engine/schemas/types/lists.mock'; +import { getThreatMock } from '../../../../../../common/detection_engine/schemas/types/threat.mock'; import { getSampleDetailsAsNdjson, getOutputDetailsSampleWithExceptions, -} from '../../../../common/detection_engine/schemas/response/export_rules_details_schema.mock'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; +} from '../../../../../../common/detection_engine/rule_management/mocks'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; import { getExceptionListClientMock } from '@kbn/lists-plugin/server/services/exception_lists/exception_list_client.mock'; const exceptionsClient = getExceptionListClientMock(); import type { loggingSystemMock } from '@kbn/core/server/mocks'; -import { requestContextMock } from '../routes/__mocks__/request_context'; +import { requestContextMock } from '../../../routes/__mocks__/request_context'; describe('get_export_by_object_ids', () => { let logger: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/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 similarity index 91% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts index e044c8fdfd1ca..67da643d503e4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/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 @@ -14,18 +14,18 @@ import type { RulesClient, RuleExecutorServices } from '@kbn/alerting-plugin/ser import { getExportDetailsNdjson } from './get_export_details_ndjson'; -import { isAlertType } from './types'; -import { findRules } from './find_rules'; +import { isAlertType } from '../../../rule_schema'; +import { findRules } from '../search/find_rules'; import { getRuleExceptionsForExport } from './get_export_rule_exceptions'; // eslint-disable-next-line no-restricted-imports -import { legacyGetBulkRuleActionsSavedObject } from '../rule_actions/legacy_get_bulk_rule_actions_saved_object'; -import { internalRuleToAPIResponse } from '../schemas/rule_converters'; -import type { FullResponseSchema } from '../../../../common/detection_engine/schemas/request'; +import { legacyGetBulkRuleActionsSavedObject } from '../../../rule_actions_legacy'; +import { internalRuleToAPIResponse } from '../../normalization/rule_converters'; +import type { RuleResponse } from '../../../../../../common/detection_engine/rule_schema'; interface ExportSuccessRule { statusCode: 200; - rule: FullResponseSchema; + rule: RuleResponse; } interface ExportFailedRule { @@ -36,7 +36,7 @@ interface ExportFailedRule { export interface RulesErrors { exportedCount: number; missingRules: Array<{ rule_id: string }>; - rules: FullResponseSchema[]; + rules: RuleResponse[]; } export const getExportByObjectIds = async ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_details_ndjson.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_details_ndjson.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.test.ts index e58d1b5088fce..b380fc804233b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_details_ndjson.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.test.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { getRulesSchemaMock } from '../../../../../../common/detection_engine/rule_schema/mocks'; import { getExportDetailsNdjson } from './get_export_details_ndjson'; -import { getRulesSchemaMock } from '../../../../common/detection_engine/schemas/response/rules_schema.mocks'; describe('getExportDetailsNdjson', () => { test('it ends with a new line character', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_details_ndjson.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.ts similarity index 79% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_details_ndjson.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.ts index 204d78f5fe7d2..465c4b53b1e51 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_details_ndjson.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.ts @@ -6,12 +6,11 @@ */ import type { ExportExceptionDetails } from '@kbn/securitysolution-io-ts-list-types'; -import type { FullResponseSchema } from '../../../../common/detection_engine/schemas/request'; - -import type { ExportRulesDetails } from '../../../../common/detection_engine/schemas/response/export_rules_details_schema'; +import type { ExportRulesDetails } from '../../../../../../common/detection_engine/rule_management'; +import type { RuleResponse } from '../../../../../../common/detection_engine/rule_schema'; export const getExportDetailsNdjson = ( - rules: FullResponseSchema[], + rules: RuleResponse[], missingRules: Array<{ rule_id: string }> = [], exceptionDetails?: ExportExceptionDetails ): string => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_rule_exceptions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_exceptions.test.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_rule_exceptions.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_exceptions.test.ts index 79507a73147a9..07360aeda2986 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_rule_exceptions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_exceptions.test.ts @@ -11,12 +11,12 @@ import { getExceptionListClientMock } from '@kbn/lists-plugin/server/services/ex import { getDetectionsExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; +import { getListMock } from '../../../../../../common/detection_engine/schemas/types/lists.mock'; import { getRuleExceptionsForExport, getExportableExceptions, getDefaultExportDetails, } from './get_export_rule_exceptions'; -import { getListMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; describe('get_export_rule_exceptions', () => { describe('getRuleExceptionsForExport', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_rule_exceptions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_exceptions.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_rule_exceptions.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_exceptions.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_rule_exception_references.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/check_rule_exception_references.test.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_rule_exception_references.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/check_rule_exception_references.test.ts index d1fb4881ae9a8..fdee52eac1a24 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_rule_exception_references.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/check_rule_exception_references.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { getImportRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/request/import_rules_schema.mock'; -import { checkRuleExceptionReferences } from './check_rule_exception_references'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; +import { getImportRulesSchemaMock } from '../../../../../../common/detection_engine/rule_management/mocks'; +import { checkRuleExceptionReferences } from './check_rule_exception_references'; describe('checkRuleExceptionReferences', () => { it('returns empty array if rule has no exception list references', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_rule_exception_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/check_rule_exception_references.ts similarity index 89% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_rule_exception_references.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/check_rule_exception_references.ts index a92d7e4ec1723..23494c3fc23dd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/check_rule_exception_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/check_rule_exception_references.ts @@ -6,9 +6,9 @@ */ import type { ListArray, ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; -import type { ImportRulesSchema } from '../../../../../../common/detection_engine/schemas/request/import_rules_schema'; -import type { BulkError } from '../../utils'; -import { createBulkErrorObject } from '../../utils'; +import type { RuleToImport } from '../../../../../../common/detection_engine/rule_management'; +import type { BulkError } from '../../../routes/utils'; +import { createBulkErrorObject } from '../../../routes/utils'; /** * Helper to check if all the exception lists referenced on a @@ -25,7 +25,7 @@ export const checkRuleExceptionReferences = ({ rule, existingLists, }: { - rule: ImportRulesSchema; + rule: RuleToImport; existingLists: Record; }): [BulkError[], ListArray] => { let ruleExceptions: ListArray = []; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.test.ts similarity index 95% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.test.ts index 4b3483229af89..47a4a4832b034 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.test.ts @@ -9,14 +9,15 @@ import { Readable } from 'stream'; import { createPromiseFromStreams } from '@kbn/utils'; import { createRulesAndExceptionsStreamFromNdJson } from './create_rules_stream_from_ndjson'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import type { ImportRulesSchema } from '../../../../common/detection_engine/schemas/request/import_rules_schema'; + +import type { RuleToImport } from '../../../../../../common/detection_engine/rule_management'; import { getOutputDetailsSample, getSampleDetailsAsNdjson, -} from '../../../../common/detection_engine/schemas/response/export_rules_details_schema.mock'; -import type { RuleExceptionsPromiseFromStreams } from '../routes/rules/utils/import_rules_utils'; +} from '../../../../../../common/detection_engine/rule_management/mocks'; +import type { RuleExceptionsPromiseFromStreams } from './import_rules_utils'; -export const getOutputSample = (): Partial => ({ +export const getOutputSample = (): Partial => ({ rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -30,7 +31,7 @@ export const getOutputSample = (): Partial => ({ type: 'query', }); -export const getSampleAsNdjson = (sample: Partial): string => { +export const getSampleAsNdjson = (sample: Partial): string => { return `${JSON.stringify(sample)}\n`; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.ts similarity index 74% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.ts index 486b8b531a3fd..e325496225d9f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.ts @@ -5,10 +5,11 @@ * 2.0. */ -import type { Transform } from 'stream'; -import type * as t from 'io-ts'; +import { has } from 'lodash/fp'; import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; +import type * as t from 'io-ts'; +import type { Transform } from 'stream'; import { createSplitStream, createMapStream, @@ -16,21 +17,22 @@ import { createReduceStream, } from '@kbn/utils'; -import { exactCheck, formatErrors } from '@kbn/securitysolution-io-ts-utils'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; +import { exactCheck, formatErrors } from '@kbn/securitysolution-io-ts-utils'; import type { ImportExceptionListItemSchema, ImportExceptionsListSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { has } from 'lodash/fp'; -import { importRuleValidateTypeDependents } from '../../../../common/detection_engine/schemas/request/import_rules_type_dependents'; -import type { ImportRulesSchema } from '../../../../common/detection_engine/schemas/request/import_rules_schema'; -import { importRulesSchema } from '../../../../common/detection_engine/schemas/request/import_rules_schema'; + +import { + RuleToImport, + validateRuleToImport, +} from '../../../../../../common/detection_engine/rule_management'; import { parseNdjsonStrings, createRulesLimitStream, filterExportedCounts, -} from '../../../utils/read_stream/create_stream_from_ndjson'; +} from '../../../../../utils/read_stream/create_stream_from_ndjson'; /** * Validates exception lists and items schemas @@ -38,25 +40,23 @@ import { export const validateRulesStream = (): Transform => { return createMapStream<{ exceptions: Array; - rules: Array; + rules: Array; }>((items) => ({ exceptions: items.exceptions, rules: validateRules(items.rules), })); }; -export const validateRules = ( - rules: Array -): Array => { - return rules.map((obj: ImportRulesSchema | Error) => { +export const validateRules = (rules: Array): Array => { + return rules.map((obj: RuleToImport | Error) => { if (!(obj instanceof Error)) { - const decoded = importRulesSchema.decode(obj); + const decoded = RuleToImport.decode(obj); const checked = exactCheck(obj, decoded); - const onLeft = (errors: t.Errors): BadRequestError | ImportRulesSchema => { + const onLeft = (errors: t.Errors): BadRequestError | RuleToImport => { return new BadRequestError(formatErrors(errors).join()); }; - const onRight = (schema: ImportRulesSchema): BadRequestError | ImportRulesSchema => { - const validationErrors = importRuleValidateTypeDependents(schema); + const onRight = (schema: RuleToImport): BadRequestError | RuleToImport => { + const validationErrors = validateRuleToImport(schema); if (validationErrors.length) { return new BadRequestError(validationErrors.join()); } else { @@ -79,7 +79,7 @@ export const validateRules = ( export const sortImports = (): Transform => { return createReduceStream<{ exceptions: Array; - rules: Array; + rules: Array; }>( (acc, importItem) => { if (has('list_id', importItem) || has('item_id', importItem) || has('entries', importItem)) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/gather_referenced_exceptions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.test.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/gather_referenced_exceptions.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.test.ts index 62c591abc5e9d..797c45ea45fa2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/gather_referenced_exceptions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.test.ts @@ -6,12 +6,11 @@ */ import type { SavedObjectsClientContract } from '@kbn/core/server'; - import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import { findExceptionList } from '@kbn/lists-plugin/server/services/exception_lists/find_exception_list'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; +import { getImportRulesSchemaMock } from '../../../../../../common/detection_engine/rule_management/mocks'; import { getReferencedExceptionLists } from './gather_referenced_exceptions'; -import { getImportRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/request/import_rules_schema.mock'; jest.mock('@kbn/lists-plugin/server/services/exception_lists/find_exception_list'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/gather_referenced_exceptions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.ts similarity index 92% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/gather_referenced_exceptions.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.ts index ce6ab5c84678f..cbf6050b10b1c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/gather_referenced_exceptions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/gather_referenced_exceptions.ts @@ -8,7 +8,7 @@ import type { ExceptionListSchema, ListArray } from '@kbn/securitysolution-io-ts import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { ExceptionListQueryInfo } from '@kbn/lists-plugin/server/services/exception_lists/utils/import/find_all_exception_list_types'; import { getAllListTypes } from '@kbn/lists-plugin/server/services/exception_lists/utils/import/find_all_exception_list_types'; -import type { ImportRulesSchema } from '../../../../../../common/detection_engine/schemas/request/import_rules_schema'; +import type { RuleToImport } from '../../../../../../common/detection_engine/rule_management'; /** * Helper that takes rules, goes through their referenced exception lists and @@ -21,7 +21,7 @@ export const getReferencedExceptionLists = async ({ rules, savedObjectsClient, }: { - rules: Array; + rules: Array; savedObjectsClient: SavedObjectsClientContract; }): Promise> => { const [lists] = rules.reduce((acc, rule) => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/hapi_readable_stream.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/hapi_readable_stream.ts new file mode 100644 index 0000000000000..420d264a617ac --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/hapi_readable_stream.ts @@ -0,0 +1,14 @@ +/* + * 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 { Readable } from 'stream'; + +export interface HapiReadableStream extends Readable { + hapi: { + filename: string; + }; +} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rule_exceptions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_exceptions.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rule_exceptions.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_exceptions.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rule_exceptions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_exceptions.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rule_exceptions.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_exceptions.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.test.ts index c98bac15d457c..2de1816e4541f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.test.ts @@ -5,20 +5,22 @@ * 2.0. */ -import { requestContextMock } from '../../__mocks__'; -import { importRules } from './import_rules_utils'; +import { getImportRulesSchemaMock } from '../../../../../../common/detection_engine/rule_management/mocks'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; + +import { requestContextMock } from '../../../routes/__mocks__'; import { getRuleMock, getEmptyFindResult, getFindResultWithSingleHit, -} from '../../__mocks__/request_responses'; -import { getQueryRuleParams } from '../../../schemas/rule_schemas.mock'; -import { getImportRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/request/import_rules_schema.mock'; -import { createRules } from '../../../rules/create_rules'; -import { patchRules } from '../../../rules/patch_rules'; +} from '../../../routes/__mocks__/request_responses'; + +import { createRules } from '../crud/create_rules'; +import { patchRules } from '../crud/patch_rules'; +import { importRules } from './import_rules_utils'; -jest.mock('../../../rules/create_rules'); -jest.mock('../../../rules/patch_rules'); +jest.mock('../crud/create_rules'); +jest.mock('../crud/patch_rules'); describe('importRules', () => { const mlAuthz = { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts similarity index 91% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts index a623f3887276a..694bc916fefe3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts @@ -14,18 +14,20 @@ import type { import type { RulesClient } from '@kbn/alerting-plugin/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; -import { legacyMigrate } from '../../../rules/utils'; -import type { ImportRuleResponse } from '../../utils'; -import { createBulkErrorObject } from '../../utils'; -import { createRules } from '../../../rules/create_rules'; -import { readRules } from '../../../rules/read_rules'; -import { patchRules } from '../../../rules/patch_rules'; -import type { ImportRulesSchema } from '../../../../../../common/detection_engine/schemas/request/import_rules_schema'; + +import type { RuleToImport } from '../../../../../../common/detection_engine/rule_management'; +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate } from '../rule_actions/legacy_action_migration'; +import type { ImportRuleResponse } from '../../../routes/utils'; +import { createBulkErrorObject } from '../../../routes/utils'; +import { createRules } from '../crud/create_rules'; +import { readRules } from '../crud/read_rules'; +import { patchRules } from '../crud/patch_rules'; import type { MlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; import { checkRuleExceptionReferences } from './check_rule_exception_references'; -export type PromiseFromStreams = ImportRulesSchema | Error; +export type PromiseFromStreams = RuleToImport | Error; export interface RuleExceptionsPromiseFromStreams { rules: PromiseFromStreams[]; exceptions: Array; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/legacy_action_migration.test.ts similarity index 56% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/legacy_action_migration.test.ts index eb5d877d01942..f8332d5c3f3b1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/legacy_action_migration.test.ts @@ -5,33 +5,21 @@ * 2.0. */ -import { - transformToNotifyWhen, - transformToAlertThrottle, - transformFromAlertThrottle, - transformActions, - legacyMigrate, - getUpdatedActionsParams, -} from './utils'; -import type { RuleAction, SanitizedRule } from '@kbn/alerting-plugin/common'; -import type { RuleParams } from '../schemas/rule_schemas'; -import { - NOTIFICATION_THROTTLE_NO_ACTIONS, - NOTIFICATION_THROTTLE_RULE, -} from '../../../../common/constants'; -import type { FullResponseSchema } from '../../../../common/detection_engine/schemas/request'; -// eslint-disable-next-line no-restricted-imports -import type { LegacyRuleActions } from '../rule_actions/legacy_types'; +import { requestContextMock } from '../../../routes/__mocks__'; import { getEmptyFindResult, - legacyGetSiemNotificationRuleActionsSOResultWithSingleHit, legacyGetDailyNotificationResult, legacyGetHourlyNotificationResult, + legacyGetSiemNotificationRuleActionsSOResultWithSingleHit, legacyGetWeeklyNotificationResult, -} from '../routes/__mocks__/request_responses'; -import { requestContextMock } from '../routes/__mocks__'; +} from '../../../routes/__mocks__/request_responses'; -const getRuleLegacyActions = (): SanitizedRule => +import type { RuleAlertType } from '../../../rule_schema'; + +// eslint-disable-next-line no-restricted-imports +import { legacyMigrate, getUpdatedActionsParams } from './legacy_action_migration'; + +const getRuleLegacyActions = (): RuleAlertType => ({ id: '123', notifyWhen: 'onThrottleInterval', @@ -82,377 +70,10 @@ const getRuleLegacyActions = (): SanitizedRule => lastExecutionDate: '2022-03-31T21:47:25.695Z', lastDuration: 0, }, - } as unknown as SanitizedRule); - -describe('utils', () => { - describe('#transformToNotifyWhen', () => { - test('"null" throttle returns "null" notify', () => { - expect(transformToNotifyWhen(null)).toEqual(null); - }); - - test('"undefined" throttle returns "null" notify', () => { - expect(transformToNotifyWhen(undefined)).toEqual(null); - }); - - test('"NOTIFICATION_THROTTLE_NO_ACTIONS" throttle returns "null" notify', () => { - expect(transformToNotifyWhen(NOTIFICATION_THROTTLE_NO_ACTIONS)).toEqual(null); - }); - - test('"NOTIFICATION_THROTTLE_RULE" throttle returns "onActiveAlert" notify', () => { - expect(transformToNotifyWhen(NOTIFICATION_THROTTLE_RULE)).toEqual('onActiveAlert'); - }); - - test('"1h" throttle returns "onThrottleInterval" notify', () => { - expect(transformToNotifyWhen('1d')).toEqual('onThrottleInterval'); - }); - - test('"1d" throttle returns "onThrottleInterval" notify', () => { - expect(transformToNotifyWhen('1d')).toEqual('onThrottleInterval'); - }); - - test('"7d" throttle returns "onThrottleInterval" notify', () => { - expect(transformToNotifyWhen('7d')).toEqual('onThrottleInterval'); - }); - }); - - describe('#transformToAlertThrottle', () => { - test('"null" throttle returns "null" alert throttle', () => { - expect(transformToAlertThrottle(null)).toEqual(null); - }); - - test('"undefined" throttle returns "null" alert throttle', () => { - expect(transformToAlertThrottle(undefined)).toEqual(null); - }); - - test('"NOTIFICATION_THROTTLE_NO_ACTIONS" throttle returns "null" alert throttle', () => { - expect(transformToAlertThrottle(NOTIFICATION_THROTTLE_NO_ACTIONS)).toEqual(null); - }); - - test('"NOTIFICATION_THROTTLE_RULE" throttle returns "null" alert throttle', () => { - expect(transformToAlertThrottle(NOTIFICATION_THROTTLE_RULE)).toEqual(null); - }); - - test('"1h" throttle returns "1h" alert throttle', () => { - expect(transformToAlertThrottle('1h')).toEqual('1h'); - }); - - test('"1d" throttle returns "1d" alert throttle', () => { - expect(transformToAlertThrottle('1d')).toEqual('1d'); - }); - - test('"7d" throttle returns "7d" alert throttle', () => { - expect(transformToAlertThrottle('7d')).toEqual('7d'); - }); - }); - - describe('#transformFromAlertThrottle', () => { - test('muteAll returns "NOTIFICATION_THROTTLE_NO_ACTIONS" even with notifyWhen set and actions has an array element', () => { - expect( - transformFromAlertThrottle( - { - muteAll: true, - notifyWhen: 'onActiveAlert', - actions: [ - { - group: 'group', - id: 'id-123', - actionTypeId: 'id-456', - params: {}, - }, - ], - } as SanitizedRule, - undefined - ) - ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); - }); - - test('returns "NOTIFICATION_THROTTLE_NO_ACTIONS" if actions is an empty array and we do not have a throttle', () => { - expect( - transformFromAlertThrottle( - { - muteAll: false, - notifyWhen: 'onActiveAlert', - actions: [], - } as unknown as SanitizedRule, - undefined - ) - ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); - }); - - test('returns "NOTIFICATION_THROTTLE_NO_ACTIONS" if actions is an empty array and we have a throttle', () => { - expect( - transformFromAlertThrottle( - { - muteAll: false, - notifyWhen: 'onThrottleInterval', - actions: [], - throttle: '1d', - } as unknown as SanitizedRule, - undefined - ) - ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); - }); - - test('it returns "NOTIFICATION_THROTTLE_RULE" if "notifyWhen" is set, muteAll is false and we have an actions array', () => { - expect( - transformFromAlertThrottle( - { - muteAll: false, - notifyWhen: 'onActiveAlert', - actions: [ - { - group: 'group', - id: 'id-123', - actionTypeId: 'id-456', - params: {}, - }, - ], - } as SanitizedRule, - undefined - ) - ).toEqual(NOTIFICATION_THROTTLE_RULE); - }); - - test('it returns "NOTIFICATION_THROTTLE_RULE" if "notifyWhen" and "throttle" are not set, but we have an actions array', () => { - expect( - transformFromAlertThrottle( - { - muteAll: false, - actions: [ - { - group: 'group', - id: 'id-123', - actionTypeId: 'id-456', - params: {}, - }, - ], - } as SanitizedRule, - undefined - ) - ).toEqual(NOTIFICATION_THROTTLE_RULE); - }); - - test('it will use the "rule" and not the "legacyRuleActions" if the rule and actions is defined', () => { - const legacyRuleActions: LegacyRuleActions = { - id: 'id_1', - ruleThrottle: '', - alertThrottle: '', - actions: [ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ], - }; - - expect( - transformFromAlertThrottle( - { - muteAll: true, - notifyWhen: 'onActiveAlert', - actions: [ - { - group: 'group', - id: 'id-123', - actionTypeId: 'id-456', - params: {}, - }, - ], - } as SanitizedRule, - legacyRuleActions - ) - ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); - }); - - test('it will use the "legacyRuleActions" and not the "rule" if the rule actions is an empty array', () => { - const legacyRuleActions: LegacyRuleActions = { - id: 'id_1', - ruleThrottle: NOTIFICATION_THROTTLE_RULE, - alertThrottle: null, - actions: [ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ], - }; - - expect( - transformFromAlertThrottle( - { - muteAll: true, - notifyWhen: 'onActiveAlert', - actions: [], - } as unknown as SanitizedRule, - legacyRuleActions - ) - ).toEqual(NOTIFICATION_THROTTLE_RULE); - }); - - test('it will use the "legacyRuleActions" and not the "rule" if the rule actions is a null', () => { - const legacyRuleActions: LegacyRuleActions = { - id: 'id_1', - ruleThrottle: NOTIFICATION_THROTTLE_RULE, - alertThrottle: null, - actions: [ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ], - }; - - expect( - transformFromAlertThrottle( - { - muteAll: true, - notifyWhen: 'onActiveAlert', - actions: null, - } as unknown as SanitizedRule, - legacyRuleActions - ) - ).toEqual(NOTIFICATION_THROTTLE_RULE); - }); - }); - - describe('#transformActions', () => { - test('It transforms two alert actions', () => { - const alertAction: RuleAction[] = [ - { - id: 'id_1', - group: 'group', - actionTypeId: 'actionTypeId', - params: {}, - }, - { - id: 'id_2', - group: 'group', - actionTypeId: 'actionTypeId', - params: {}, - }, - ]; - - const transformed = transformActions(alertAction, null); - expect(transformed).toEqual([ - { - id: 'id_1', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ]); - }); - - test('It transforms two alert actions but not a legacyRuleActions if this is also passed in', () => { - const alertAction: RuleAction[] = [ - { - id: 'id_1', - group: 'group', - actionTypeId: 'actionTypeId', - params: {}, - }, - { - id: 'id_2', - group: 'group', - actionTypeId: 'actionTypeId', - params: {}, - }, - ]; - const legacyRuleActions: LegacyRuleActions = { - id: 'id_1', - ruleThrottle: '', - alertThrottle: '', - actions: [ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ], - }; - const transformed = transformActions(alertAction, legacyRuleActions); - expect(transformed).toEqual([ - { - id: 'id_1', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ]); - }); - - test('It will transform the legacyRuleActions if the alertAction is an empty array', () => { - const alertAction: RuleAction[] = []; - const legacyRuleActions: LegacyRuleActions = { - id: 'id_1', - ruleThrottle: '', - alertThrottle: '', - actions: [ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ], - }; - const transformed = transformActions(alertAction, legacyRuleActions); - expect(transformed).toEqual([ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ]); - }); - - test('It will transform the legacyRuleActions if the alertAction is undefined', () => { - const legacyRuleActions: LegacyRuleActions = { - id: 'id_1', - ruleThrottle: '', - alertThrottle: '', - actions: [ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ], - }; - const transformed = transformActions(undefined, legacyRuleActions); - expect(transformed).toEqual([ - { - id: 'id_2', - group: 'group', - action_type_id: 'actionTypeId', - params: {}, - }, - ]); - }); - }); + } as unknown as RuleAlertType); - describe('#legacyMigrate', () => { +describe('Legacy rule action migration logic', () => { + describe('legacyMigrate', () => { const ruleId = '123'; const connectorId = '456'; const { clients } = requestContextMock.createTools(); @@ -477,7 +98,7 @@ describe('utils', () => { throttle: null, notifyWhen: 'onActiveAlert', muteAll: true, - } as SanitizedRule; + } as RuleAlertType; const migratedRule = await legacyMigrate({ rulesClient: clients.rulesClient, @@ -720,7 +341,7 @@ describe('utils', () => { }); }); - describe('#getUpdatedActionsParams', () => { + describe('getUpdatedActionsParams', () => { it('updates one action', () => { const { id, ...rule } = { ...getRuleLegacyActions(), @@ -728,7 +349,7 @@ describe('utils', () => { actions: [], throttle: null, notifyWhen: 'onActiveAlert', - } as SanitizedRule; + } as RuleAlertType; expect( getUpdatedActionsParams({ @@ -788,7 +409,7 @@ describe('utils', () => { actions: [], throttle: null, notifyWhen: 'onActiveAlert', - } as SanitizedRule; + } as RuleAlertType; expect( getUpdatedActionsParams({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/legacy_action_migration.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/legacy_action_migration.ts new file mode 100644 index 0000000000000..8c69edc33064b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/legacy_action_migration.ts @@ -0,0 +1,178 @@ +/* + * 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 { isEmpty } from 'lodash/fp'; + +import type { RuleAction } from '@kbn/alerting-plugin/common'; +import type { RulesClient } from '@kbn/alerting-plugin/server'; +import type { SavedObjectReference, SavedObjectsClientContract } from '@kbn/core/server'; + +import { withSecuritySpan } from '../../../../../utils/with_security_span'; +import type { RuleAlertType } from '../../../rule_schema'; + +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../../../rule_actions_legacy'; +// eslint-disable-next-line no-restricted-imports +import type { + LegacyIRuleActionsAttributes, + LegacyRuleAlertSavedObjectAction, +} from '../../../rule_actions_legacy'; + +import { transformToAlertThrottle, transformToNotifyWhen } from '../../normalization/rule_actions'; + +export interface LegacyMigrateParams { + rulesClient: RulesClient; + savedObjectsClient: SavedObjectsClientContract; + rule: RuleAlertType | null | undefined; +} + +/** + * Determines if rule needs to be migrated from legacy actions + * and returns necessary pieces for the updated rule + */ +export const legacyMigrate = async ({ + rulesClient, + savedObjectsClient, + rule, +}: LegacyMigrateParams): Promise => + withSecuritySpan('legacyMigrate', async () => { + if (rule == null || rule.id == null) { + return rule; + } + /** + * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result + * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actual value (1hr etc..) + * Then use the rules client to delete the siem.notification + * Then with the legacy Rule Actions saved object type, just delete it. + */ + // find it using the references array, not params.ruleAlertId + const [siemNotification, legacyRuleActionsSO] = await Promise.all([ + rulesClient.find({ + options: { + filter: 'alert.attributes.alertTypeId:(siem.notifications)', + hasReference: { + type: 'alert', + id: rule.id, + }, + }, + }), + savedObjectsClient.find({ + type: legacyRuleActionsSavedObjectType, + hasReference: { + type: 'alert', + id: rule.id, + }, + }), + ]); + + const siemNotificationsExist = siemNotification != null && siemNotification.data.length > 0; + const legacyRuleNotificationSOsExist = + legacyRuleActionsSO != null && legacyRuleActionsSO.saved_objects.length > 0; + + // Assumption: if no legacy sidecar SO or notification rule types exist + // that reference the rule in question, assume rule actions are not legacy + if (!siemNotificationsExist && !legacyRuleNotificationSOsExist) { + return rule; + } + // If the legacy notification rule type ("siem.notification") exist, + // migration and cleanup are needed + if (siemNotificationsExist) { + await rulesClient.delete({ id: siemNotification.data[0].id }); + } + // If legacy notification sidecar ("siem-detection-engine-rule-actions") + // exist, migration and cleanup are needed + if (legacyRuleNotificationSOsExist) { + // Delete the legacy sidecar SO + await savedObjectsClient.delete( + legacyRuleActionsSavedObjectType, + legacyRuleActionsSO.saved_objects[0].id + ); + + // If "siem-detection-engine-rule-actions" notes that `ruleThrottle` is + // "no_actions" or "rule", rule has no actions or rule is set to run + // action on every rule run. In these cases, sidecar deletion is the only + // cleanup needed and updates to the "throttle" and "notifyWhen". "siem.notification" are + // not created for these action types + if ( + legacyRuleActionsSO.saved_objects[0].attributes.ruleThrottle === 'no_actions' || + legacyRuleActionsSO.saved_objects[0].attributes.ruleThrottle === 'rule' + ) { + return rule; + } + + // Use "legacyRuleActionsSO" instead of "siemNotification" as "siemNotification" is not created + // until a rule is run and added to task manager. That means that if by chance a user has a rule + // with actions which they have yet to enable, the actions would be lost. Instead, + // "legacyRuleActionsSO" is created on rule creation (pre 7.15) and we can rely on it to be there + const migratedRule = getUpdatedActionsParams({ + rule, + ruleThrottle: legacyRuleActionsSO.saved_objects[0].attributes.ruleThrottle, + actions: legacyRuleActionsSO.saved_objects[0].attributes.actions, + references: legacyRuleActionsSO.saved_objects[0].references, + }); + + await rulesClient.update({ + id: rule.id, + data: migratedRule, + }); + + return { id: rule.id, ...migratedRule }; + } + }); + +/** + * Translate legacy action sidecar action to rule action + */ +export const getUpdatedActionsParams = ({ + rule, + ruleThrottle, + actions, + references, +}: { + rule: RuleAlertType; + ruleThrottle: string | null; + actions: LegacyRuleAlertSavedObjectAction[]; + references: SavedObjectReference[]; +}): Omit => { + const { id, ...restOfRule } = rule; + + const actionReference = references.reduce>( + (acc, reference) => { + acc[reference.name] = reference; + return acc; + }, + {} + ); + + if (isEmpty(actionReference)) { + throw new Error( + `An error occurred migrating legacy action for rule with id:${id}. Connector reference id not found.` + ); + } + // If rule has an action on any other interval (other than on every + // rule run), need to move the action info from the sidecar/legacy action + // into the rule itself + return { + ...restOfRule, + actions: actions.reduce((acc, action) => { + const { actionRef, action_type_id: actionTypeId, ...resOfAction } = action; + if (!actionReference[actionRef]) { + return acc; + } + return [ + ...acc, + { + ...resOfAction, + id: actionReference[actionRef].id, + actionTypeId, + }, + ]; + }, []), + throttle: transformToAlertThrottle(ruleThrottle), + notifyWhen: transformToNotifyWhen(ruleThrottle), + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/muting.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/muting.ts new file mode 100644 index 0000000000000..6c0c7d9686767 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/rule_actions/muting.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../common/constants'; +import type { RuleAlertType } from '../../../rule_schema'; + +/** + * Mutes, unmutes, or does nothing to the alert if no changed is detected + * @param id The id of the alert to (un)mute + * @param rulesClient the rules client + * @param muteAll If the existing alert has all actions muted + * @param throttle If the existing alert has a throttle set + */ +export const maybeMute = async ({ + id, + rulesClient, + muteAll, + throttle, +}: { + id: RuleAlertType['id']; + rulesClient: RulesClient; + muteAll: RuleAlertType['muteAll']; + throttle: string | null | undefined; +}): Promise => { + if (muteAll && throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS) { + await rulesClient.unmuteAll({ id }); + } else if (!muteAll && throttle === NOTIFICATION_THROTTLE_NO_ACTIONS) { + await rulesClient.muteAll({ id }); + } else { + // Do nothing, no-operation + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/enrich_filter_with_rule_type_mappings.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/enrich_filter_with_rule_type_mappings.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/enrich_filter_with_rule_type_mappings.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/enrich_filter_with_rule_type_mappings.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/enrich_filter_with_rule_type_mappings.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/enrich_filter_with_rule_type_mappings.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/enrich_filter_with_rule_type_mappings.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/enrich_filter_with_rule_type_mappings.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/find_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/find_rules.ts similarity index 53% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/find_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/find_rules.ts index db45306420bb8..bb46831417d71 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/find_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/find_rules.ts @@ -5,11 +5,29 @@ * 2.0. */ -import type { FindResult } from '@kbn/alerting-plugin/server'; +import type { FindResult, RulesClient } from '@kbn/alerting-plugin/server'; + +import type { + FieldsOrUndefined, + PageOrUndefined, + PerPageOrUndefined, + QueryFilterOrUndefined, + SortFieldOrUndefined, + SortOrderOrUndefined, +} from '../../../../../../common/detection_engine/schemas/common'; + +import type { RuleParams } from '../../../rule_schema'; import { enrichFilterWithRuleTypeMapping } from './enrich_filter_with_rule_type_mappings'; -import type { RuleParams } from '../schemas/rule_schemas'; -import type { FindRuleOptions } from './types'; +export interface FindRuleOptions { + rulesClient: RulesClient; + filter: QueryFilterOrUndefined; + fields: FieldsOrUndefined; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; + page: PageOrUndefined; + perPage: PerPageOrUndefined; +} export const findRules = ({ rulesClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_existing_prepackaged_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/get_existing_prepackaged_rules.test.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_existing_prepackaged_rules.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/get_existing_prepackaged_rules.test.ts index 279a211c9ea33..338a0239b6250 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_existing_prepackaged_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/get_existing_prepackaged_rules.test.ts @@ -10,8 +10,8 @@ import { getRuleMock, getFindResultWithSingleHit, getFindResultWithMultiHits, -} from '../routes/__mocks__/request_responses'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; +} from '../../../routes/__mocks__/request_responses'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; import { getExistingPrepackagedRules, getNonPackagedRules, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_existing_prepackaged_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/get_existing_prepackaged_rules.ts similarity index 93% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_existing_prepackaged_rules.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/get_existing_prepackaged_rules.ts index 0536a7e0a264d..469de8544a13a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_existing_prepackaged_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/get_existing_prepackaged_rules.ts @@ -6,9 +6,9 @@ */ import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { withSecuritySpan } from '../../../utils/with_security_span'; +import { withSecuritySpan } from '../../../../../utils/with_security_span'; import { findRules } from './find_rules'; -import type { RuleAlertType } from './types'; +import type { RuleAlertType } from '../../../rule_schema'; export const FILTER_NON_PREPACKED_RULES = 'alert.attributes.params.immutable: false'; export const FILTER_PREPACKED_RULES = 'alert.attributes.params.immutable: true'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_actions.test.ts new file mode 100644 index 0000000000000..419e84d4d8373 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_actions.test.ts @@ -0,0 +1,394 @@ +/* + * 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 { RuleAction } from '@kbn/alerting-plugin/common'; + +import { + NOTIFICATION_THROTTLE_NO_ACTIONS, + NOTIFICATION_THROTTLE_RULE, +} from '../../../../../common/constants'; + +import type { RuleResponse } from '../../../../../common/detection_engine/rule_schema'; +// eslint-disable-next-line no-restricted-imports +import type { LegacyRuleActions } from '../../rule_actions_legacy'; +import type { RuleAlertType } from '../../rule_schema'; + +import { + transformActions, + transformFromAlertThrottle, + transformToAlertThrottle, + transformToNotifyWhen, +} from './rule_actions'; + +describe('Rule actions normalization', () => { + describe('transformToNotifyWhen', () => { + test('"null" throttle returns "null" notify', () => { + expect(transformToNotifyWhen(null)).toEqual(null); + }); + + test('"undefined" throttle returns "null" notify', () => { + expect(transformToNotifyWhen(undefined)).toEqual(null); + }); + + test('"NOTIFICATION_THROTTLE_NO_ACTIONS" throttle returns "null" notify', () => { + expect(transformToNotifyWhen(NOTIFICATION_THROTTLE_NO_ACTIONS)).toEqual(null); + }); + + test('"NOTIFICATION_THROTTLE_RULE" throttle returns "onActiveAlert" notify', () => { + expect(transformToNotifyWhen(NOTIFICATION_THROTTLE_RULE)).toEqual('onActiveAlert'); + }); + + test('"1h" throttle returns "onThrottleInterval" notify', () => { + expect(transformToNotifyWhen('1d')).toEqual('onThrottleInterval'); + }); + + test('"1d" throttle returns "onThrottleInterval" notify', () => { + expect(transformToNotifyWhen('1d')).toEqual('onThrottleInterval'); + }); + + test('"7d" throttle returns "onThrottleInterval" notify', () => { + expect(transformToNotifyWhen('7d')).toEqual('onThrottleInterval'); + }); + }); + + describe('transformToAlertThrottle', () => { + test('"null" throttle returns "null" alert throttle', () => { + expect(transformToAlertThrottle(null)).toEqual(null); + }); + + test('"undefined" throttle returns "null" alert throttle', () => { + expect(transformToAlertThrottle(undefined)).toEqual(null); + }); + + test('"NOTIFICATION_THROTTLE_NO_ACTIONS" throttle returns "null" alert throttle', () => { + expect(transformToAlertThrottle(NOTIFICATION_THROTTLE_NO_ACTIONS)).toEqual(null); + }); + + test('"NOTIFICATION_THROTTLE_RULE" throttle returns "null" alert throttle', () => { + expect(transformToAlertThrottle(NOTIFICATION_THROTTLE_RULE)).toEqual(null); + }); + + test('"1h" throttle returns "1h" alert throttle', () => { + expect(transformToAlertThrottle('1h')).toEqual('1h'); + }); + + test('"1d" throttle returns "1d" alert throttle', () => { + expect(transformToAlertThrottle('1d')).toEqual('1d'); + }); + + test('"7d" throttle returns "7d" alert throttle', () => { + expect(transformToAlertThrottle('7d')).toEqual('7d'); + }); + }); + + describe('transformFromAlertThrottle', () => { + test('muteAll returns "NOTIFICATION_THROTTLE_NO_ACTIONS" even with notifyWhen set and actions has an array element', () => { + expect( + transformFromAlertThrottle( + { + muteAll: true, + notifyWhen: 'onActiveAlert', + actions: [ + { + group: 'group', + id: 'id-123', + actionTypeId: 'id-456', + params: {}, + }, + ], + } as RuleAlertType, + undefined + ) + ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); + }); + + test('returns "NOTIFICATION_THROTTLE_NO_ACTIONS" if actions is an empty array and we do not have a throttle', () => { + expect( + transformFromAlertThrottle( + { + muteAll: false, + notifyWhen: 'onActiveAlert', + actions: [], + } as unknown as RuleAlertType, + undefined + ) + ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); + }); + + test('returns "NOTIFICATION_THROTTLE_NO_ACTIONS" if actions is an empty array and we have a throttle', () => { + expect( + transformFromAlertThrottle( + { + muteAll: false, + notifyWhen: 'onThrottleInterval', + actions: [], + throttle: '1d', + } as unknown as RuleAlertType, + undefined + ) + ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); + }); + + test('it returns "NOTIFICATION_THROTTLE_RULE" if "notifyWhen" is set, muteAll is false and we have an actions array', () => { + expect( + transformFromAlertThrottle( + { + muteAll: false, + notifyWhen: 'onActiveAlert', + actions: [ + { + group: 'group', + id: 'id-123', + actionTypeId: 'id-456', + params: {}, + }, + ], + } as RuleAlertType, + undefined + ) + ).toEqual(NOTIFICATION_THROTTLE_RULE); + }); + + test('it returns "NOTIFICATION_THROTTLE_RULE" if "notifyWhen" and "throttle" are not set, but we have an actions array', () => { + expect( + transformFromAlertThrottle( + { + muteAll: false, + actions: [ + { + group: 'group', + id: 'id-123', + actionTypeId: 'id-456', + params: {}, + }, + ], + } as RuleAlertType, + undefined + ) + ).toEqual(NOTIFICATION_THROTTLE_RULE); + }); + + test('it will use the "rule" and not the "legacyRuleActions" if the rule and actions is defined', () => { + const legacyRuleActions: LegacyRuleActions = { + id: 'id_1', + ruleThrottle: '', + alertThrottle: '', + actions: [ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ], + }; + + expect( + transformFromAlertThrottle( + { + muteAll: true, + notifyWhen: 'onActiveAlert', + actions: [ + { + group: 'group', + id: 'id-123', + actionTypeId: 'id-456', + params: {}, + }, + ], + } as RuleAlertType, + legacyRuleActions + ) + ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); + }); + + test('it will use the "legacyRuleActions" and not the "rule" if the rule actions is an empty array', () => { + const legacyRuleActions: LegacyRuleActions = { + id: 'id_1', + ruleThrottle: NOTIFICATION_THROTTLE_RULE, + alertThrottle: null, + actions: [ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ], + }; + + expect( + transformFromAlertThrottle( + { + muteAll: true, + notifyWhen: 'onActiveAlert', + actions: [], + } as unknown as RuleAlertType, + legacyRuleActions + ) + ).toEqual(NOTIFICATION_THROTTLE_RULE); + }); + + test('it will use the "legacyRuleActions" and not the "rule" if the rule actions is a null', () => { + const legacyRuleActions: LegacyRuleActions = { + id: 'id_1', + ruleThrottle: NOTIFICATION_THROTTLE_RULE, + alertThrottle: null, + actions: [ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ], + }; + + expect( + transformFromAlertThrottle( + { + muteAll: true, + notifyWhen: 'onActiveAlert', + actions: null, + } as unknown as RuleAlertType, + legacyRuleActions + ) + ).toEqual(NOTIFICATION_THROTTLE_RULE); + }); + }); + + describe('transformActions', () => { + test('It transforms two alert actions', () => { + const alertAction: RuleAction[] = [ + { + id: 'id_1', + group: 'group', + actionTypeId: 'actionTypeId', + params: {}, + }, + { + id: 'id_2', + group: 'group', + actionTypeId: 'actionTypeId', + params: {}, + }, + ]; + + const transformed = transformActions(alertAction, null); + expect(transformed).toEqual([ + { + id: 'id_1', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ]); + }); + + test('It transforms two alert actions but not a legacyRuleActions if this is also passed in', () => { + const alertAction: RuleAction[] = [ + { + id: 'id_1', + group: 'group', + actionTypeId: 'actionTypeId', + params: {}, + }, + { + id: 'id_2', + group: 'group', + actionTypeId: 'actionTypeId', + params: {}, + }, + ]; + const legacyRuleActions: LegacyRuleActions = { + id: 'id_1', + ruleThrottle: '', + alertThrottle: '', + actions: [ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ], + }; + const transformed = transformActions(alertAction, legacyRuleActions); + expect(transformed).toEqual([ + { + id: 'id_1', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ]); + }); + + test('It will transform the legacyRuleActions if the alertAction is an empty array', () => { + const alertAction: RuleAction[] = []; + const legacyRuleActions: LegacyRuleActions = { + id: 'id_1', + ruleThrottle: '', + alertThrottle: '', + actions: [ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ], + }; + const transformed = transformActions(alertAction, legacyRuleActions); + expect(transformed).toEqual([ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ]); + }); + + test('It will transform the legacyRuleActions if the alertAction is undefined', () => { + const legacyRuleActions: LegacyRuleActions = { + id: 'id_1', + ruleThrottle: '', + alertThrottle: '', + actions: [ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ], + }; + const transformed = transformActions(undefined, legacyRuleActions); + expect(transformed).toEqual([ + { + id: 'id_2', + group: 'group', + action_type_id: 'actionTypeId', + params: {}, + }, + ]); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_actions.ts new file mode 100644 index 0000000000000..99b97ea6d89ec --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_actions.ts @@ -0,0 +1,108 @@ +/* + * 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 { RuleAction, RuleNotifyWhenType } from '@kbn/alerting-plugin/common'; + +import { + NOTIFICATION_THROTTLE_NO_ACTIONS, + NOTIFICATION_THROTTLE_RULE, +} from '../../../../../common/constants'; + +import type { RuleResponse } from '../../../../../common/detection_engine/rule_schema'; +import { transformAlertToRuleAction } from '../../../../../common/detection_engine/transform_actions'; +// eslint-disable-next-line no-restricted-imports +import type { LegacyRuleActions } from '../../rule_actions_legacy'; +import type { RuleAlertType } from '../../rule_schema'; + +/** + * Given a throttle from a "security_solution" rule this will transform it into an "alerting" notifyWhen + * on their saved object. + * @params throttle The throttle from a "security_solution" rule + * @returns The correct "NotifyWhen" for a Kibana alerting. + */ +export const transformToNotifyWhen = ( + throttle: string | null | undefined +): RuleNotifyWhenType | null => { + if (throttle == null || throttle === NOTIFICATION_THROTTLE_NO_ACTIONS) { + return null; // Although I return null, this does not change the value of the "notifyWhen" and it keeps the current value of "notifyWhen" + } else if (throttle === NOTIFICATION_THROTTLE_RULE) { + return 'onActiveAlert'; + } else { + return 'onThrottleInterval'; + } +}; + +/** + * Given a throttle from a "security_solution" rule this will transform it into an "alerting" "throttle" + * on their saved object. + * @params throttle The throttle from a "security_solution" rule + * @returns The "alerting" throttle + */ +export const transformToAlertThrottle = (throttle: string | null | undefined): string | null => { + if ( + throttle == null || + throttle === NOTIFICATION_THROTTLE_RULE || + throttle === NOTIFICATION_THROTTLE_NO_ACTIONS + ) { + return null; + } else { + return throttle; + } +}; + +/** + * Given a throttle from an "alerting" Saved Object (SO) this will transform it into a "security_solution" + * throttle type. If given the "legacyRuleActions" but we detect that the rule for an unknown reason has actions + * on it to which should not be typical but possible due to the split nature of the API's, this will prefer the + * usage of the non-legacy version. Eventually the "legacyRuleActions" should be removed. + * @param throttle The throttle from a "alerting" Saved Object (SO) + * @param legacyRuleActions Legacy "side car" rule actions that if it detects it being passed it in will transform using it. + * @returns The "security_solution" throttle + */ +export const transformFromAlertThrottle = ( + rule: RuleAlertType, + legacyRuleActions: LegacyRuleActions | null | undefined +): string => { + if (legacyRuleActions == null || (rule.actions != null && rule.actions.length > 0)) { + if (rule.muteAll || rule.actions.length === 0) { + return NOTIFICATION_THROTTLE_NO_ACTIONS; + } else if ( + rule.notifyWhen === 'onActiveAlert' || + (rule.throttle == null && rule.notifyWhen == null) + ) { + return NOTIFICATION_THROTTLE_RULE; + } else if (rule.throttle == null) { + return NOTIFICATION_THROTTLE_NO_ACTIONS; + } else { + return rule.throttle; + } + } else { + return legacyRuleActions.ruleThrottle; + } +}; + +/** + * Given a set of actions from an "alerting" Saved Object (SO) this will transform it into a "security_solution" alert action. + * If this detects any legacy rule actions it will transform it. If both are sent in which is not typical but possible due to + * the split nature of the API's this will prefer the usage of the non-legacy version. Eventually the "legacyRuleActions" should + * be removed. + * @param alertAction The alert action form a "alerting" Saved Object (SO). + * @param legacyRuleActions Legacy "side car" rule actions that if it detects it being passed it in will transform using it. + * @returns The actions of the RuleResponse + */ +export const transformActions = ( + alertAction: RuleAction[] | undefined, + legacyRuleActions: LegacyRuleActions | null | undefined +): RuleResponse['actions'] => { + if (alertAction != null && alertAction.length !== 0) { + return alertAction.map((action) => transformAlertToRuleAction(action)); + } else if (legacyRuleActions != null) { + return legacyRuleActions.actions; + } else { + return []; + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.test.ts similarity index 98% rename from x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.test.ts index 50cfce7ac905a..f5e17d2bff231 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.test.ts @@ -14,8 +14,8 @@ import { getSavedQueryRuleParams, getThreatRuleParams, getThresholdRuleParams, -} from './rule_schemas.mock'; -import { getRuleMock } from '../routes/__mocks__/request_responses'; +} from '../../rule_schema/mocks'; +import { getRuleMock } from '../../routes/__mocks__/request_responses'; describe('rule_converters', () => { describe('patchTypeSpecificSnakeToCamel', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts similarity index 92% rename from x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts index e25f387160e5b..82d6ee6b1c4b2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts @@ -8,14 +8,53 @@ import uuid from 'uuid'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import { ruleTypeMappings } from '@kbn/securitysolution-rules'; import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; - +import { ruleTypeMappings } from '@kbn/securitysolution-rules'; import type { ResolvedSanitizedRule, SanitizedRule } from '@kbn/alerting-plugin/common'; + +import { + DEFAULT_INDICATOR_SOURCE_PATH, + DEFAULT_MAX_SIGNALS, + SERVER_APP_ID, +} from '../../../../../common/constants'; + +import type { PatchRuleRequestBody } from '../../../../../common/detection_engine/rule_management'; +import type { RuleExecutionSummary } from '../../../../../common/detection_engine/rule_monitoring'; +import type { + RelatedIntegrationArray, + RequiredFieldArray, + SetupGuide, + RuleCreateProps, + RuleResponse, + TypeSpecificCreateProps, + TypeSpecificResponse, +} from '../../../../../common/detection_engine/rule_schema'; +import { + EqlPatchParams, + MachineLearningPatchParams, + NewTermsPatchParams, + QueryPatchParams, + SavedQueryPatchParams, + ThreatMatchPatchParams, + ThresholdPatchParams, +} from '../../../../../common/detection_engine/rule_schema'; + +import { + transformAlertToRuleResponseAction, + transformRuleToAlertAction, + transformRuleToAlertResponseAction, +} from '../../../../../common/detection_engine/transform_actions'; + import { normalizeMachineLearningJobIds, normalizeThresholdObject, -} from '../../../../common/detection_engine/utils'; +} from '../../../../../common/detection_engine/utils'; + +import { assertUnreachable } from '../../../../../common/utility_types'; + +// eslint-disable-next-line no-restricted-imports +import type { LegacyRuleActions } from '../../rule_actions_legacy'; +import { mergeRuleExecutionSummary } from '../../rule_monitoring'; import type { InternalRuleCreate, RuleParams, @@ -36,56 +75,13 @@ import type { InternalRuleUpdate, NewTermsRuleParams, NewTermsSpecificRuleParams, -} from './rule_schemas'; -import { assertUnreachable } from '../../../../common/utility_types'; -import type { - RelatedIntegrationArray, - RequiredFieldArray, - SetupGuide, -} from '../../../../common/detection_engine/schemas/common'; -import type { RuleExecutionSummary } from '../../../../common/detection_engine/rule_monitoring'; -import { - eqlPatchParams, - machineLearningPatchParams, - newTermsPatchParams, - queryPatchParams, - savedQueryPatchParams, - threatMatchPatchParams, - thresholdPatchParams, -} from '../../../../common/detection_engine/schemas/request'; -import type { - CreateRulesSchema, - CreateTypeSpecific, - EqlPatchParams, - FullResponseSchema, - MachineLearningPatchParams, - NewTermsPatchParams, - QueryPatchParams, - ResponseTypeSpecific, - SavedQueryPatchParams, - ThreatMatchPatchParams, - ThresholdPatchParams, -} from '../../../../common/detection_engine/schemas/request'; -import type { PatchRulesSchema } from '../../../../common/detection_engine/schemas/request/patch_rules_schema'; -import { - DEFAULT_INDICATOR_SOURCE_PATH, - DEFAULT_MAX_SIGNALS, - SERVER_APP_ID, -} from '../../../../common/constants'; -import { - transformAlertToRuleResponseAction, - transformRuleToAlertAction, - transformRuleToAlertResponseAction, -} from '../../../../common/detection_engine/transform_actions'; +} from '../../rule_schema'; import { + transformActions, transformFromAlertThrottle, transformToAlertThrottle, transformToNotifyWhen, - transformActions, -} from '../rules/utils'; -// eslint-disable-next-line no-restricted-imports -import type { LegacyRuleActions } from '../rule_actions/legacy_types'; -import { mergeRuleExecutionSummary } from '../rule_monitoring'; +} from './rule_actions'; // These functions provide conversions from the request API schema to the internal rule schema and from the internal rule schema // to the response API schema. This provides static type-check assurances that the internal schema is in sync with the API schema for @@ -95,7 +91,9 @@ import { mergeRuleExecutionSummary } from '../rule_monitoring'; // Converts params from the snake case API format to the internal camel case format AND applies default values where needed. // Notice that params.language is possibly undefined for most rule types in the API but we default it to kuery to match // the legacy API behavior -export const typeSpecificSnakeToCamel = (params: CreateTypeSpecific): TypeSpecificRuleParams => { +export const typeSpecificSnakeToCamel = ( + params: TypeSpecificCreateProps +): TypeSpecificRuleParams => { switch (params.type) { case 'eql': { return { @@ -322,7 +320,7 @@ const parseValidationError = (error: string | null): BadRequestError => { }; export const patchTypeSpecificSnakeToCamel = ( - params: PatchRulesSchema, + params: PatchRuleRequestBody, existingRule: RuleParams ): TypeSpecificRuleParams => { // Here we do the validation of patch params by rule type to ensure that the fields that are @@ -332,49 +330,49 @@ 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); + const [validated, error] = validateNonExact(params, EqlPatchParams); if (validated == null) { throw parseValidationError(error); } return patchEqlParams(validated, existingRule); } case 'threat_match': { - const [validated, error] = validateNonExact(params, threatMatchPatchParams); + const [validated, error] = validateNonExact(params, ThreatMatchPatchParams); if (validated == null) { throw parseValidationError(error); } return patchThreatMatchParams(validated, existingRule); } case 'query': { - const [validated, error] = validateNonExact(params, queryPatchParams); + const [validated, error] = validateNonExact(params, QueryPatchParams); if (validated == null) { throw parseValidationError(error); } return patchQueryParams(validated, existingRule); } case 'saved_query': { - const [validated, error] = validateNonExact(params, savedQueryPatchParams); + const [validated, error] = validateNonExact(params, SavedQueryPatchParams); if (validated == null) { throw parseValidationError(error); } return patchSavedQueryParams(validated, existingRule); } case 'threshold': { - const [validated, error] = validateNonExact(params, thresholdPatchParams); + const [validated, error] = validateNonExact(params, ThresholdPatchParams); if (validated == null) { throw parseValidationError(error); } return patchThresholdParams(validated, existingRule); } case 'machine_learning': { - const [validated, error] = validateNonExact(params, machineLearningPatchParams); + const [validated, error] = validateNonExact(params, MachineLearningPatchParams); if (validated == null) { throw parseValidationError(error); } return patchMachineLearningParams(validated, existingRule); } case 'new_terms': { - const [validated, error] = validateNonExact(params, newTermsPatchParams); + const [validated, error] = validateNonExact(params, NewTermsPatchParams); if (validated == null) { throw parseValidationError(error); } @@ -387,7 +385,7 @@ export const patchTypeSpecificSnakeToCamel = ( }; const versionExcludedKeys = ['enabled', 'id', 'rule_id']; -const incrementVersion = (nextParams: PatchRulesSchema, existingRule: RuleParams) => { +const incrementVersion = (nextParams: PatchRuleRequestBody, existingRule: RuleParams) => { // The the version from nextParams if it's provided if (nextParams.version) { return nextParams.version; @@ -409,7 +407,7 @@ const incrementVersion = (nextParams: PatchRulesSchema, existingRule: RuleParams // eslint-disable-next-line complexity export const convertPatchAPIToInternalSchema = ( - nextParams: PatchRulesSchema & { + nextParams: PatchRuleRequestBody & { related_integrations?: RelatedIntegrationArray; required_fields?: RequiredFieldArray; setup?: SetupGuide; @@ -473,7 +471,7 @@ export const convertPatchAPIToInternalSchema = ( // eslint-disable-next-line complexity export const convertCreateAPIToInternalSchema = ( - input: CreateRulesSchema & { + input: RuleCreateProps & { related_integrations?: RelatedIntegrationArray; required_fields?: RequiredFieldArray; setup?: SetupGuide; @@ -530,7 +528,7 @@ export const convertCreateAPIToInternalSchema = ( }; // Converts the internal rule data structure to the response API schema -export const typeSpecificCamelToSnake = (params: TypeSpecificRuleParams): ResponseTypeSpecific => { +export const typeSpecificCamelToSnake = (params: TypeSpecificRuleParams): TypeSpecificResponse => { switch (params.type) { case 'eql': { return { @@ -666,10 +664,15 @@ export const internalRuleToAPIResponse = ( rule: SanitizedRule | ResolvedSanitizedRule, ruleExecutionSummary?: RuleExecutionSummary | null, legacyRuleActions?: LegacyRuleActions | null -): FullResponseSchema => { - const mergedExecutionSummary = mergeRuleExecutionSummary(rule, ruleExecutionSummary ?? null); +): RuleResponse => { + const mergedExecutionSummary = mergeRuleExecutionSummary( + rule.executionStatus, + ruleExecutionSummary ?? null + ); + const isResolvedRule = (obj: unknown): obj is ResolvedSanitizedRule => (obj as ResolvedSanitizedRule).outcome != null; + return { // saved object properties outcome: isResolvedRule(rule) ? rule.outcome : undefined, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.test.ts similarity index 94% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.test.ts index dd9d7ef74cb30..4737fad57a7e9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.test.ts @@ -5,49 +5,47 @@ * 2.0. */ +import { partition } from 'lodash/fp'; import { Readable } from 'stream'; import { createPromiseFromStreams } from '@kbn/utils'; -import type { Action, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { RuleAction, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { PartialRule } from '@kbn/alerting-plugin/server'; + +import type { RuleToImport } from '../../../../../common/detection_engine/rule_management'; +import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/rule_schema/mocks'; +import { requestContextMock } from '../../routes/__mocks__'; +import { getOutputRuleAlertForRest } from '../../routes/__mocks__/utils'; import { getIdError, transformFindAlerts, transform, getIdBulkError, transformAlertsToRules, - getDuplicates, getTupleDuplicateErrorsAndUniqueRules, getInvalidConnectors, swapActionIds, migrateLegacyActionsIds, } from './utils'; -import { getRuleMock } from '../__mocks__/request_responses'; +import { getRuleMock } from '../../routes/__mocks__/request_responses'; import type { PartialFilter } from '../../types'; -import type { BulkError } from '../utils'; -import { createBulkErrorObject } from '../utils'; -import { getOutputRuleAlertForRest } from '../__mocks__/utils'; -import type { PartialRule } from '@kbn/alerting-plugin/server'; -import { createRulesAndExceptionsStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; -import type { RuleAlertType } from '../../rules/types'; -import type { ImportRulesSchema } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; -import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import type { CreateRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request'; -import { - getMlRuleParams, - getQueryRuleParams, - getThreatRuleParams, -} from '../../schemas/rule_schemas.mock'; -import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; -import { requestContextMock } from '../__mocks__'; +import type { BulkError } from '../../routes/utils'; +import { createBulkErrorObject } from '../../routes/utils'; + +import type { RuleAlertType } from '../../rule_schema'; +import { getMlRuleParams, getQueryRuleParams, getThreatRuleParams } from '../../rule_schema/mocks'; // eslint-disable-next-line no-restricted-imports -import type { LegacyRulesActionsSavedObject } from '../../rule_actions/legacy_get_rule_actions_saved_object'; -// eslint-disable-next-line no-restricted-imports -import type { LegacyRuleAlertAction } from '../../rule_actions/legacy_types'; -import type { RuleExceptionsPromiseFromStreams } from './utils/import_rules_utils'; -import { partition } from 'lodash/fp'; +import type { + LegacyRuleAlertAction, + LegacyRulesActionsSavedObject, +} from '../../rule_actions_legacy'; + +import { createRulesAndExceptionsStreamFromNdJson } from '../logic/import/create_rules_stream_from_ndjson'; +import type { RuleExceptionsPromiseFromStreams } from '../logic/import/import_rules_utils'; +import { internalRuleToAPIResponse } from '../normalization/rule_converters'; -type PromiseFromStreams = ImportRulesSchema | Error; +type PromiseFromStreams = RuleToImport | Error; const createMockImportRule = async (rule: ReturnType) => { const ndJsonStream = new Readable({ @@ -492,39 +490,6 @@ describe('utils', () => { }); }); - describe('getDuplicates', () => { - test("returns array of ruleIds showing the duplicate keys of 'value2' and 'value3'", () => { - const output = getDuplicates( - [ - { rule_id: 'value1' }, - { rule_id: 'value2' }, - { rule_id: 'value2' }, - { rule_id: 'value3' }, - { rule_id: 'value3' }, - {}, - {}, - ] as CreateRulesBulkSchema, - 'rule_id' - ); - const expected = ['value2', 'value3']; - expect(output).toEqual(expected); - }); - test('returns null when given a map of no duplicates', () => { - const output = getDuplicates( - [ - { rule_id: 'value1' }, - { rule_id: 'value2' }, - { rule_id: 'value3' }, - {}, - {}, - ] as CreateRulesBulkSchema, - 'rule_id' - ); - const expected: string[] = []; - expect(output).toEqual(expected); - }); - }); - describe('getTupleDuplicateErrorsAndUniqueRules', () => { test('returns tuple of empty duplicate errors array and rule array with instance of Syntax Error when imported rule contains parse error', async () => { // This is a string because we have a double "::" below to make an error happen on purpose. @@ -645,7 +610,7 @@ describe('utils', () => { }); describe('swapActionIds', () => { - const mockAction: Action = { + const mockAction: RuleAction = { group: 'group string', id: 'some-7.x-id', action_type_id: '.slack', @@ -706,7 +671,7 @@ describe('utils', () => { }); describe('migrateLegacyActionsIds', () => { - const mockAction: Action = { + const mockAction: RuleAction = { group: 'group string', id: 'some-7.x-id', action_type_id: '.slack', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.ts similarity index 85% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.ts index 9dfd5b1efed7c..3c8ca41801303 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.ts @@ -5,29 +5,29 @@ * 2.0. */ -import { countBy, partition } from 'lodash/fp'; -import uuid from 'uuid'; -import type { Action } from '@kbn/securitysolution-io-ts-alerting-types'; -import type { SavedObjectsClientContract } from '@kbn/core/server'; +import { partition } from 'lodash/fp'; import pMap from 'p-map'; +import uuid from 'uuid'; +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 { RuleToImport } from '../../../../../common/detection_engine/rule_management'; import type { RuleExecutionSummary } from '../../../../../common/detection_engine/rule_monitoring'; -import type { ImportRulesSchema } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; -import type { CreateRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/create_rules_bulk_schema'; -import type { RuleAlertType } from '../../rules/types'; -import { isAlertType } from '../../rules/types'; -import type { BulkError, OutputError } from '../utils'; -import { createBulkErrorObject } from '../utils'; -import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; -import type { RuleParams } from '../../schemas/rule_schemas'; +import type { RuleResponse } from '../../../../../common/detection_engine/rule_schema'; + // eslint-disable-next-line no-restricted-imports -import type { LegacyRulesActionsSavedObject } from '../../rule_actions/legacy_get_rule_actions_saved_object'; +import type { LegacyRulesActionsSavedObject } from '../../rule_actions_legacy'; import type { RuleExecutionSummariesByRuleId } from '../../rule_monitoring'; -import type { FullResponseSchema } from '../../../../../common/detection_engine/schemas/request'; +import type { RuleAlertType, RuleParams } from '../../rule_schema'; +import { isAlertType } from '../../rule_schema'; +import type { BulkError, OutputError } from '../../routes/utils'; +import { createBulkErrorObject } from '../../routes/utils'; +import { internalRuleToAPIResponse } from '../normalization/rule_converters'; -type PromiseFromStreams = ImportRulesSchema | Error; +type PromiseFromStreams = RuleToImport | Error; const MAX_CONCURRENT_SEARCHES = 10; export const getIdError = ({ @@ -92,7 +92,7 @@ export const getIdBulkError = ({ export const transformAlertsToRules = ( rules: RuleAlertType[], legacyRuleActions: Record -): FullResponseSchema[] => { +): RuleResponse[] => { return rules.map((rule) => internalRuleToAPIResponse(rule, null, legacyRuleActions[rule.id])); }; @@ -104,7 +104,7 @@ export const transformFindAlerts = ( page: number; perPage: number; total: number; - data: Array>; + data: Array>; } | null => { return { page: ruleFindResults.page, @@ -121,7 +121,7 @@ export const transform = ( rule: PartialRule, ruleExecutionSummary?: RuleExecutionSummary | null, legacyRuleActions?: LegacyRulesActionsSavedObject | null -): FullResponseSchema | null => { +): RuleResponse | null => { if (isAlertType(rule)) { return internalRuleToAPIResponse(rule, ruleExecutionSummary, legacyRuleActions); } @@ -129,18 +129,6 @@ export const transform = ( return null; }; -export const getDuplicates = (ruleDefinitions: CreateRulesBulkSchema, by: 'rule_id'): string[] => { - const mappedDuplicates = countBy( - by, - ruleDefinitions.filter((r) => r[by] != null) - ); - const hasDuplicates = Object.values(mappedDuplicates).some((i) => i > 1); - if (hasDuplicates) { - return Object.keys(mappedDuplicates).filter((key) => mappedDuplicates[key] > 1); - } - return []; -}; - export const getTupleDuplicateErrorsAndUniqueRules = ( rules: PromiseFromStreams[], isOverwrite: boolean @@ -189,12 +177,12 @@ const createQuery = (type: string, id: string) => * @returns */ export const swapActionIds = async ( - action: Action, + action: RuleAction, savedObjectsClient: SavedObjectsClientContract -): Promise => { +): Promise => { try { const search = createQuery('action', action.id); - const foundAction = await savedObjectsClient.find({ + const foundAction = await savedObjectsClient.find({ type: 'action', search, rootSearchFields: ['_id', 'originId'], @@ -247,7 +235,7 @@ export const migrateLegacyActionsIds = async ( rules: PromiseFromStreams[], savedObjectsClient: SavedObjectsClientContract ): Promise => { - const isImportRule = (r: unknown): r is ImportRulesSchema => !(r instanceof Error); + const isImportRule = (r: unknown): r is RuleToImport => !(r instanceof Error); const toReturn = await pMap( rules, @@ -255,14 +243,14 @@ export const migrateLegacyActionsIds = async ( if (isImportRule(rule)) { // can we swap the pre 8.0 action connector(s) id with the new, // post-8.0 action id (swap the originId for the new _id?) - const newActions: Array = await pMap( + const newActions: Array = await pMap( rule.actions ?? [], - (action: Action) => swapActionIds(action, savedObjectsClient), + (action: RuleAction) => swapActionIds(action, savedObjectsClient), { concurrency: MAX_CONCURRENT_SEARCHES } ); // were there any errors discovered while trying to migrate and swap the action connector ids? - const [actionMigrationErrors, newlyMigratedActions] = partition( + const [actionMigrationErrors, newlyMigratedActions] = partition( (item): item is Error => item instanceof Error )(newActions); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts similarity index 92% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts index fbd763aed9758..8d920ef4ba652 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts @@ -6,15 +6,15 @@ */ import { transformValidate, transformValidateBulkError } from './validate'; -import type { BulkError } from '../utils'; -import { getRuleMock } from '../__mocks__/request_responses'; +import type { BulkError } from '../../routes/utils'; +import { getRuleMock } from '../../routes/__mocks__/request_responses'; import { ruleExecutionSummaryMock } from '../../../../../common/detection_engine/rule_monitoring/mocks'; import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import type { FullResponseSchema } from '../../../../../common/detection_engine/schemas/request'; +import { getQueryRuleParams } from '../../rule_schema/mocks'; +import type { RuleResponse } from '../../../../../common/detection_engine/rule_schema'; -export const ruleOutput = (): FullResponseSchema => ({ +export const ruleOutput = (): RuleResponse => ({ actions: [], author: ['Elastic'], building_block_type: 'default', @@ -124,7 +124,7 @@ describe('validate', () => { const rule = getRuleMock(getQueryRuleParams()); const ruleExecutionSumary = ruleExecutionSummaryMock.getSummarySucceeded(); const validatedOrError = transformValidateBulkError('rule-1', rule, ruleExecutionSumary); - const expected: FullResponseSchema = { + const expected: RuleResponse = { ...ruleOutput(), execution_summary: ruleExecutionSumary, }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts similarity index 68% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 42e50db79294a..e784068e0248e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -9,27 +9,26 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import type { PartialRule } from '@kbn/alerting-plugin/server'; import type { RuleExecutionSummary } from '../../../../../common/detection_engine/rule_monitoring'; -import type { FullResponseSchema } from '../../../../../common/detection_engine/schemas/request'; -import { fullResponseSchema } from '../../../../../common/detection_engine/schemas/request'; -import { isAlertType } from '../../rules/types'; -import type { BulkError } from '../utils'; -import { createBulkErrorObject } from '../utils'; +import { RuleResponse } from '../../../../../common/detection_engine/rule_schema'; +import type { RuleParams } from '../../rule_schema'; +import { isAlertType } from '../../rule_schema'; +import type { BulkError } from '../../routes/utils'; +import { createBulkErrorObject } from '../../routes/utils'; import { transform } from './utils'; -import type { RuleParams } from '../../schemas/rule_schemas'; // eslint-disable-next-line no-restricted-imports -import type { LegacyRulesActionsSavedObject } from '../../rule_actions/legacy_get_rule_actions_saved_object'; -import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; +import type { LegacyRulesActionsSavedObject } from '../../rule_actions_legacy'; +import { internalRuleToAPIResponse } from '../normalization/rule_converters'; export const transformValidate = ( rule: PartialRule, ruleExecutionSummary: RuleExecutionSummary | null, legacyRuleActions?: LegacyRulesActionsSavedObject | null -): [FullResponseSchema | null, string | null] => { +): [RuleResponse | null, string | null] => { const transformed = transform(rule, ruleExecutionSummary, legacyRuleActions); if (transformed == null) { return [null, 'Internal error transforming']; } else { - return validateNonExact(transformed, fullResponseSchema); + return validateNonExact(transformed, RuleResponse); } }; @@ -37,10 +36,10 @@ export const transformValidateBulkError = ( ruleId: string, rule: PartialRule, ruleExecutionSummary: RuleExecutionSummary | null -): FullResponseSchema | BulkError => { +): RuleResponse | BulkError => { if (isAlertType(rule)) { const transformed = internalRuleToAPIResponse(rule, ruleExecutionSummary); - const [validated, errors] = validateNonExact(transformed, fullResponseSchema); + const [validated, errors] = validateNonExact(transformed, RuleResponse); if (errors != null || validated == null) { return createBulkErrorObject({ ruleId, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/merge_rule_execution_summary.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/merge_rule_execution_summary.ts index 2b017d27bb971..cf403f3d6b66c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/merge_rule_execution_summary.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/merge_rule_execution_summary.ts @@ -5,22 +5,23 @@ * 2.0. */ +import type { RuleExecutionStatus as RuleExecutionStatusByFramework } from '@kbn/alerting-plugin/common'; + import type { RuleExecutionSummary } from '../../../../../../common/detection_engine/rule_monitoring'; import { RuleExecutionStatus, ruleExecutionStatusToNumber, } from '../../../../../../common/detection_engine/rule_monitoring'; -import type { RuleAlertType } from '../../../rules/types'; export const mergeRuleExecutionSummary = ( - rule: RuleAlertType, + ruleExecutionStatus: RuleExecutionStatusByFramework, ruleExecutionSummary: RuleExecutionSummary | null ): RuleExecutionSummary | null => { if (ruleExecutionSummary == null) { return null; } - const frameworkStatus = rule.executionStatus; + const frameworkStatus = ruleExecutionStatus; const customStatus = ruleExecutionSummary.last_execution; if ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts similarity index 88% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts index 9a1ba3a2b144c..1c82dc1194cef 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts @@ -17,30 +17,35 @@ import type { import { parseDuration } from '@kbn/alerting-plugin/common'; import type { ExecutorType } from '@kbn/alerting-plugin/server/types'; import type { Alert } from '@kbn/alerting-plugin/server'; -import type { StartPlugins, SetupPlugins } from '../../../../plugin'; -import { buildSiemResponse } from '../utils'; -import { convertCreateAPIToInternalSchema } from '../../schemas/rule_converters'; -import type { RuleParams } from '../../schemas/rule_schemas'; -import { createPreviewRuleExecutionLogger } from '../../signals/preview/preview_rule_execution_logger'; -import { parseInterval } from '../../signals/utils'; -import { buildMlAuthz } from '../../../machine_learning/authz'; -import { throwAuthzError } from '../../../machine_learning/validation'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { createRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/create_rules_type_dependents'; + import { DEFAULT_PREVIEW_INDEX, DETECTION_ENGINE_RULES_PREVIEW, -} from '../../../../../common/constants'; -import { wrapScopedClusterClient } from './utils/wrap_scoped_cluster_client'; -import type { RulePreviewLogs } from '../../../../../common/detection_engine/schemas/request'; -import { previewRulesSchema } from '../../../../../common/detection_engine/schemas/request'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/rule_monitoring'; -import type { RuleExecutionContext, StatusChangeArgs } from '../../rule_monitoring'; +} from '../../../../../../common/constants'; +import { validateCreateRuleProps } from '../../../../../../common/detection_engine/rule_management'; +import { RuleExecutionStatus } from '../../../../../../common/detection_engine/rule_monitoring'; +import type { RulePreviewLogs } from '../../../../../../common/detection_engine/rule_schema'; +import { previewRulesSchema } from '../../../../../../common/detection_engine/rule_schema'; + +import type { StartPlugins, SetupPlugins } from '../../../../../plugin'; +import { buildSiemResponse } from '../../../routes/utils'; +import { convertCreateAPIToInternalSchema } from '../../../rule_management'; +import type { RuleParams } from '../../../rule_schema'; +import { createPreviewRuleExecutionLogger } from '../../../signals/preview/preview_rule_execution_logger'; +import { parseInterval } from '../../../signals/utils'; +import { buildMlAuthz } from '../../../../machine_learning/authz'; +import { throwAuthzError } from '../../../../machine_learning/validation'; +import { buildRouteValidation } from '../../../../../utils/build_validation/route_validation'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; -import type { ConfigType } from '../../../../config'; -import { alertInstanceFactoryStub } from '../../signals/preview/alert_instance_factory_stub'; -import type { CreateRuleOptions, CreateSecurityRuleTypeWrapperProps } from '../../rule_types/types'; +import type { RuleExecutionContext, StatusChangeArgs } from '../../../rule_monitoring'; + +import type { ConfigType } from '../../../../../config'; +import { alertInstanceFactoryStub } from '../../../signals/preview/alert_instance_factory_stub'; +import type { + CreateRuleOptions, + CreateSecurityRuleTypeWrapperProps, +} from '../../../rule_types/types'; import { createEqlAlertType, createIndicatorMatchAlertType, @@ -49,10 +54,11 @@ import { createSavedQueryAlertType, createThresholdAlertType, createNewTermsAlertType, -} from '../../rule_types'; -import { createSecurityRuleTypeWrapper } from '../../rule_types/create_security_rule_type_wrapper'; -import { assertUnreachable } from '../../../../../common/utility_types'; -import { wrapSearchSourceClient } from './utils/wrap_search_source_client'; +} from '../../../rule_types'; +import { createSecurityRuleTypeWrapper } from '../../../rule_types/create_security_rule_type_wrapper'; +import { assertUnreachable } from '../../../../../../common/utility_types'; +import { wrapScopedClusterClient } from './wrap_scoped_cluster_client'; +import { wrapSearchSourceClient } from './wrap_search_source_client'; const PREVIEW_TIMEOUT_SECONDS = 60; @@ -79,7 +85,7 @@ export const previewRulesRoute = async ( }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const validationErrors = createRuleValidateTypeDependents(request.body); + const validationErrors = validateCreateRuleProps(request.body); const coreContext = await context.core; if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_scoped_cluster_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_scoped_cluster_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_scoped_cluster_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_scoped_cluster_client.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_scoped_cluster_client.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/wrap_search_source_client.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/register_routes.ts new file mode 100644 index 0000000000000..4fedc1ea27849 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/register_routes.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 type { Logger, StartServicesAccessor } from '@kbn/core/server'; +import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; + +import type { ConfigType } from '../../../../config'; +import type { SetupPlugins, StartPlugins } from '../../../../plugin_contract'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import type { CreateRuleOptions, CreateSecurityRuleTypeWrapperProps } from '../../rule_types/types'; + +import { previewRulesRoute } from './preview_rules/route'; + +export const registerRulePreviewRoutes = ( + router: SecuritySolutionPluginRouter, + config: ConfigType, + ml: SetupPlugins['ml'], + security: SetupPlugins['security'], + ruleOptions: CreateRuleOptions, + securityRuleTypeOptions: CreateSecurityRuleTypeWrapperProps, + previewRuleDataClient: IRuleDataClient, + getStartServices: StartServicesAccessor, + logger: Logger +) => { + previewRulesRoute( + router, + config, + ml, + security, + ruleOptions, + securityRuleTypeOptions, + previewRuleDataClient, + getStartServices, + logger + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/index.ts new file mode 100644 index 0000000000000..c0123e587d9bf --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './api/register_routes'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/index.ts new file mode 100644 index 0000000000000..9b4598ed13641 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export * from './model/rule_alert_type'; +export * from './model/rule_schemas'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/mocks.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/mocks.ts new file mode 100644 index 0000000000000..7b2a4f4440689 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/mocks.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './model/rule_schemas.mock'; 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 new file mode 100644 index 0000000000000..f7e73b49104c1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_alert_type.ts @@ -0,0 +1,20 @@ +/* + * 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 { ruleTypeMappings } from '@kbn/securitysolution-rules'; +import type { SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { PartialRule } from '@kbn/alerting-plugin/server'; +import type { RuleParams } from './rule_schemas'; + +export type RuleAlertType = SanitizedRule; + +export const isAlertType = ( + partialAlert: PartialRule +): partialAlert is RuleAlertType => { + const ruleTypeValues = Object.values(ruleTypeMappings) as unknown as string[]; + return ruleTypeValues.includes(partialAlert.alertTypeId as string); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_schemas.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.mock.ts similarity index 93% rename from x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_schemas.mock.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.mock.ts index d608c08eabcd9..f41494cf5fed4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_schemas.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.mock.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { getThreatMock } from '../../../../common/detection_engine/schemas/types/threat.mock'; -import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; -import { getThreatMappingMock } from '../signals/threat_mapping/build_threat_mapping_filter.mock'; +import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; +import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; +import { getThreatMappingMock } from '../../signals/threat_mapping/build_threat_mapping_filter.mock'; import type { BaseRuleParams, CompleteRule, @@ -19,9 +19,9 @@ import type { SavedQueryRuleParams, ThreatRuleParams, ThresholdRuleParams, -} from './rule_schemas'; +} from '..'; import type { SanitizedRuleConfig } from '@kbn/alerting-plugin/common'; -import { sampleRuleGuid } from '../signals/__mocks__/es_results'; +import { sampleRuleGuid } from '../../signals/__mocks__/es_results'; const getBaseRuleParams = (): BaseRuleParams => { return { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_schemas.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts similarity index 62% rename from x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_schemas.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts index 80f9adf29aacb..0e64cc3788a12 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_schemas.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts @@ -8,25 +8,22 @@ import * as t from 'io-ts'; import { - actionsCamel, - from, + concurrentSearchesOrUndefined, + itemsPerSearchOrUndefined, machine_learning_job_id_normalized, - risk_score, - risk_score_mapping, - threat_mapping, + RiskScore, + RiskScoreMapping, + RuleActionArrayCamel, + RuleActionThrottle, + RuleIntervalFrom, + RuleIntervalTo, + Severity, + SeverityMapping, threat_index, + threat_mapping, threat_query, - concurrentSearchesOrUndefined, - itemsPerSearchOrUndefined, threatIndicatorPathOrUndefined, - threats, - severity, - severity_mapping, - throttleOrNull, - max_signals, } from '@kbn/securitysolution-io-ts-alerting-types'; -import { listArray } from '@kbn/securitysolution-io-ts-list-types'; -import { version } from '@kbn/securitysolution-io-ts-types'; import { SIGNALS_ID, EQL_RULE_TYPE_ID, @@ -40,80 +37,84 @@ import { import type { SanitizedRuleConfig } from '@kbn/alerting-plugin/common'; import { - author, - buildingBlockTypeOrUndefined, - description, - enabled, - namespaceOrUndefined, - noteOrUndefined, - false_positives, - rule_id, - immutable, - dataViewIdOrUndefined, - indexOrUndefined, - licenseOrUndefined, - output_index, - timelineIdOrUndefined, - timelineTitleOrUndefined, - metaOrUndefined, - name, - query, - queryOrUndefined, - filtersOrUndefined, - ruleNameOverrideOrUndefined, - tags, - timestampOverrideOrUndefined, - to, - references, - timestampFieldOrUndefined, - eventCategoryOverrideOrUndefined, - tiebreakerFieldOrUndefined, - savedIdOrUndefined, - saved_id, - thresholdNormalized, - anomaly_threshold, + AlertsIndex, + AlertsIndexNamespace, + BuildingBlockType, + DataViewId, + EventCategoryOverride, + ExceptionListArray, + HistoryWindowStart, + IndexPatternArray, + InvestigationGuide, + IsRuleEnabled, + IsRuleImmutable, + MaxSignals, + NewTermsFields, RelatedIntegrationArray, RequiredFieldArray, + RuleAuthorArray, + RuleDescription, + RuleFalsePositiveArray, + RuleFilterArray, + RuleLicense, + RuleMetadata, + RuleName, + RuleNameOverride, + RuleQuery, + RuleReferenceArray, + RuleSignatureId, + RuleTagArray, + RuleVersion, SetupGuide, - newTermsFields, - historyWindowStart, - timestampOverrideFallbackDisabledOrUndefined, -} from '../../../../common/detection_engine/schemas/common'; -import { SERVER_APP_ID } from '../../../../common/constants'; -import { ResponseActionRuleParamsOrUndefined } from '../../../../common/detection_engine/rule_response_actions/schemas'; + ThreatArray, + ThresholdNormalized, + TiebreakerField, + TimelineTemplateId, + TimelineTemplateTitle, + TimestampField, + TimestampOverride, + TimestampOverrideFallbackDisabled, +} from '../../../../../common/detection_engine/rule_schema'; +import { + savedIdOrUndefined, + saved_id, + anomaly_threshold, +} from '../../../../../common/detection_engine/schemas/common'; +import { SERVER_APP_ID } from '../../../../../common/constants'; +import { ResponseActionRuleParamsOrUndefined } from '../../../../../common/detection_engine/rule_response_actions/schemas'; const nonEqlLanguages = t.keyof({ kuery: null, lucene: null }); export const baseRuleParams = t.exact( t.type({ - author, - buildingBlockType: buildingBlockTypeOrUndefined, - description, - namespace: namespaceOrUndefined, - note: noteOrUndefined, - falsePositives: false_positives, - from, - ruleId: rule_id, - immutable, - license: licenseOrUndefined, - outputIndex: output_index, - timelineId: timelineIdOrUndefined, - timelineTitle: timelineTitleOrUndefined, - meta: metaOrUndefined, + 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, + 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: max_signals, - riskScore: risk_score, - riskScoreMapping: risk_score_mapping, - ruleNameOverride: ruleNameOverrideOrUndefined, - severity, - severityMapping: severity_mapping, - timestampOverride: timestampOverrideOrUndefined, - timestampOverrideFallbackDisabled: timestampOverrideFallbackDisabledOrUndefined, - threat: threats, - to, - references, - version, - exceptionsList: listArray, + 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]), @@ -124,13 +125,13 @@ export type BaseRuleParams = t.TypeOf; const eqlSpecificRuleParams = t.type({ type: t.literal('eql'), language: t.literal('eql'), - index: indexOrUndefined, - query, - filters: filtersOrUndefined, - timestampField: timestampFieldOrUndefined, - eventCategoryOverride: eventCategoryOverrideOrUndefined, - dataViewId: dataViewIdOrUndefined, - tiebreakerField: tiebreakerFieldOrUndefined, + index: t.union([IndexPatternArray, t.undefined]), + dataViewId: t.union([DataViewId, t.undefined]), + 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]), }); export const eqlRuleParams = t.intersection([baseRuleParams, eqlSpecificRuleParams]); export type EqlSpecificRuleParams = t.TypeOf; @@ -139,11 +140,11 @@ export type EqlRuleParams = t.TypeOf; const threatSpecificRuleParams = t.type({ type: t.literal('threat_match'), language: nonEqlLanguages, - index: indexOrUndefined, - query, - filters: filtersOrUndefined, + index: t.union([IndexPatternArray, t.undefined]), + query: RuleQuery, + filters: t.union([RuleFilterArray, t.undefined]), savedId: savedIdOrUndefined, - threatFilters: filtersOrUndefined, + threatFilters: t.union([RuleFilterArray, t.undefined]), threatQuery: threat_query, threatMapping: threat_mapping, threatLanguage: t.union([nonEqlLanguages, t.undefined]), @@ -151,7 +152,7 @@ const threatSpecificRuleParams = t.type({ threatIndicatorPath: threatIndicatorPathOrUndefined, concurrentSearches: concurrentSearchesOrUndefined, itemsPerSearch: itemsPerSearchOrUndefined, - dataViewId: dataViewIdOrUndefined, + dataViewId: t.union([DataViewId, t.undefined]), }); export const threatRuleParams = t.intersection([baseRuleParams, threatSpecificRuleParams]); export type ThreatSpecificRuleParams = t.TypeOf; @@ -161,11 +162,11 @@ const querySpecificRuleParams = t.exact( t.type({ type: t.literal('query'), language: nonEqlLanguages, - index: indexOrUndefined, - query, - filters: filtersOrUndefined, + index: t.union([IndexPatternArray, t.undefined]), + query: RuleQuery, + filters: t.union([RuleFilterArray, t.undefined]), savedId: savedIdOrUndefined, - dataViewId: dataViewIdOrUndefined, + dataViewId: t.union([DataViewId, t.undefined]), responseActions: ResponseActionRuleParamsOrUndefined, }) ); @@ -178,10 +179,10 @@ const savedQuerySpecificRuleParams = t.type({ // 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: indexOrUndefined, - dataViewId: dataViewIdOrUndefined, - query: queryOrUndefined, - filters: filtersOrUndefined, + 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, }); @@ -198,12 +199,12 @@ export type UnifiedQueryRuleParams = t.TypeOf; const thresholdSpecificRuleParams = t.type({ type: t.literal('threshold'), language: nonEqlLanguages, - index: indexOrUndefined, - query, - filters: filtersOrUndefined, + index: t.union([IndexPatternArray, t.undefined]), + query: RuleQuery, + filters: t.union([RuleFilterArray, t.undefined]), savedId: savedIdOrUndefined, - threshold: thresholdNormalized, - dataViewId: dataViewIdOrUndefined, + threshold: ThresholdNormalized, + dataViewId: t.union([DataViewId, t.undefined]), }); export const thresholdRuleParams = t.intersection([baseRuleParams, thresholdSpecificRuleParams]); export type ThresholdSpecificRuleParams = t.TypeOf; @@ -223,13 +224,13 @@ export type MachineLearningRuleParams = t.TypeOf; @@ -274,30 +275,30 @@ export const allRuleTypes = t.union([ ]); export const internalRuleCreate = t.type({ - name, - tags, + name: RuleName, + tags: RuleTagArray, alertTypeId: allRuleTypes, consumer: t.literal(SERVER_APP_ID), schedule: t.type({ interval: t.string, }), - enabled, - actions: actionsCamel, + enabled: IsRuleEnabled, + actions: RuleActionArrayCamel, params: ruleParams, - throttle: throttleOrNull, + throttle: t.union([RuleActionThrottle, t.null]), notifyWhen, }); export type InternalRuleCreate = t.TypeOf; export const internalRuleUpdate = t.type({ - name, - tags, + name: RuleName, + tags: RuleTagArray, schedule: t.type({ interval: t.string, }), - actions: actionsCamel, + actions: RuleActionArrayCamel, params: ruleParams, - throttle: throttleOrNull, + throttle: t.union([RuleActionThrottle, t.null]), notifyWhen, }); export type InternalRuleUpdate = t.TypeOf; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule.ts index 505560ee6a25c..8ec684b2065fe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RuleParams } from '../../schemas/rule_schemas'; +import type { RuleParams } from '../../rule_schema'; export const createRuleMock = (params: Partial) => ({ actions: [], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts index bfe25804de29a..a76e3d3d3af7e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts @@ -20,10 +20,10 @@ import type { ConfigType } from '../../../../config'; import type { AlertAttributes } from '../../signals/types'; import { createRuleMock } from './rule'; import { listMock } from '@kbn/lists-plugin/server/mocks'; -import type { QueryRuleParams, RuleParams } from '../../schemas/rule_schemas'; +import type { QueryRuleParams, RuleParams } from '../../rule_schema'; // this is only used in tests import { createDefaultAlertExecutorOptions } from '@kbn/rule-registry-plugin/server/utils/rule_executor.test_helpers'; -import { getCompleteRuleMock } from '../../schemas/rule_schemas.mock'; +import { getCompleteRuleMock } from '../../rule_schema/mocks'; export const createRuleTypeMocks = ( ruleType: string = 'query', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts index 21107ba361645..ab6d64e69b58d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts @@ -26,7 +26,7 @@ import { flattenWithPrefix } from '@kbn/securitysolution-rules'; import type { TypeOfFieldMap } from '@kbn/rule-registry-plugin/common/field_map'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import { ANCHOR_DATE } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; +import { ANCHOR_DATE } from '../../../../../common/detection_engine/rule_schema/mocks'; import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; import type { RulesFieldMap } from '../../../../../common/field_maps'; import { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts index 05813ed1ee29c..bd630b1a71107 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts @@ -25,14 +25,18 @@ import { import { DEFAULT_MAX_SIGNALS, DEFAULT_SEARCH_AFTER_PAGE_SIZE } from '../../../../common/constants'; import type { CreateSecurityRuleTypeWrapper } from './types'; import { getListClient } from './utils/get_list_client'; -import type { NotificationRuleTypeParams } from '../notifications/schedule_notification_actions'; -import { scheduleNotificationActions } from '../notifications/schedule_notification_actions'; -import { getNotificationResultsLink } from '../notifications/utils'; +// eslint-disable-next-line no-restricted-imports +import type { NotificationRuleTypeParams } from '../rule_actions_legacy'; +// eslint-disable-next-line no-restricted-imports +import { + scheduleNotificationActions, + scheduleThrottledNotificationActions, + getNotificationResultsLink, +} from '../rule_actions_legacy'; import { createResultObject } from './utils'; import { bulkCreateFactory, wrapHitsFactory, wrapSequencesFactory } from './factories'; import { RuleExecutionStatus } from '../../../../common/detection_engine/rule_monitoring'; import { truncateList } from '../rule_monitoring'; -import { scheduleThrottledNotificationActions } from '../notifications/schedule_throttle_notification_actions'; import aadFieldConversion from '../routes/index/signal_aad_mapping.json'; import { extractReferences, injectReferences } from '../signals/saved_object_references'; import { withSecuritySpan } from '../../../utils/with_security_span'; 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 0d1a8462ac738..6e31a9753d381 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 @@ -9,8 +9,8 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { EQL_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { EqlRuleParams } from '../../schemas/rule_schemas'; -import { eqlRuleParams } from '../../schemas/rule_schemas'; +import type { EqlRuleParams } from '../../rule_schema'; +import { eqlRuleParams } from '../../rule_schema'; import { eqlExecutor } from '../../signals/executors/eql'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; import { validateIndexPatterns } from '../utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts index b1f9ed1361da1..5e6cccd11e037 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts @@ -41,7 +41,7 @@ import { ALERT_BUILDING_BLOCK_TYPE, ALERT_RULE_INDICES, } from '../../../../../../common/field_maps/field_names'; -import { getCompleteRuleMock, getQueryRuleParams } from '../../../schemas/rule_schemas.mock'; +import { getCompleteRuleMock, getQueryRuleParams } from '../../../rule_schema/mocks'; type SignalDoc = SignalSourceHit & { _source: Required['_source'] & { [TIMESTAMP]: string }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts index 38115347a8241..c716af17361ec 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts @@ -74,11 +74,8 @@ import { ALERT_RULE_EXCEPTIONS_LIST, ALERT_RULE_IMMUTABLE, } from '../../../../../../common/field_maps/field_names'; -import type { CompleteRule, RuleParams } from '../../../schemas/rule_schemas'; -import { - commonParamsCamelToSnake, - typeSpecificCamelToSnake, -} from '../../../schemas/rule_converters'; +import type { CompleteRule, RuleParams } from '../../../rule_schema'; +import { commonParamsCamelToSnake, typeSpecificCamelToSnake } from '../../../rule_management'; import { transformAlertToRuleAction } from '../../../../../../common/detection_engine/transform_actions'; import type { AncestorLatest, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.test.ts index d90bc09fb7794..e047c86e75473 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.test.ts @@ -16,8 +16,8 @@ import { objectPairIntersection, } from './build_alert_group_from_sequence'; import { SERVER_APP_ID } from '../../../../../../common/constants'; -import { getCompleteRuleMock, getQueryRuleParams } from '../../../schemas/rule_schemas.mock'; -import type { QueryRuleParams } from '../../../schemas/rule_schemas'; +import { getCompleteRuleMock, getQueryRuleParams } from '../../../rule_schema/mocks'; +import type { QueryRuleParams } from '../../../rule_schema'; import { ALERT_ANCESTORS, ALERT_DEPTH, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.ts index ccd089e767308..700986198468c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert_group_from_sequence.ts @@ -16,7 +16,7 @@ import { buildBulkBody } from './build_bulk_body'; import type { EqlSequence } from '../../../../../../common/detection_engine/types'; import { generateBuildingBlockIds } from './generate_building_block_ids'; import type { BuildReasonMessage } from '../../../signals/reason_formatters'; -import type { CompleteRule, RuleParams } from '../../../schemas/rule_schemas'; +import type { CompleteRule, RuleParams } from '../../../rule_schema'; import { ALERT_BUILDING_BLOCK_TYPE, ALERT_GROUP_ID, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts index 5ea566ce33af0..4d63f5c848484 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts @@ -15,7 +15,7 @@ import { getMergeStrategy } from '../../../signals/source_fields_merging/strateg import type { BaseSignalHit, SignalSource, SignalSourceHit } from '../../../signals/types'; import { additionalAlertFields, buildAlert } from './build_alert'; import { filterSource } from './filter_source'; -import type { CompleteRule, RuleParams } from '../../../schemas/rule_schemas'; +import type { CompleteRule, RuleParams } from '../../../rule_schema'; import { buildRuleNameFromMapping } from '../../../signals/mappings/build_rule_name_from_mapping'; import { buildSeverityFromMapping } from '../../../signals/mappings/build_severity_from_mapping'; import { buildRiskScoreFromMapping } from '../../../signals/mappings/build_risk_score_from_mapping'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.test.ts index dfdd2ce715ee4..6742f21759648 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.test.ts @@ -7,7 +7,7 @@ import { ALERT_UUID } from '@kbn/rule-data-utils'; import { ALERT_NEW_TERMS } from '../../../../../../common/field_maps/field_names'; -import { getCompleteRuleMock, getNewTermsRuleParams } from '../../../schemas/rule_schemas.mock'; +import { getCompleteRuleMock, getNewTermsRuleParams } from '../../../rule_schema/mocks'; import { sampleDocNoSortIdWithTimestamp } from '../../../signals/__mocks__/es_results'; import { wrapNewTermsAlerts } from './wrap_new_terms_alerts'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.ts index f3e1434b75f2b..38ae5b1be75ae 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/wrap_new_terms_alerts.ts @@ -15,7 +15,7 @@ import type { } from '../../../../../../common/detection_engine/schemas/alerts'; import { ALERT_NEW_TERMS } from '../../../../../../common/field_maps/field_names'; import type { ConfigType } from '../../../../../config'; -import type { CompleteRule, RuleParams } from '../../../schemas/rule_schemas'; +import type { CompleteRule, RuleParams } from '../../../rule_schema'; import { buildReasonMessageForNewTermsAlert } from '../../../signals/reason_formatters'; import type { SignalSource } from '../../../signals/types'; import { buildBulkBody } from './build_bulk_body'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts index bf4c3a8aa46e3..75d55a5756680 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts @@ -10,7 +10,7 @@ import { ALERT_UUID } from '@kbn/rule-data-utils'; import type { ConfigType } from '../../../../config'; import type { SignalSource, SimpleHit } from '../../signals/types'; -import type { CompleteRule, RuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, RuleParams } from '../../rule_schema'; import { generateId } from '../../signals/utils'; import { buildBulkBody } from './utils/build_bulk_body'; import type { BuildReasonMessage } from '../../signals/reason_formatters'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_sequences_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_sequences_factory.ts index ccf959daa9e7a..b700c31cf7c72 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_sequences_factory.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_sequences_factory.ts @@ -10,7 +10,7 @@ import type { Logger } from '@kbn/core/server'; import type { WrapSequences } from '../../signals/types'; import { buildAlertGroupFromSequence } from './utils/build_alert_group_from_sequence'; import type { ConfigType } from '../../../../config'; -import type { CompleteRule, RuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, RuleParams } from '../../rule_schema'; import type { BaseFieldsLatest, WrappedFieldsLatest, 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 fe0bc6fe77a7c..796900829d6ea 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 @@ -9,8 +9,8 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { INDICATOR_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { ThreatRuleParams } from '../../schemas/rule_schemas'; -import { threatRuleParams } from '../../schemas/rule_schemas'; +import type { ThreatRuleParams } from '../../rule_schema'; +import { threatRuleParams } from '../../rule_schema'; import { threatMatchExecutor } from '../../signals/executors/threat_match'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; import { validateIndexPatterns } from '../utils'; 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 f70d6d82087c9..c652de348484f 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 @@ -9,8 +9,8 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { ML_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { MachineLearningRuleParams } from '../../schemas/rule_schemas'; -import { machineLearningRuleParams } from '../../schemas/rule_schemas'; +import type { MachineLearningRuleParams } from '../../rule_schema'; +import { machineLearningRuleParams } from '../../rule_schema'; import { mlExecutor } from '../../signals/executors/ml'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; 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 2e22d3a5798bf..630553bc4d78c 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 @@ -10,8 +10,8 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { NEW_TERMS_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { NewTermsRuleParams } from '../../schemas/rule_schemas'; -import { newTermsRuleParams } from '../../schemas/rule_schemas'; +import type { NewTermsRuleParams } from '../../rule_schema'; +import { newTermsRuleParams } from '../../rule_schema'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; import { singleSearchAfter } from '../../signals/single_search_after'; import { getFilter } from '../../signals/get_filter'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts index dfd0ffc6c4353..c2ecb5a88df8e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts @@ -15,7 +15,7 @@ import { createMockConfig } from '../../routes/__mocks__'; import { createMockTelemetryEventsSender } from '../../../telemetry/__mocks__'; import { ruleExecutionLogMock } from '../../rule_monitoring/mocks'; import { sampleDocNoSortId } from '../../signals/__mocks__/es_results'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; +import { getQueryRuleParams } from '../../rule_schema/mocks'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; jest.mock('../../signals/utils', () => ({ 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 4ce8a1dacabf7..4f246e5ada204 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 @@ -9,8 +9,8 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { QUERY_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { UnifiedQueryRuleParams } from '../../schemas/rule_schemas'; -import { unifiedQueryRuleParams } from '../../schemas/rule_schemas'; +import type { UnifiedQueryRuleParams } from '../../rule_schema'; +import { unifiedQueryRuleParams } from '../../rule_schema'; import { queryExecutor } from '../../signals/executors/query'; import type { CreateQueryRuleOptions, SecurityAlertType } from '../types'; import { validateIndexPatterns } from '../utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts index 6565e6e14cfea..6e761bb6a51a0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts @@ -9,8 +9,8 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { SAVED_QUERY_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { CompleteRule, UnifiedQueryRuleParams } from '../../schemas/rule_schemas'; -import { unifiedQueryRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, UnifiedQueryRuleParams } from '../../rule_schema'; +import { unifiedQueryRuleParams } from '../../rule_schema'; import { queryExecutor } from '../../signals/executors/query'; import type { CreateQueryRuleOptions, SecurityAlertType } from '../types'; import { validateIndexPatterns } from '../utils'; 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 1541b08c5938c..b465abed15977 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 @@ -9,8 +9,8 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { THRESHOLD_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { ThresholdRuleParams } from '../../schemas/rule_schemas'; -import { thresholdRuleParams } from '../../schemas/rule_schemas'; +import type { ThresholdRuleParams } from '../../rule_schema'; +import { thresholdRuleParams } from '../../rule_schema'; import { thresholdExecutor } from '../../signals/executors/threshold'; import type { ThresholdAlertState } from '../../signals/types'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; 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 e1af3077ec3e3..03634c19b0ba0 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 @@ -29,7 +29,7 @@ import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import type { Filter } from '@kbn/es-query'; import type { ConfigType } from '../../../config'; import type { SetupPlugins } from '../../../plugin'; -import type { CompleteRule, RuleParams } from '../schemas/rule_schemas'; +import type { CompleteRule, RuleParams } from '../rule_schema'; import type { BulkCreate, SearchAfterAndBulkCreateReturnType, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_prepackaged_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_prepackaged_rules.test.ts deleted file mode 100644 index 0075b091d58a4..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_prepackaged_rules.test.ts +++ /dev/null @@ -1,47 +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 { getPrepackagedRules } from './get_prepackaged_rules'; -import { isEmpty } from 'lodash/fp'; -import type { AddPrepackagedRulesSchema } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; - -describe('get_existing_prepackaged_rules', () => { - test('should not throw any errors with the existing checked in pre-packaged rules', () => { - expect(() => getPrepackagedRules()).not.toThrow(); - }); - - test('no rule should have the same rule_id as another rule_id', () => { - const prePackagedRules = getPrepackagedRules(); - let existingRuleIds: AddPrepackagedRulesSchema[] = []; - prePackagedRules.forEach((rule) => { - const foundDuplicate = existingRuleIds.reduce((accum, existingRule) => { - if (existingRule.rule_id === rule.rule_id) { - return `Found duplicate rule_id of ${rule.rule_id} between these two rule names of "${rule.name}" and "${existingRule.name}"`; - } else { - return accum; - } - }, ''); - if (!isEmpty(foundDuplicate)) { - expect(foundDuplicate).toEqual(''); - } else { - existingRuleIds = [...existingRuleIds, rule]; - } - }); - }); - - test('should throw an exception if a pre-packaged rule is not valid', () => { - // @ts-expect-error intentionally invalid argument - expect(() => getPrepackagedRules([{ not_valid_made_up_key: true }])).toThrow(); - }); - - test('should throw an exception with a message having rule_id and name in it', () => { - expect(() => - // @ts-expect-error intentionally invalid argument - getPrepackagedRules([{ name: 'rule name', rule_id: 'id-123' }]) - ).toThrow(); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts deleted file mode 100644 index e1b55ca9124b1..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ /dev/null @@ -1,112 +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 { Readable } from 'stream'; - -import type { SavedObjectsClientContract } from '@kbn/core/server'; -import type { SanitizedRule } from '@kbn/alerting-plugin/common'; -import type { RulesClient, PartialRule } from '@kbn/alerting-plugin/server'; -import { ruleTypeMappings } from '@kbn/securitysolution-rules'; - -import type { - FieldsOrUndefined, - Id, - IdOrUndefined, - PageOrUndefined, - PerPageOrUndefined, - QueryFilterOrUndefined, - RuleIdOrUndefined, - SortFieldOrUndefined, - SortOrderOrUndefined, -} from '../../../../common/detection_engine/schemas/common'; - -import type { CreateRulesSchema } from '../../../../common/detection_engine/schemas/request/rule_schemas'; -import type { PatchRulesSchema } from '../../../../common/detection_engine/schemas/request/patch_rules_schema'; -import type { UpdateRulesSchema } from '../../../../common/detection_engine/schemas/request'; - -import type { RuleParams } from '../schemas/rule_schemas'; -import type { IRuleExecutionLogForRoutes } from '../rule_monitoring'; - -export type RuleAlertType = SanitizedRule; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export interface IRuleAssetSOAttributes extends Record { - rule_id: string | null | undefined; - version: string | null | undefined; - name: string | null | undefined; -} - -export interface IRuleAssetSavedObject { - type: string; - id: string; - attributes: IRuleAssetSOAttributes; -} - -export interface HapiReadableStream extends Readable { - hapi: { - filename: string; - }; -} - -export interface Clients { - rulesClient: RulesClient; -} - -export const isAlertType = ( - partialAlert: PartialRule -): partialAlert is RuleAlertType => { - const ruleTypeValues = Object.values(ruleTypeMappings) as unknown as string[]; - return ruleTypeValues.includes(partialAlert.alertTypeId as string); -}; - -export interface CreateRulesOptions { - rulesClient: RulesClient; - params: T; - id?: string; - immutable?: boolean; - defaultEnabled?: boolean; -} - -export interface UpdateRulesOptions { - rulesClient: RulesClient; - existingRule: RuleAlertType | null | undefined; - ruleUpdate: UpdateRulesSchema; -} - -export interface PatchRulesOptions { - rulesClient: RulesClient; - nextParams: PatchRulesSchema; - existingRule: RuleAlertType | null | undefined; -} - -export interface ReadRuleOptions { - rulesClient: RulesClient; - id: IdOrUndefined; - ruleId: RuleIdOrUndefined; -} - -export interface DeleteRuleOptions { - ruleId: Id; - rulesClient: RulesClient; - ruleExecutionLog: IRuleExecutionLogForRoutes; -} - -export interface FindRuleOptions { - rulesClient: RulesClient; - filter: QueryFilterOrUndefined; - fields: FieldsOrUndefined; - sortField: SortFieldOrUndefined; - sortOrder: SortOrderOrUndefined; - page: PageOrUndefined; - perPage: PerPageOrUndefined; -} - -export interface LegacyMigrateParams { - rulesClient: RulesClient; - savedObjectsClient: SavedObjectsClientContract; - rule: SanitizedRule | null | undefined; -} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts deleted file mode 100644 index dc35948bafe8a..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts +++ /dev/null @@ -1,312 +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 { RuleAction, RuleNotifyWhenType, SanitizedRule } from '@kbn/alerting-plugin/common'; -import type { RulesClient } from '@kbn/alerting-plugin/server'; -import type { SavedObjectReference } from '@kbn/core/server'; -import { isEmpty } from 'lodash/fp'; -import { - NOTIFICATION_THROTTLE_NO_ACTIONS, - NOTIFICATION_THROTTLE_RULE, -} from '../../../../common/constants'; -import type { - AddPrepackagedRulesSchema, - FullResponseSchema, -} from '../../../../common/detection_engine/schemas/request'; -import { transformAlertToRuleAction } from '../../../../common/detection_engine/transform_actions'; -import { withSecuritySpan } from '../../../utils/with_security_span'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleActionsSavedObjectType } from '../rule_actions/legacy_saved_object_mappings'; -// eslint-disable-next-line no-restricted-imports -import type { - LegacyIRuleActionsAttributes, - LegacyRuleActions, - LegacyRuleAlertSavedObjectAction, -} from '../rule_actions/legacy_types'; -import type { RuleParams } from '../schemas/rule_schemas'; -import type { LegacyMigrateParams, RuleAlertType } from './types'; - -/** - * Given a throttle from a "security_solution" rule this will transform it into an "alerting" notifyWhen - * on their saved object. - * @params throttle The throttle from a "security_solution" rule - * @returns The correct "NotifyWhen" for a Kibana alerting. - */ -export const transformToNotifyWhen = ( - throttle: string | null | undefined -): RuleNotifyWhenType | null => { - if (throttle == null || throttle === NOTIFICATION_THROTTLE_NO_ACTIONS) { - return null; // Although I return null, this does not change the value of the "notifyWhen" and it keeps the current value of "notifyWhen" - } else if (throttle === NOTIFICATION_THROTTLE_RULE) { - return 'onActiveAlert'; - } else { - return 'onThrottleInterval'; - } -}; - -/** - * Given a throttle from a "security_solution" rule this will transform it into an "alerting" "throttle" - * on their saved object. - * @params throttle The throttle from a "security_solution" rule - * @returns The "alerting" throttle - */ -export const transformToAlertThrottle = (throttle: string | null | undefined): string | null => { - if ( - throttle == null || - throttle === NOTIFICATION_THROTTLE_RULE || - throttle === NOTIFICATION_THROTTLE_NO_ACTIONS - ) { - return null; - } else { - return throttle; - } -}; - -/** - * Given a set of actions from an "alerting" Saved Object (SO) this will transform it into a "security_solution" alert action. - * If this detects any legacy rule actions it will transform it. If both are sent in which is not typical but possible due to - * the split nature of the API's this will prefer the usage of the non-legacy version. Eventually the "legacyRuleActions" should - * be removed. - * @param alertAction The alert action form a "alerting" Saved Object (SO). - * @param legacyRuleActions Legacy "side car" rule actions that if it detects it being passed it in will transform using it. - * @returns The actions of the FullResponseSchema - */ -export const transformActions = ( - alertAction: RuleAction[] | undefined, - legacyRuleActions: LegacyRuleActions | null | undefined -): FullResponseSchema['actions'] => { - if (alertAction != null && alertAction.length !== 0) { - return alertAction.map((action) => transformAlertToRuleAction(action)); - } else if (legacyRuleActions != null) { - return legacyRuleActions.actions; - } else { - return []; - } -}; - -/** - * Given a throttle from an "alerting" Saved Object (SO) this will transform it into a "security_solution" - * throttle type. If given the "legacyRuleActions" but we detect that the rule for an unknown reason has actions - * on it to which should not be typical but possible due to the split nature of the API's, this will prefer the - * usage of the non-legacy version. Eventually the "legacyRuleActions" should be removed. - * @param throttle The throttle from a "alerting" Saved Object (SO) - * @param legacyRuleActions Legacy "side car" rule actions that if it detects it being passed it in will transform using it. - * @returns The "security_solution" throttle - */ -export const transformFromAlertThrottle = ( - rule: SanitizedRule, - legacyRuleActions: LegacyRuleActions | null | undefined -): string => { - if (legacyRuleActions == null || (rule.actions != null && rule.actions.length > 0)) { - if (rule.muteAll || rule.actions.length === 0) { - return NOTIFICATION_THROTTLE_NO_ACTIONS; - } else if ( - rule.notifyWhen === 'onActiveAlert' || - (rule.throttle == null && rule.notifyWhen == null) - ) { - return NOTIFICATION_THROTTLE_RULE; - } else if (rule.throttle == null) { - return NOTIFICATION_THROTTLE_NO_ACTIONS; - } else { - return rule.throttle; - } - } else { - return legacyRuleActions.ruleThrottle; - } -}; - -/** - * Mutes, unmutes, or does nothing to the alert if no changed is detected - * @param id The id of the alert to (un)mute - * @param rulesClient the rules client - * @param muteAll If the existing alert has all actions muted - * @param throttle If the existing alert has a throttle set - */ -export const maybeMute = async ({ - id, - rulesClient, - muteAll, - throttle, -}: { - id: SanitizedRule['id']; - rulesClient: RulesClient; - muteAll: SanitizedRule['muteAll']; - throttle: string | null | undefined; -}): Promise => { - if (muteAll && throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS) { - await rulesClient.unmuteAll({ id }); - } else if (!muteAll && throttle === NOTIFICATION_THROTTLE_NO_ACTIONS) { - await rulesClient.muteAll({ id }); - } else { - // Do nothing, no-operation - } -}; - -/** - * Translate legacy action sidecar action to rule action - */ -export const getUpdatedActionsParams = ({ - rule, - ruleThrottle, - actions, - references, -}: { - rule: SanitizedRule; - ruleThrottle: string | null; - actions: LegacyRuleAlertSavedObjectAction[]; - references: SavedObjectReference[]; -}): Omit, 'id'> => { - const { id, ...restOfRule } = rule; - - const actionReference = references.reduce>( - (acc, reference) => { - acc[reference.name] = reference; - return acc; - }, - {} - ); - - if (isEmpty(actionReference)) { - throw new Error( - `An error occurred migrating legacy action for rule with id:${id}. Connector reference id not found.` - ); - } - // If rule has an action on any other interval (other than on every - // rule run), need to move the action info from the sidecar/legacy action - // into the rule itself - return { - ...restOfRule, - actions: actions.reduce((acc, action) => { - const { actionRef, action_type_id: actionTypeId, ...resOfAction } = action; - if (!actionReference[actionRef]) { - return acc; - } - return [ - ...acc, - { - ...resOfAction, - id: actionReference[actionRef].id, - actionTypeId, - }, - ]; - }, []), - throttle: transformToAlertThrottle(ruleThrottle), - notifyWhen: transformToNotifyWhen(ruleThrottle), - }; -}; - -/** - * Determines if rule needs to be migrated from legacy actions - * and returns necessary pieces for the updated rule - */ -export const legacyMigrate = async ({ - rulesClient, - savedObjectsClient, - rule, -}: LegacyMigrateParams): Promise | null | undefined> => - withSecuritySpan('legacyMigrate', async () => { - if (rule == null || rule.id == null) { - return rule; - } - /** - * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result - * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actual value (1hr etc..) - * Then use the rules client to delete the siem.notification - * Then with the legacy Rule Actions saved object type, just delete it. - */ - // find it using the references array, not params.ruleAlertId - const [siemNotification, legacyRuleActionsSO] = await Promise.all([ - rulesClient.find({ - options: { - filter: 'alert.attributes.alertTypeId:(siem.notifications)', - hasReference: { - type: 'alert', - id: rule.id, - }, - }, - }), - savedObjectsClient.find({ - type: legacyRuleActionsSavedObjectType, - hasReference: { - type: 'alert', - id: rule.id, - }, - }), - ]); - - const siemNotificationsExist = siemNotification != null && siemNotification.data.length > 0; - const legacyRuleNotificationSOsExist = - legacyRuleActionsSO != null && legacyRuleActionsSO.saved_objects.length > 0; - - // Assumption: if no legacy sidecar SO or notification rule types exist - // that reference the rule in question, assume rule actions are not legacy - if (!siemNotificationsExist && !legacyRuleNotificationSOsExist) { - return rule; - } - // If the legacy notification rule type ("siem.notification") exist, - // migration and cleanup are needed - if (siemNotificationsExist) { - await rulesClient.delete({ id: siemNotification.data[0].id }); - } - // If legacy notification sidecar ("siem-detection-engine-rule-actions") - // exist, migration and cleanup are needed - if (legacyRuleNotificationSOsExist) { - // Delete the legacy sidecar SO - await savedObjectsClient.delete( - legacyRuleActionsSavedObjectType, - legacyRuleActionsSO.saved_objects[0].id - ); - - // If "siem-detection-engine-rule-actions" notes that `ruleThrottle` is - // "no_actions" or "rule", rule has no actions or rule is set to run - // action on every rule run. In these cases, sidecar deletion is the only - // cleanup needed and updates to the "throttle" and "notifyWhen". "siem.notification" are - // not created for these action types - if ( - legacyRuleActionsSO.saved_objects[0].attributes.ruleThrottle === 'no_actions' || - legacyRuleActionsSO.saved_objects[0].attributes.ruleThrottle === 'rule' - ) { - return rule; - } - - // Use "legacyRuleActionsSO" instead of "siemNotification" as "siemNotification" is not created - // until a rule is run and added to task manager. That means that if by chance a user has a rule - // with actions which they have yet to enable, the actions would be lost. Instead, - // "legacyRuleActionsSO" is created on rule creation (pre 7.15) and we can rely on it to be there - const migratedRule = getUpdatedActionsParams({ - rule, - ruleThrottle: legacyRuleActionsSO.saved_objects[0].attributes.ruleThrottle, - actions: legacyRuleActionsSO.saved_objects[0].attributes.actions, - references: legacyRuleActionsSO.saved_objects[0].references, - }); - - await rulesClient.update({ - id: rule.id, - data: migratedRule, - }); - - return { id: rule.id, ...migratedRule }; - } - }); - -/** - * Converts an array of prepackaged rules to a Map with rule IDs as keys - * - * @param rules Array of prepackaged rules - * @returns Map - */ -export const prepackagedRulesToMap = (rules: AddPrepackagedRulesSchema[]) => - new Map(rules.map((rule) => [rule.rule_id, rule])); - -/** - * Converts an array of rules to a Map with rule IDs as keys - * - * @param rules Array of rules - * @returns Map - */ -export const rulesToMap = (rules: RuleAlertType[]) => - new Map(rules.map((rule) => [rule.params.ruleId, rule])); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/create_ndjson_prepackaged_rules.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/create_ndjson_prepackaged_rules.sh index 2c983fd7c9824..c69916770086c 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/create_ndjson_prepackaged_rules.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/create_ndjson_prepackaged_rules.sh @@ -8,10 +8,10 @@ # i=0; -for f in ../rules/prepackaged_rules/*.json ; do +for f in ../prebuilt_rules/content/prepackaged_rules/*.json ; do ((i++)); echo "converting $f" - cat ../rules/prepackaged_rules/windows_msxsl_network.json | tr -d '\n' | tr -d ' ' >> pre_packaged_rules.ndjson + cat ../prebuilt_rules/content/prepackaged_rules/windows_msxsl_network.json | tr -d '\n' | tr -d ' ' >> pre_packaged_rules.ndjson echo "" >> pre_packaged_rules.ndjson done echo "{\"exported_count\":$i,\"missing_rules\":[],\"missing_rules_count\":0}" >> pre_packaged_rules.ndjson diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/regen_prepackage_rules_index.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/regen_prepackage_rules_index.sh index 507e9815c4c74..6eb1b28dc8c2e 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/regen_prepackage_rules_index.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/regen_prepackage_rules_index.sh @@ -4,7 +4,7 @@ set -e # Regenerates the index.ts that contains all of the rules that are read in from json -PREPACKAGED_RULES_INDEX=../rules/prepackaged_rules/index.ts +PREPACKAGED_RULES_INDEX=../prebuilt_rules/content/prepackaged_rules/index.ts echo "/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one @@ -18,7 +18,7 @@ echo "/* " > ${PREPACKAGED_RULES_INDEX} RULE_NUMBER=1 -for f in ../rules/prepackaged_rules/*.json ; do +for f in ../prebuilt_rules/content/prepackaged_rules/*.json ; do echo "import rule${RULE_NUMBER} from './$(basename -- "$f")';" >> ${PREPACKAGED_RULES_INDEX} RULE_NUMBER=$[$RULE_NUMBER +1] done @@ -26,7 +26,7 @@ done echo "export const rawRules = [" >> ${PREPACKAGED_RULES_INDEX} RULE_NUMBER=1 -for f in ../rules/prepackaged_rules/*.json ; do +for f in ../prebuilt_rules/content/prepackaged_rules/*.json ; do echo " rule${RULE_NUMBER}," >> ${PREPACKAGED_RULES_INDEX} RULE_NUMBER=$[$RULE_NUMBER +1] done diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/add_prepackaged_timelines.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/add_prepackaged_timelines.sh index 6de63e5910a37..48bd884294611 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/add_prepackaged_timelines.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/add_prepackaged_timelines.sh @@ -11,9 +11,9 @@ set -e ./check_env_variables.sh # Uses a defaults if no argument is specified -TIMELINES=${1:-../../rules/prepackaged_timelines/index.ndjson} +TIMELINES=${1:-../../prebuilt_rules/content/prepackaged_timelines/index.ndjson} -# Example to import and overwrite everything from ../rules/prepackaged_timelines/index.ndjson +# Example to import and overwrite everything from ../prebuilt_rules/content/prepackaged_timelines/index.ndjson # ./timelines/add_prepackaged_timelines.sh curl -s -k \ -H 'kbn-xsrf: 123' \ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/regen_prepackage_timelines_index.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/regen_prepackage_timelines_index.sh index 8bd6101dfcc9a..a643a7bbcf838 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/regen_prepackage_timelines_index.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/timelines/regen_prepackage_timelines_index.sh @@ -4,7 +4,7 @@ set -e ./check_env_variables.sh # Regenerates the index.ts that contains all of the timelines that are read in from json -PREPACKAGED_TIMELINES_INDEX=../rules/prepackaged_timelines/index.ndjson +PREPACKAGED_TIMELINES_INDEX=../prebuilt_rules/content/prepackaged_timelines/index.ndjson # Clear existing content echo "" > ${PREPACKAGED_TIMELINES_INDEX} @@ -20,7 +20,7 @@ echo "/* // Do not hand edit. Run that script to regenerate package information instead " > ${PREPACKAGED_TIMELINES_INDEX} -for f in ../rules/prepackaged_timelines/*.json ; do +for f in ../prebuilt_rules/content/prepackaged_timelines/*.json ; do echo "converting $f" sed ':a;N;$!ba;s/\n/ /g' $f >> ${PREPACKAGED_TIMELINES_INDEX} done diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts index e3b05756709cc..a5a8c4963f227 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts @@ -8,10 +8,9 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isEmpty } from 'lodash'; import type { Filter } from '@kbn/es-query'; import type { - FiltersOrUndefined, - TimestampOverrideOrUndefined, + RuleFilterArray, TimestampOverride, -} from '../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../common/detection_engine/rule_schema'; import { getQueryFilter } from './get_query_filter'; interface BuildEventsSearchQuery { @@ -25,7 +24,7 @@ interface BuildEventsSearchQuery { sortOrder?: estypes.SortOrder; searchAfterSortIds: estypes.SortResults | undefined; primaryTimestamp: TimestampOverride; - secondaryTimestamp: TimestampOverrideOrUndefined; + secondaryTimestamp: TimestampOverride | undefined; trackTotalHits?: boolean; } @@ -35,9 +34,9 @@ interface BuildEqlSearchRequestParams { from: string; to: string; size: number; - filters: FiltersOrUndefined; + filters: RuleFilterArray | undefined; primaryTimestamp: TimestampOverride; - secondaryTimestamp: TimestampOverrideOrUndefined; + secondaryTimestamp: TimestampOverride | undefined; runtimeMappings: estypes.MappingRuntimeFields | undefined; eventCategoryOverride?: string; timestampField?: string; @@ -54,7 +53,7 @@ const buildTimeRangeFilter = ({ to: string; from: string; primaryTimestamp: TimestampOverride; - secondaryTimestamp: TimestampOverrideOrUndefined; + secondaryTimestamp: TimestampOverride | undefined; }): estypes.QueryDslQueryContainer => { // The primaryTimestamp is always provided and will contain either the timestamp override field or `@timestamp` otherwise. // The secondaryTimestamp is `undefined` if diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts index f9a4c21898b09..7f565036abe3f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts @@ -16,7 +16,7 @@ import type { import type { GenericBulkCreateResponse } from '../rule_types/factories'; import type { Anomaly } from '../../machine_learning'; import type { BulkCreate, WrapHits } from './types'; -import type { CompleteRule, MachineLearningRuleParams } from '../schemas/rule_schemas'; +import type { CompleteRule, MachineLearningRuleParams } from '../rule_schema'; import { buildReasonMessageForMlAlert } from './reason_formatters'; import type { BaseFieldsLatest } from '../../../../common/detection_engine/schemas/alerts'; import type { IRuleExecutionLogForExecutors } from '../rule_monitoring'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts index 93e37c41c8ab3..fb0920bef9ade 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts @@ -12,8 +12,8 @@ import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas import { DEFAULT_INDEX_PATTERN } from '../../../../../common/constants'; import { getIndexVersion } from '../../routes/index/get_index_version'; import { SIGNALS_TEMPLATE_VERSION } from '../../routes/index/get_signals_template'; -import type { EqlRuleParams } from '../../schemas/rule_schemas'; -import { getCompleteRuleMock, getEqlRuleParams } from '../../schemas/rule_schemas.mock'; +import type { EqlRuleParams } from '../../rule_schema'; +import { getCompleteRuleMock, getEqlRuleParams } from '../../rule_schema/mocks'; import { ruleExecutionLogMock } from '../../rule_monitoring/mocks'; import { eqlExecutor } from './eql'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts index 436ebec9c27c1..a67a404478b18 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts @@ -32,7 +32,7 @@ import { getUnprocessedExceptionsWarnings, } from '../utils'; import { buildReasonMessageForEqlAlert } from '../reason_formatters'; -import type { CompleteRule, EqlRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, EqlRuleParams } from '../../rule_schema'; import { withSecuritySpan } from '../../../../utils/with_security_span'; import type { BaseFieldsLatest, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts index 49e2ef43282a2..ac6865554b36a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts @@ -9,12 +9,12 @@ import dateMath from '@kbn/datemath'; import type { RuleExecutorServicesMock } from '@kbn/alerting-plugin/server/mocks'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; import { mlExecutor } from './ml'; -import { getCompleteRuleMock, getMlRuleParams } from '../../schemas/rule_schemas.mock'; +import { getCompleteRuleMock, getMlRuleParams } from '../../rule_schema/mocks'; import { getListClientMock } from '@kbn/lists-plugin/server/services/lists/list_client.mock'; import { findMlSignals } from '../find_ml_signals'; import { bulkCreateMlSignals } from '../bulk_create_ml_signals'; import { mlPluginServerMock } from '@kbn/ml-plugin/server/mocks'; -import type { MachineLearningRuleParams } from '../../schemas/rule_schemas'; +import type { MachineLearningRuleParams } from '../../rule_schema'; import { ruleExecutionLogMock } from '../../rule_monitoring/mocks'; jest.mock('../find_ml_signals'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts index ad49900078c4c..b7cb97f906bf0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts @@ -15,7 +15,7 @@ import type { import type { ListClient } from '@kbn/lists-plugin/server'; import type { Filter } from '@kbn/es-query'; import { isJobStarted } from '../../../../../common/machine_learning/helpers'; -import type { CompleteRule, MachineLearningRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, MachineLearningRuleParams } from '../../rule_schema'; import { bulkCreateMlSignals } from '../bulk_create_ml_signals'; import { filterEventsAgainstList } from '../filters/filter_events_against_list'; import { findMlSignals } from '../find_ml_signals'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts index b2309bee8ad0a..52c0247b950db 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts @@ -21,7 +21,7 @@ import { getFilter } from '../get_filter'; import { searchAfterAndBulkCreate } from '../search_after_bulk_create'; import type { RuleRangeTuple, BulkCreate, WrapHits } from '../types'; import type { ITelemetryEventsSender } from '../../../telemetry/sender'; -import type { CompleteRule, UnifiedQueryRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, UnifiedQueryRuleParams } from '../../rule_schema'; import type { ExperimentalFeatures } from '../../../../../common/experimental_features'; import { buildReasonMessageForQueryAlert } from '../reason_formatters'; import { withSecuritySpan } from '../../../../utils/with_security_span'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts index 4f99412acb5c2..8ebf39867dea4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts @@ -18,7 +18,7 @@ import type { Filter } from '@kbn/es-query'; import type { RuleRangeTuple, BulkCreate, WrapHits } from '../types'; import type { ITelemetryEventsSender } from '../../../telemetry/sender'; import { createThreatSignals } from '../threat_mapping/create_threat_signals'; -import type { CompleteRule, ThreatRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, ThreatRuleParams } from '../../rule_schema'; import { withSecuritySpan } from '../../../../utils/with_security_span'; import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../common/constants'; import type { IRuleExecutionLogForExecutors } from '../../rule_monitoring'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts index 832ffa1e5b5c4..0e780d9709ab8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts @@ -11,10 +11,10 @@ import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas import type { RuleExecutorServicesMock } from '@kbn/alerting-plugin/server/mocks'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; import { thresholdExecutor } from './threshold'; -import { getThresholdRuleParams, getCompleteRuleMock } from '../../schemas/rule_schemas.mock'; +import { getThresholdRuleParams, getCompleteRuleMock } from '../../rule_schema/mocks'; import { sampleEmptyAggsSearchResults } from '../__mocks__/es_results'; import { getThresholdTermsHash } from '../utils'; -import type { ThresholdRuleParams } from '../../schemas/rule_schemas'; +import type { ThresholdRuleParams } from '../../rule_schema'; import { createRuleDataClientMock } from '@kbn/rule-registry-plugin/server/rule_data_client/rule_data_client.mock'; import { TIMESTAMP } from '@kbn/rule-data-utils'; import { ruleExecutionLogMock } from '../../rule_monitoring/mocks'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts index ed82f7cdb1f8a..7a148e80282dc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts @@ -16,7 +16,7 @@ import type { } from '@kbn/alerting-plugin/server'; import type { IRuleDataReader } from '@kbn/rule-registry-plugin/server'; import type { Filter } from '@kbn/es-query'; -import type { CompleteRule, ThresholdRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, ThresholdRuleParams } from '../../rule_schema'; import { getFilter } from '../get_filter'; import { bulkCreateThresholdSignals, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts index 521fdf1e5a595..33d710ed2ffa4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts @@ -18,11 +18,8 @@ import type { } from '@kbn/alerting-plugin/server'; import type { Filter } from '@kbn/es-query'; import { assertUnreachable } from '../../../../common/utility_types'; -import type { - QueryOrUndefined, - SavedIdOrUndefined, - IndexOrUndefined, -} from '../../../../common/detection_engine/schemas/common/schemas'; +import type { IndexPatternArray, RuleQuery } from '../../../../common/detection_engine/rule_schema'; +import type { SavedIdOrUndefined } from '../../../../common/detection_engine/schemas/common/schemas'; import type { PartialFilter } from '../types'; import { withSecuritySpan } from '../../../utils/with_security_span'; import type { ESBoolQuery } from '../../../../common/typed_json'; @@ -32,10 +29,10 @@ interface GetFilterArgs { type: Type; filters: unknown | undefined; language: LanguageOrUndefined; - query: QueryOrUndefined; + query: RuleQuery | undefined; savedId: SavedIdOrUndefined; services: RuleExecutorServices; - index: IndexOrUndefined; + index: IndexPatternArray | undefined; exceptionFilter: Filter | undefined; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts index 58b13152bb64a..15477388839e4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_query_filter.ts @@ -9,7 +9,7 @@ import type { Language } from '@kbn/securitysolution-io-ts-alerting-types'; import type { Filter, EsQueryConfig, DataViewBase } from '@kbn/es-query'; import { buildEsQuery } from '@kbn/es-query'; import type { ESBoolQuery } from '../../../../common/typed_json'; -import type { Index, Query } from '../../../../common/detection_engine/schemas/common'; +import type { IndexPatternArray, RuleQuery } from '../../../../common/detection_engine/rule_schema'; export const getQueryFilter = ({ query, @@ -18,10 +18,10 @@ export const getQueryFilter = ({ index, exceptionFilter, }: { - query: Query; + query: RuleQuery; language: Language; filters: unknown; - index: Index; + index: IndexPatternArray; exceptionFilter: Filter | undefined; }): ESBoolQuery => { const indexPattern: DataViewBase = { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.test.ts index ffd9e2b46d48f..5ae4aff3a6687 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.test.ts @@ -5,10 +5,7 @@ * 2.0. */ -import type { - RiskScore, - RiskScoreMappingOrUndefined, -} from '@kbn/securitysolution-io-ts-alerting-types'; +import type { RiskScore, RiskScoreMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import { sampleDocRiskScore } from '../__mocks__/es_results'; import type { BuildRiskScoreFromMappingReturn } from './build_risk_score_from_mapping'; import { buildRiskScoreFromMapping } from './build_risk_score_from_mapping'; @@ -187,7 +184,7 @@ describe('buildRiskScoreFromMapping', () => { interface TestCase { fieldValue: unknown; scoreDefault: RiskScore; - scoreMapping: RiskScoreMappingOrUndefined; + scoreMapping: RiskScoreMapping | undefined; expected: BuildRiskScoreFromMappingReturn; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.ts index 9e875165cf469..e17c5b941cbb5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.ts @@ -5,23 +5,21 @@ * 2.0. */ -import type { - RiskScore, - RiskScoreMappingOrUndefined, -} from '@kbn/securitysolution-io-ts-alerting-types'; import { get } from 'lodash/fp'; -import type { Meta } from '../../../../../common/detection_engine/schemas/common/schemas'; + +import type { RiskScore, RiskScoreMapping } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { RuleMetadata } from '../../../../../common/detection_engine/rule_schema'; import type { SignalSource } from '../types'; export interface BuildRiskScoreFromMappingProps { eventSource: SignalSource; riskScore: RiskScore; - riskScoreMapping: RiskScoreMappingOrUndefined; + riskScoreMapping: RiskScoreMapping | undefined; } export interface BuildRiskScoreFromMappingReturn { riskScore: RiskScore; - riskScoreMeta: Meta; // TODO: Stricter types + riskScoreMeta: RuleMetadata; // TODO: Stricter types } /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_rule_name_from_mapping.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_rule_name_from_mapping.ts index ae7247c01b1af..933a330a77098 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_rule_name_from_mapping.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_rule_name_from_mapping.ts @@ -7,22 +7,23 @@ import * as t from 'io-ts'; import { get } from 'lodash/fp'; + import type { - Meta, - Name, - RuleNameOverrideOrUndefined, -} from '../../../../../common/detection_engine/schemas/common/schemas'; + RuleMetadata, + RuleName, + RuleNameOverride, +} from '../../../../../common/detection_engine/rule_schema'; import type { SignalSource } from '../types'; interface BuildRuleNameFromMappingProps { eventSource: SignalSource; - ruleName: Name; - ruleNameMapping: RuleNameOverrideOrUndefined; + ruleName: RuleName; + ruleNameMapping: RuleNameOverride | undefined; } interface BuildRuleNameFromMappingReturn { - ruleName: Name; - ruleNameMeta: Meta; // TODO: Stricter types + ruleName: RuleName; + ruleNameMeta: RuleMetadata; // TODO: Stricter types } export const buildRuleNameFromMapping = ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.test.ts index 75e53cdf0ae4c..875da0124b42f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.test.ts @@ -5,11 +5,7 @@ * 2.0. */ -import type { - Severity, - SeverityMappingOrUndefined, -} from '@kbn/securitysolution-io-ts-alerting-types'; - +import type { Severity, SeverityMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import { sampleDocSeverity } from '../__mocks__/es_results'; import type { BuildSeverityFromMappingReturn } from './build_severity_from_mapping'; import { buildSeverityFromMapping } from './build_severity_from_mapping'; @@ -141,7 +137,7 @@ interface TestCase { fieldName?: string; fieldValue: unknown; severityDefault: Severity; - severityMapping: SeverityMappingOrUndefined; + severityMapping: SeverityMapping | undefined; expected: BuildSeverityFromMappingReturn; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.ts index 4a57467040b5e..53691eeb98814 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.ts @@ -7,25 +7,25 @@ import { get } from 'lodash/fp'; +import { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; import type { - Severity, + SeverityMapping, SeverityMappingItem, - SeverityMappingOrUndefined, } from '@kbn/securitysolution-io-ts-alerting-types'; -import { severity as SeverityIOTS } from '@kbn/securitysolution-io-ts-alerting-types'; -import type { Meta } from '../../../../../common/detection_engine/schemas/common/schemas'; + +import type { RuleMetadata } from '../../../../../common/detection_engine/rule_schema'; import type { SearchTypes } from '../../../../../common/detection_engine/types'; import type { SignalSource } from '../types'; export interface BuildSeverityFromMappingProps { eventSource: SignalSource; severity: Severity; - severityMapping: SeverityMappingOrUndefined; + severityMapping: SeverityMapping | undefined; } export interface BuildSeverityFromMappingReturn { severity: Severity; - severityMeta: Meta; // TODO: Stricter types + severityMeta: RuleMetadata; // TODO: Stricter types } const severitySortMapping = { @@ -66,7 +66,7 @@ export const buildSeverityFromMapping = ({ } }); - if (severityMatch != null && SeverityIOTS.is(severityMatch.severity)) { + if (severityMatch != null && Severity.is(severityMatch.severity)) { return overriddenSeverity(severityMatch.severity, severityMatch.field); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts index a3cf4ebc95d7c..1b947b1be08a2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts @@ -11,7 +11,7 @@ import type { RuleTypeState, } from '@kbn/alerting-plugin/common'; import { Alert } from '@kbn/alerting-plugin/server/alert'; -import type { RuleParams } from '../../schemas/rule_schemas'; +import type { RuleParams } from '../../rule_schema'; export const alertInstanceFactoryStub = < TParams extends RuleParams, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_data_view.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_data_view.ts index 3cbe4d4b1c980..293d853f1d2ad 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_data_view.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_data_view.ts @@ -12,7 +12,7 @@ import type { QueryRuleParams, ThreatRuleParams, ThresholdRuleParams, -} from '../../schemas/rule_schemas'; +} from '../../rule_schema'; /** * This extracts the "dataViewId" and returns it as a saved object reference. diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.test.ts index 68d262961bfa1..db86d90598be7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.test.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { extractExceptionsList } from './extract_exceptions_list'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -import type { RuleParams } from '../../schemas/rule_schemas'; import { EXCEPTION_LIST_NAMESPACE, EXCEPTION_LIST_NAMESPACE_AGNOSTIC, } from '@kbn/securitysolution-list-constants'; + +import type { RuleParams } from '../../rule_schema'; +import { extractExceptionsList } from './extract_exceptions_list'; import { EXCEPTIONS_SAVED_OBJECT_REFERENCE_NAME } from './utils/constants'; describe('extract_exceptions_list', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.ts index 87e607bb3b9a1..010fd04923159 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_exceptions_list.ts @@ -7,7 +7,7 @@ import type { Logger, SavedObjectReference } from '@kbn/core/server'; import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; -import type { RuleParams } from '../../schemas/rule_schemas'; +import type { RuleParams } from '../../rule_schema'; import { getSavedObjectNamePatternForExceptionsList } from './utils'; /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.test.ts index 76325e187b005..5d27540773641 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.test.ts @@ -6,12 +6,13 @@ */ import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { extractReferences } from './extract_references'; -import type { RuleParams } from '../../schemas/rule_schemas'; import { EXCEPTION_LIST_NAMESPACE, EXCEPTION_LIST_NAMESPACE_AGNOSTIC, } from '@kbn/securitysolution-list-constants'; + +import type { RuleParams } from '../../rule_schema'; +import { extractReferences } from './extract_references'; import { EXCEPTIONS_SAVED_OBJECT_REFERENCE_NAME } from './utils/constants'; describe('extract_references', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.ts index 9843223b37e89..91ceb32edfe35 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/extract_references.ts @@ -8,7 +8,7 @@ import type { Logger } from '@kbn/core/server'; import type { RuleParamsAndRefs } from '@kbn/alerting-plugin/server'; -import type { RuleParams } from '../../schemas/rule_schemas'; +import type { RuleParams } from '../../rule_schema'; import { isMachineLearningParams } from '../utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.test.ts index 4d086970e458e..d653591493a3a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.test.ts @@ -8,8 +8,9 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import type { SavedObjectReference } from '@kbn/core/server'; import { EXCEPTION_LIST_NAMESPACE } from '@kbn/securitysolution-list-constants'; + +import type { RuleParams } from '../../rule_schema'; import { injectExceptionsReferences } from './inject_exceptions_list'; -import type { RuleParams } from '../../schemas/rule_schemas'; import { EXCEPTIONS_SAVED_OBJECT_REFERENCE_NAME } from './utils/constants'; describe('inject_exceptions_list', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.ts index 84a2c30c2e7ee..3baab73f1e50f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_exceptions_list.ts @@ -6,7 +6,7 @@ */ import type { Logger, SavedObjectReference } from '@kbn/core/server'; -import type { RuleParams } from '../../schemas/rule_schemas'; +import type { RuleParams } from '../../rule_schema'; import { getSavedObjectReferenceForExceptionsList, logMissingSavedObjectError } from './utils'; /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.test.ts index 3d7b17e5b6e89..f0dba726c712c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.test.ts @@ -8,8 +8,9 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import type { SavedObjectReference } from '@kbn/core/server'; import { EXCEPTION_LIST_NAMESPACE } from '@kbn/securitysolution-list-constants'; + +import type { RuleParams } from '../../rule_schema'; import { injectReferences } from './inject_references'; -import type { RuleParams } from '../../schemas/rule_schemas'; import { EXCEPTIONS_SAVED_OBJECT_REFERENCE_NAME } from './utils/constants'; describe('inject_references', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts index bae0e0749a62b..40ad3cf3678a9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts @@ -6,7 +6,7 @@ */ import type { Logger, SavedObjectReference } from '@kbn/core/server'; -import type { RuleParams } from '../../schemas/rule_schemas'; +import type { RuleParams } from '../../rule_schema'; import { isMachineLearningParams } from '../utils'; import { injectExceptionsReferences } from './inject_exceptions_list'; import { injectDataViewReferences } from './inject_data_view'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/utils/log_missing_saved_object_error.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/utils/log_missing_saved_object_error.ts index 203d6ce342d4c..3293508e035c4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/utils/log_missing_saved_object_error.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/utils/log_missing_saved_object_error.ts @@ -6,7 +6,7 @@ */ import type { Logger } from '@kbn/core/server'; -import type { RuleParams } from '../../../schemas/rule_schemas'; +import type { RuleParams } from '../../../rule_schema'; type Keys = keyof RuleParams; type PossibleRuleParamValues = RuleParams[Keys]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts index 613104bc7604b..489237ea1b2c9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts @@ -23,12 +23,12 @@ import type { SearchListItemArraySchema } from '@kbn/securitysolution-io-ts-list import { getSearchListItemResponseMock } from '@kbn/lists-plugin/common/schemas/response/search_list_item_schema.mock'; import { getRuleRangeTuples } from './utils'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; -import { getCompleteRuleMock, getQueryRuleParams } from '../schemas/rule_schemas.mock'; +import { getCompleteRuleMock, getQueryRuleParams } from '../rule_schema/mocks'; import { bulkCreateFactory } from '../rule_types/factories/bulk_create_factory'; import { wrapHitsFactory } from '../rule_types/factories/wrap_hits_factory'; import { ruleExecutionLogMock } from '../rule_monitoring/mocks'; import type { BuildReasonMessage } from './reason_formatters'; -import type { QueryRuleParams } from '../schemas/rule_schemas'; +import type { QueryRuleParams } from '../rule_schema'; import { createPersistenceServicesMock } from '@kbn/rule-registry-plugin/server/utils/create_persistence_rule_type_wrapper.mock'; import type { PersistenceServices } from '@kbn/rule-registry-plugin/server'; import { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts index 0a0534e887c5e..04fec0e21a467 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts @@ -14,10 +14,7 @@ import type { import type { SignalSearchResponse, SignalSource } from './types'; import { buildEventsSearchQuery } from './build_events_query'; import { createErrorsFromShard, makeFloatString } from './utils'; -import type { - TimestampOverride, - TimestampOverrideOrUndefined, -} from '../../../../common/detection_engine/schemas/common/schemas'; +import type { TimestampOverride } from '../../../../common/detection_engine/rule_schema'; import { withSecuritySpan } from '../../../utils/with_security_span'; import type { IRuleExecutionLogForExecutors } from '../rule_monitoring'; @@ -33,7 +30,7 @@ interface SingleSearchAfterParams { sortOrder?: estypes.SortOrder; filter: estypes.QueryDslQueryContainer; primaryTimestamp: TimestampOverride; - secondaryTimestamp: TimestampOverrideOrUndefined; + secondaryTimestamp: TimestampOverride | undefined; trackTotalHits?: boolean; runtimeMappings: estypes.MappingRuntimeFields | undefined; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts index f9ce4479dc3ac..03175fa0dda11 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts @@ -35,7 +35,7 @@ import type { SignalsEnrichment, WrapHits, } from '../types'; -import type { CompleteRule, ThreatRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, ThreatRuleParams } from '../../rule_schema'; import type { IRuleExecutionLogForExecutors } from '../../rule_monitoring'; export type SortOrderOrUndefined = 'asc' | 'desc' | undefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/build_threshold_aggregation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/build_threshold_aggregation.ts index f0b808e743772..1bc2b18860722 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/build_threshold_aggregation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/build_threshold_aggregation.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { ThresholdNormalized } from '../../../../../common/detection_engine/schemas/common'; +import type { ThresholdNormalized } from '../../../../../common/detection_engine/rule_schema'; import { shouldFilterByCardinality } from './utils'; export const buildThresholdMultiBucketAggregation = ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts index d92bd5b360b2d..1fa0baaedfa13 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { ThresholdNormalized } from '../../../../../common/detection_engine/schemas/common/schemas'; +import type { ThresholdNormalized } from '../../../../../common/detection_engine/rule_schema'; import { calculateThresholdSignalUuid } from '../utils'; import { getTransformedHits } from './bulk_create_threshold_signals'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts index 758e69553bb4b..22ebcf8c1ced0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts @@ -12,12 +12,12 @@ import type { AlertInstanceState, RuleExecutorServices, } from '@kbn/alerting-plugin/server'; -import type { ThresholdNormalized } from '../../../../../common/detection_engine/schemas/common/schemas'; +import type { ThresholdNormalized } from '../../../../../common/detection_engine/rule_schema'; import type { GenericBulkCreateResponse } from '../../rule_types/factories/bulk_create_factory'; import { calculateThresholdSignalUuid } from '../utils'; import { buildReasonMessageForThresholdAlert } from '../reason_formatters'; import type { ThresholdSignalHistory, BulkCreate, WrapHits } from '../types'; -import type { CompleteRule, ThresholdRuleParams } from '../../schemas/rule_schemas'; +import type { CompleteRule, ThresholdRuleParams } from '../../rule_schema'; import type { BaseFieldsLatest } from '../../../../../common/detection_engine/schemas/alerts'; import type { ThresholdBucket } from './types'; import { createEnrichEventsFunction } from '../enrichments'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts index 63e293401a77a..dba72e0560734 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts @@ -17,8 +17,7 @@ import type { ESBoolQuery } from '../../../../../common/typed_json'; import type { ThresholdNormalized, TimestampOverride, - TimestampOverrideOrUndefined, -} from '../../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../../common/detection_engine/rule_schema'; import { singleSearchAfter } from '../single_search_after'; import { buildThresholdMultiBucketAggregation, @@ -43,7 +42,7 @@ interface FindThresholdSignalsParams { threshold: ThresholdNormalized; runtimeMappings: estypes.MappingRuntimeFields | undefined; primaryTimestamp: TimestampOverride; - secondaryTimestamp: TimestampOverrideOrUndefined; + secondaryTimestamp: TimestampOverride | undefined; aggregatableTimestampField: string; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/utils.ts index bcb61f04cda0d..1e1ecbc12b444 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/utils.ts @@ -8,7 +8,7 @@ import type { ThresholdNormalized, ThresholdWithCardinality, -} from '../../../../../common/detection_engine/schemas/common'; +} from '../../../../../common/detection_engine/rule_schema'; export const shouldFilterByCardinality = ( threshold: ThresholdNormalized diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts index f786a28b50044..e8dd19fd2ff8e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts @@ -26,7 +26,7 @@ import type { EqlSequence, } from '../../../../common/detection_engine/types'; import type { ITelemetryEventsSender } from '../../telemetry/sender'; -import type { RuleParams } from '../schemas/rule_schemas'; +import type { RuleParams } from '../rule_schema'; import type { GenericBulkCreateResponse } from '../rule_types/factories'; import type { BuildReasonMessage } from './reason_formatters'; import type { @@ -35,7 +35,7 @@ import type { WrappedFieldsLatest, } from '../../../../common/detection_engine/schemas/alerts'; import type { IRuleExecutionLogForExecutors } from '../rule_monitoring'; -import type { FullResponseSchema } from '../../../../common/detection_engine/schemas/request'; +import type { RuleResponse } from '../../../../common/detection_engine/rule_schema'; import type { EnrichEvents } from './enrichments/types'; export interface ThresholdResult { @@ -187,7 +187,7 @@ export interface Signal { _meta?: { version: number; }; - rule: FullResponseSchema; + rule: RuleResponse; /** * @deprecated Use "parents" instead of "parent" */ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index 24b5b068d5689..c8a98aeabd82a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -31,10 +31,8 @@ import type { } from '@kbn/alerting-plugin/server'; import { parseDuration } from '@kbn/alerting-plugin/server'; import type { ExceptionListClient, ListClient, ListPluginSetup } from '@kbn/lists-plugin/server'; -import type { - TimestampOverride, - Privilege, -} from '../../../../common/detection_engine/schemas/common'; +import type { TimestampOverride } from '../../../../common/detection_engine/rule_schema'; +import type { Privilege } from '../../../../common/detection_engine/schemas/common'; import { RuleExecutionStatus } from '../../../../common/detection_engine/rule_monitoring'; import type { BulkResponseErrorAggregation, @@ -57,7 +55,7 @@ import type { RuleParams, ThreatRuleParams, ThresholdRuleParams, -} from '../schemas/rule_schemas'; +} from '../rule_schema'; import type { BaseHit, SearchTypes } from '../../../../common/detection_engine/types'; import type { IRuleExecutionLogForExecutors } from '../rule_monitoring'; import { withSecuritySpan } from '../../../utils/with_security_span'; diff --git a/x-pack/plugins/security_solution/server/lib/machine_learning/__mocks__/authz.ts b/x-pack/plugins/security_solution/server/lib/machine_learning/__mocks__/authz.ts new file mode 100644 index 0000000000000..33ab06ba67a8f --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/machine_learning/__mocks__/authz.ts @@ -0,0 +1,14 @@ +/* + * 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 { mlPluginServerMock } from '@kbn/ml-plugin/server/mocks'; + +export const mlServicesMock = mlPluginServerMock; + +const mockValidateRuleType = jest.fn().mockResolvedValue({ valid: true, message: undefined }); + +export const buildMlAuthz = jest.fn().mockReturnValue({ validateRuleType: mockValidateRuleType }); diff --git a/x-pack/plugins/security_solution/server/lib/machine_learning/mocks.ts b/x-pack/plugins/security_solution/server/lib/machine_learning/mocks.ts index b76dba6d072ef..2a46163515958 100644 --- a/x-pack/plugins/security_solution/server/lib/machine_learning/mocks.ts +++ b/x-pack/plugins/security_solution/server/lib/machine_learning/mocks.ts @@ -8,13 +8,3 @@ import { mlPluginServerMock } from '@kbn/ml-plugin/server/mocks'; export const mlServicesMock = mlPluginServerMock; - -const mockValidateRuleType = jest.fn().mockResolvedValue({ valid: true, message: undefined }); -const createBuildMlAuthzMock = () => - jest.fn().mockReturnValue({ validateRuleType: mockValidateRuleType }); - -export const mlAuthzMock = { - create: () => ({ - buildMlAuthz: createBuildMlAuthzMock(), - }), -}; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts index 64bee51ae8965..9d32145717de6 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts @@ -41,7 +41,9 @@ export const getExportTimelinesRequest = () => }); export const getImportTimelinesRequest = async (fileName?: string) => { - const dir = resolve(join(__dirname, '../../detection_engine/rules/prepackaged_timelines')); + const dir = resolve( + join(__dirname, '../../detection_engine/prebuilt_rules/content/prepackaged_timelines') + ); const file = fileName ?? 'index.ndjson'; const dataPath = path.join(dir, file); const readable = await getReadables(dataPath); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts index 69d1b672ddcf4..b003a54657feb 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts @@ -25,7 +25,10 @@ export const installPrepackagedTimelines = async ( ): Promise => { let readStream; const dir = resolve( - join(__dirname, filePath ?? '../../../../detection_engine/rules/prepackaged_timelines') + join( + __dirname, + filePath ?? '../../../../detection_engine/prebuilt_rules/content/prepackaged_timelines' + ) ); const file = fileName ?? 'index.ndjson'; const dataPath = path.join(dir, file); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts index f742a5c6171c0..bf260085b5a75 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts @@ -66,7 +66,10 @@ export const checkTimelinesStatus = async ( timeline: TimelineSavedObject[]; }; const dir = resolve( - join(__dirname, filePath ?? '../../detection_engine/rules/prepackaged_timelines') + join( + __dirname, + filePath ?? '../../detection_engine/prebuilt_rules/content/prepackaged_timelines' + ) ); const file = fileName ?? 'index.ndjson'; const dataPath = path.join(dir, file); diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index a71048462b5e6..df584c8d64e96 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -80,9 +80,10 @@ import type { CreateQueryRuleAdditionalOptions, } from './lib/detection_engine/rule_types/types'; // eslint-disable-next-line no-restricted-imports -import { legacyRulesNotificationAlertType } from './lib/detection_engine/notifications/legacy_rules_notification_alert_type'; -// eslint-disable-next-line no-restricted-imports -import { legacyIsNotificationAlertExecutor } from './lib/detection_engine/notifications/legacy_types'; +import { + legacyRulesNotificationAlertType, + legacyIsNotificationAlertExecutor, +} from './lib/detection_engine/rule_actions_legacy'; import { createSecurityRuleTypeWrapper } from './lib/detection_engine/rule_types/create_security_rule_type_wrapper'; import { RequestContextFactory } from './request_context_factory'; diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index f9d2177aa9e10..df67c6ddce423 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -10,14 +10,17 @@ import type { IRuleDataClient, RuleDataPluginService } from '@kbn/rule-registry- import type { SecuritySolutionPluginRouter } from '../types'; -import { createRulesRoute } from '../lib/detection_engine/routes/rules/create_rules_route'; +import { registerFleetIntegrationsRoutes } from '../lib/detection_engine/fleet_integrations'; +import { registerPrebuiltRulesRoutes } from '../lib/detection_engine/prebuilt_rules'; +// eslint-disable-next-line no-restricted-imports +import { registerLegacyRuleActionsRoutes } from '../lib/detection_engine/rule_actions_legacy'; +import { registerRuleExceptionsRoutes } from '../lib/detection_engine/rule_exceptions'; +import { registerRuleManagementRoutes } from '../lib/detection_engine/rule_management'; +import { registerRuleMonitoringRoutes } from '../lib/detection_engine/rule_monitoring'; +import { registerRulePreviewRoutes } from '../lib/detection_engine/rule_preview'; + import { createIndexRoute } from '../lib/detection_engine/routes/index/create_index_route'; import { readIndexRoute } from '../lib/detection_engine/routes/index/read_index_route'; -import { readRulesRoute } from '../lib/detection_engine/routes/rules/read_rules_route'; -import { findRulesRoute } from '../lib/detection_engine/routes/rules/find_rules_route'; -import { deleteRulesRoute } from '../lib/detection_engine/routes/rules/delete_rules_route'; -import { updateRulesRoute } from '../lib/detection_engine/routes/rules/update_rules_route'; -import { patchRulesRoute } from '../lib/detection_engine/routes/rules/patch_rules_route'; import { createSignalsMigrationRoute } from '../lib/detection_engine/routes/signals/create_signals_migration_route'; import { deleteSignalsMigrationRoute } from '../lib/detection_engine/routes/signals/delete_signals_migration_route'; import { finalizeSignalsMigrationRoute } from '../lib/detection_engine/routes/signals/finalize_signals_migration_route'; @@ -25,18 +28,7 @@ import { getSignalsMigrationStatusRoute } from '../lib/detection_engine/routes/s import { querySignalsRoute } from '../lib/detection_engine/routes/signals/query_signals_route'; import { setSignalsStatusRoute } from '../lib/detection_engine/routes/signals/open_close_signals_route'; import { deleteIndexRoute } from '../lib/detection_engine/routes/index/delete_index_route'; -import { readTagsRoute } from '../lib/detection_engine/routes/tags/read_tags_route'; import { readPrivilegesRoute } from '../lib/detection_engine/routes/privileges/read_privileges_route'; -import { addPrepackedRulesRoute } from '../lib/detection_engine/routes/rules/add_prepackaged_rules_route'; -import { createRulesBulkRoute } from '../lib/detection_engine/routes/rules/create_rules_bulk_route'; -import { updateRulesBulkRoute } from '../lib/detection_engine/routes/rules/update_rules_bulk_route'; -import { patchRulesBulkRoute } from '../lib/detection_engine/routes/rules/patch_rules_bulk_route'; -import { deleteRulesBulkRoute } from '../lib/detection_engine/routes/rules/delete_rules_bulk_route'; -import { performBulkActionRoute } from '../lib/detection_engine/routes/rules/perform_bulk_action_route'; -import { importRulesRoute } from '../lib/detection_engine/routes/rules/import_rules_route'; -import { exportRulesRoute } from '../lib/detection_engine/routes/rules/export_rules_route'; -import { registerRuleMonitoringRoutes } from '../lib/detection_engine/rule_monitoring'; -import { getPrepackagedRulesStatusRoute } from '../lib/detection_engine/routes/rules/get_prepackaged_rules_status_route'; import { createTimelinesRoute, deleteTimelinesRoute, @@ -59,21 +51,15 @@ import type { SetupPlugins, StartPlugins } from '../plugin'; import type { ConfigType } from '../config'; import type { ITelemetryEventsSender } from '../lib/telemetry/sender'; import { installPrepackedTimelinesRoute } from '../lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines'; -import { previewRulesRoute } from '../lib/detection_engine/routes/rules/preview_rules_route'; import type { CreateRuleOptions, CreateSecurityRuleTypeWrapperProps, } from '../lib/detection_engine/rule_types/types'; -// eslint-disable-next-line no-restricted-imports -import { legacyCreateLegacyNotificationRoute } from '../lib/detection_engine/routes/rules/legacy_create_legacy_notification'; import { createSourcererDataViewRoute, getSourcererDataViewRoute } from '../lib/sourcerer/routes'; import type { ITelemetryReceiver } from '../lib/telemetry/receiver'; import { telemetryDetectionRulesPreviewRoute } from '../lib/detection_engine/routes/telemetry/telemetry_detection_rules_preview_route'; import { readAlertsIndexExistsRoute } from '../lib/detection_engine/routes/index/read_alerts_index_exists_route'; -import { getInstalledIntegrationsRoute } from '../lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route'; import { registerResolverRoutes } from '../endpoint/routes/resolver'; -import { findRuleExceptionReferencesRoute } from '../lib/detection_engine/routes/rules/find_rule_exceptions_route'; -import { createRuleExceptionsRoute } from '../lib/detection_engine/routes/rules/create_rule_exceptions_route'; import { createEsIndexRoute, createPrebuiltSavedObjectsRoute, @@ -86,6 +72,7 @@ import { readPrebuiltDevToolContentRoute, restartTransformRoute, } from '../lib/risk_score/routes'; + export const initRoutes = ( router: SecuritySolutionPluginRouter, config: ConfigType, @@ -102,15 +89,13 @@ export const initRoutes = ( previewRuleDataClient: IRuleDataClient, previewTelemetryReceiver: ITelemetryReceiver ) => { - // Detection Engine Rule routes that have the REST endpoints of /api/detection_engine/rules - // All REST rule creation, deletion, updating, etc - createRulesRoute(router, ml); - readRulesRoute(router, logger); - updateRulesRoute(router, ml); - patchRulesRoute(router, ml); - deleteRulesRoute(router); - findRulesRoute(router, logger); - previewRulesRoute( + registerFleetIntegrationsRoutes(router, logger); + registerLegacyRuleActionsRoutes(router, logger); + registerPrebuiltRulesRoutes(router, config, security); + registerRuleExceptionsRoutes(router); + registerRuleManagementRoutes(router, config, ml, logger); + registerRuleMonitoringRoutes(router); + registerRulePreviewRoutes( router, config, ml, @@ -121,29 +106,11 @@ export const initRoutes = ( getStartServices, logger ); - createRuleExceptionsRoute(router); - - // Once we no longer have the legacy notifications system/"side car actions" this should be removed. - legacyCreateLegacyNotificationRoute(router, logger); - - addPrepackedRulesRoute(router); - getPrepackagedRulesStatusRoute(router, config, security); - createRulesBulkRoute(router, ml, logger); - updateRulesBulkRoute(router, ml, logger); - patchRulesBulkRoute(router, ml, logger); - deleteRulesBulkRoute(router, logger); - performBulkActionRoute(router, ml, logger); - registerResolverRoutes(router, getStartServices, config); - - registerRuleMonitoringRoutes(router); - getInstalledIntegrationsRoute(router, logger); + registerResolverRoutes(router, getStartServices, config); createTimelinesRoute(router, config, security); patchTimelinesRoute(router, config, security); - importRulesRoute(router, config, ml); - exportRulesRoute(router, config, logger); - findRuleExceptionReferencesRoute(router); importTimelinesRoute(router, config, security); exportTimelinesRoute(router, config, security); @@ -177,9 +144,6 @@ export const initRoutes = ( readAlertsIndexExistsRoute(router); deleteIndexRoute(router); - // Detection Engine tags routes that have the REST endpoints of /api/detection_engine/tags - readTagsRoute(router); - // Privileges API to get the generic user privileges readPrivilegesRoute(router, hasEncryptionKey); diff --git a/x-pack/plugins/security_solution/server/saved_objects.ts b/x-pack/plugins/security_solution/server/saved_objects.ts index 225c0ad453a3d..bc1d86add3767 100644 --- a/x-pack/plugins/security_solution/server/saved_objects.ts +++ b/x-pack/plugins/security_solution/server/saved_objects.ts @@ -9,9 +9,9 @@ import type { CoreSetup } from '@kbn/core/server'; import { noteType, pinnedEventType, timelineType } from './lib/timeline/saved_object_mappings'; // eslint-disable-next-line no-restricted-imports -import { legacyType as legacyRuleActionsType } from './lib/detection_engine/rule_actions/legacy_saved_object_mappings'; +import { legacyType as legacyRuleActionsType } from './lib/detection_engine/rule_actions_legacy'; import { ruleExecutionType } from './lib/detection_engine/rule_monitoring'; -import { ruleAssetType } from './lib/detection_engine/rules/rule_asset/rule_asset_saved_object_mappings'; +import { ruleAssetType } from './lib/detection_engine/prebuilt_rules/logic/rule_asset/rule_asset_saved_object_mappings'; import { type as signalsMigrationType } from './lib/detection_engine/migrations/saved_objects'; import { exceptionsArtifactType, diff --git a/x-pack/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_id_to_enabled_map.ts b/x-pack/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_id_to_enabled_map.ts index cffe536549e9c..2a6a1e0b090c7 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_id_to_enabled_map.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_id_to_enabled_map.ts @@ -7,7 +7,7 @@ import type { SavedObjectsFindResult } from '@kbn/core/server'; // eslint-disable-next-line no-restricted-imports -import type { LegacyIRuleActionsAttributesSavedObjectAttributes } from '../../../../lib/detection_engine/rule_actions/legacy_types'; +import type { LegacyIRuleActionsAttributesSavedObjectAttributes } from '../../../../lib/detection_engine/rule_actions_legacy'; export const getRuleIdToEnabledMap = ( legacyRuleActions: Array< diff --git a/x-pack/plugins/security_solution/server/usage/get_internal_saved_objects_client.ts b/x-pack/plugins/security_solution/server/usage/get_internal_saved_objects_client.ts index 85fe139aa36c9..bb39b9c320b20 100644 --- a/x-pack/plugins/security_solution/server/usage/get_internal_saved_objects_client.ts +++ b/x-pack/plugins/security_solution/server/usage/get_internal_saved_objects_client.ts @@ -9,7 +9,7 @@ import type { CoreSetup, SavedObjectsClientContract } from '@kbn/core/server'; import { SAVED_OBJECT_TYPES } from '@kbn/cases-plugin/common/constants'; // eslint-disable-next-line no-restricted-imports -import { legacyRuleActionsSavedObjectType } from '../lib/detection_engine/rule_actions/legacy_saved_object_mappings'; +import { legacyRuleActionsSavedObjectType } from '../lib/detection_engine/rule_actions_legacy'; export async function getInternalSavedObjectsClient( core: CoreSetup diff --git a/x-pack/plugins/security_solution/server/usage/queries/legacy_get_rule_actions.ts b/x-pack/plugins/security_solution/server/usage/queries/legacy_get_rule_actions.ts index 8a3eba441d269..9b7140d734d16 100644 --- a/x-pack/plugins/security_solution/server/usage/queries/legacy_get_rule_actions.ts +++ b/x-pack/plugins/security_solution/server/usage/queries/legacy_get_rule_actions.ts @@ -12,10 +12,10 @@ import type { SavedObjectsCreatePointInTimeFinderOptions, } from '@kbn/core/server'; // eslint-disable-next-line no-restricted-imports -import type { LegacyIRuleActionsAttributesSavedObjectAttributes } from '../../lib/detection_engine/rule_actions/legacy_types'; +import type { LegacyIRuleActionsAttributesSavedObjectAttributes } from '../../lib/detection_engine/rule_actions_legacy'; // eslint-disable-next-line no-restricted-imports -import { legacyRuleActionsSavedObjectType } from '../../lib/detection_engine/rule_actions/legacy_saved_object_mappings'; +import { legacyRuleActionsSavedObjectType } from '../../lib/detection_engine/rule_actions_legacy'; export interface LegacyGetRuleActionsOptions { savedObjectsClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/security_solution/server/usage/types.ts b/x-pack/plugins/security_solution/server/usage/types.ts index a6db2e3d71e91..1c97dffab5bb1 100644 --- a/x-pack/plugins/security_solution/server/usage/types.ts +++ b/x-pack/plugins/security_solution/server/usage/types.ts @@ -7,7 +7,7 @@ import type { CoreSetup, Logger } from '@kbn/core/server'; import type { SanitizedRule } from '@kbn/alerting-plugin/common'; -import type { RuleParams } from '../lib/detection_engine/schemas/rule_schemas'; +import type { RuleParams } from '../lib/detection_engine/rule_schema'; import type { SetupPlugins } from '../plugin'; export type CollectorDependencies = { diff --git a/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts index cd1914df38561..e04ecd40ef04a 100644 --- a/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts +++ b/x-pack/plugins/security_solution/server/utils/read_stream/create_stream_from_ndjson.ts @@ -9,7 +9,7 @@ import { Transform } from 'stream'; import { has, isString } from 'lodash/fp'; import { createMapStream, createFilterStream } from '@kbn/utils'; -import type { ImportRulesSchema } from '../../../common/detection_engine/schemas/request/import_rules_schema'; +import type { RuleToImport } from '../../../common/detection_engine/rule_management'; export interface RulesObjectsExportResultDetails { /** number of successfully exported objects */ @@ -29,7 +29,7 @@ export const parseNdjsonStrings = (): Transform => { }; export const filterExportedCounts = (): Transform => { - return createFilterStream( + return createFilterStream( (obj) => obj != null && !has('exported_count', obj) ); }; diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 76e347d7a0b17..f69973fdac74f 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -47,6 +47,7 @@ { "path": "../security/tsconfig.json" }, { "path": "../spaces/tsconfig.json" }, { "path": "../threat_intelligence/tsconfig.json" }, - { "path": "../timelines/tsconfig.json" } + { "path": "../timelines/tsconfig.json" }, + { "path": "../files/tsconfig.json"} ] } diff --git a/x-pack/plugins/stack_alerts/kibana.json b/x-pack/plugins/stack_alerts/kibana.json index ff436ef53fae7..21ce302c333ee 100644 --- a/x-pack/plugins/stack_alerts/kibana.json +++ b/x-pack/plugins/stack_alerts/kibana.json @@ -15,6 +15,7 @@ "kibanaReact", "savedObjects", "data", + "dataViews", "kibanaUtils" ], "configPath": ["xpack", "stack_alerts"], diff --git a/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/index.tsx b/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/index.tsx index 92db8171450f3..d49ee6c15b83a 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/index.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/query_builder/index.tsx @@ -11,7 +11,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { fromKueryExpression, luceneStringToDsl } from '@kbn/es-query'; import type { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; -import type { DataView } from '@kbn/data-plugin/common'; +import type { DataView, DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { Query } from '@kbn/es-query'; import { QueryStringInput } from '@kbn/unified-search-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; @@ -45,6 +45,7 @@ const DEFAULT_VALUES = { interface KibanaDeps { http: HttpSetup; docLinks: DocLinksStart; + dataViews: DataViewsPublicPluginStart; uiSettings: IUiSettingsClient; notifications: CoreStart['notifications']; storage: IStorageWrapper; @@ -79,7 +80,7 @@ export const GeoContainmentAlertTypeExpression: React.FunctionComponent< boundaryNameField, } = ruleParams; - const { http, docLinks, uiSettings, notifications, storage, usageCollection } = + const { http, docLinks, uiSettings, notifications, storage, usageCollection, dataViews } = useKibana().services; const [indexPattern, _setIndexPattern] = useState({ @@ -226,6 +227,7 @@ export const GeoContainmentAlertTypeExpression: React.FunctionComponent< docLinks, uiSettings, data, + dataViews, storage, usageCollection, }} @@ -281,6 +283,7 @@ export const GeoContainmentAlertTypeExpression: React.FunctionComponent< docLinks, uiSettings, data, + dataViews, storage, usageCollection, }} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/stack/pagerduty/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/stack/pagerduty/index.ts index e2b7a6998bda3..76a19836b0cda 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/stack/pagerduty/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/stack/pagerduty/index.ts @@ -223,6 +223,20 @@ async function executor( }; } + if (response == null) { + const message = i18n.translate( + 'xpack.stackConnectors.pagerduty.unexpectedNullResponseErrorMessage', + { + defaultMessage: 'unexpected null response from pagerduty', + } + ); + return { + status: 'error', + actionId, + message, + }; + } + logger.debug(`response posting pagerduty event: ${response.status}`); if (response.status === 202) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/stack/teams/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/stack/teams/index.ts index df44d568a2f30..e2c7502311597 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/stack/teams/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/stack/teams/index.ts @@ -136,6 +136,10 @@ async function teamsExecutor( }) ); + if (result == null) { + return errorResultUnexpectedNullResponse(actionId); + } + if (isOk(result)) { const { value: { status, statusText, data: responseData, headers: responseHeaders }, @@ -206,6 +210,17 @@ function errorResultInvalid( }; } +function errorResultUnexpectedNullResponse(actionId: string): ConnectorTypeExecutorResult { + const message = i18n.translate('xpack.stackConnectors.teams.unexpectedNullResponseErrorMessage', { + defaultMessage: 'unexpected null response from Microsoft Teams', + }); + return { + status: 'error', + actionId, + message, + }; +} + function retryResult(actionId: string, message: string): ConnectorTypeExecutorResult { const errMessage = i18n.translate( 'xpack.stackConnectors.teams.errorPostingRetryLaterErrorMessage', diff --git a/x-pack/plugins/stack_connectors/server/connector_types/stack/webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/stack/webhook/index.ts index 0656cb0692e37..d51ed935980bd 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/stack/webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/stack/webhook/index.ts @@ -184,6 +184,10 @@ export async function executor( }) ); + if (result == null) { + return errorResultUnexpectedNullResponse(actionId); + } + if (isOk(result)) { const { value: { status, statusText }, @@ -280,6 +284,20 @@ function errorResultUnexpectedError(actionId: string): ConnectorTypeExecutorResu }; } +function errorResultUnexpectedNullResponse(actionId: string): ConnectorTypeExecutorResult { + const message = i18n.translate( + 'xpack.stackConnectors.webhook.unexpectedNullResponseErrorMessage', + { + defaultMessage: 'unexpected null response from webhook', + } + ); + return { + status: 'error', + actionId, + message, + }; +} + function retryResult(actionId: string, serviceMessage: string): ConnectorTypeExecutorResult { const errMessage = i18n.translate( 'xpack.stackConnectors.webhook.invalidResponseRetryLaterErrorMessage', diff --git a/x-pack/plugins/stack_connectors/server/connector_types/stack/xmatters/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/stack/xmatters/index.ts index b34e300a496ed..7a3d701b96242 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/stack/xmatters/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/stack/xmatters/index.ts @@ -274,6 +274,20 @@ export async function executor( }; } + if (result == null) { + const message = i18n.translate( + 'xpack.stackConnectors.xmatters.unexpectedNullResponseErrorMessage', + { + defaultMessage: 'unexpected null response from xmatters', + } + ); + return { + status: 'error', + actionId, + message, + }; + } + if (result.status >= 200 && result.status < 300) { const { status, statusText } = result; logger.debug(`Response from xMatters action "${actionId}": [HTTP ${status}] ${statusText}`); diff --git a/x-pack/plugins/synthetics/common/constants/rest_api.ts b/x-pack/plugins/synthetics/common/constants/rest_api.ts index 0f43ff654c77e..33bd608d8f5ec 100644 --- a/x-pack/plugins/synthetics/common/constants/rest_api.ts +++ b/x-pack/plugins/synthetics/common/constants/rest_api.ts @@ -48,6 +48,6 @@ export enum API_URLS { SYNTHETICS_HAS_ZIP_URL_MONITORS = '/internal/uptime/fleet/has_zip_url_monitors', // Project monitor public endpoint - SYNTHETICS_MONITORS_PROJECT_LEGACY = '/api/synthetics/service/project/monitors', SYNTHETICS_MONITORS_PROJECT = '/api/synthetics/project/{projectName}/monitors', + SYNTHETICS_MONITORS_PROJECT_LEGACY = '/api/synthetics/service/project/monitors', } diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx index f16a570f6f812..12443d7896c04 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import React, { MouseEvent, useMemo, useState } from 'react'; import { EuiBasicTable, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; +import { useKibanaDateFormat } from '../../../../../hooks/use_kibana_date_format'; import { Ping } from '../../../../../../common/runtime_types'; import { useErrorFailedStep } from '../hooks/use_error_failed_step'; import { @@ -42,6 +43,8 @@ export const ErrorsList = () => { const history = useHistory(); + const format = useKibanaDateFormat(); + const columns = [ { field: '@timestamp', @@ -50,7 +53,7 @@ export const ErrorsList = () => { render: (value: string, item: Ping) => { return ( - {formatTestRunAt(item.state!.started_at)} + {formatTestRunAt(item.state!.started_at, format)} ); }, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_ten_test_runs.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_ten_test_runs.tsx index a424a831c97ff..eddf40739e55d 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_ten_test_runs.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_ten_test_runs.tsx @@ -36,6 +36,7 @@ import { parseBadgeStatus, StatusBadge } from '../../common/monitor_test_result/ import { isStepEnd } from '../../common/monitor_test_result/browser_steps_list'; import { JourneyStepScreenshotContainer } from '../../common/monitor_test_result/journey_step_screenshot_container'; +import { useKibanaDateFormat } from '../../../../../hooks/use_kibana_date_format'; import { useSelectedMonitor } from '../hooks/use_selected_monitor'; import { useJourneySteps } from '../hooks/use_journey_steps'; @@ -118,6 +119,7 @@ export const LastTenTestRuns = () => { }, ]; + const historyIdParam = monitor?.[ConfigKey.CUSTOM_HEARTBEAT_ID] ?? monitor?.[ConfigKey.ID]; return ( @@ -133,7 +135,8 @@ export const LastTenTestRuns = () => { iconType="list" iconSide="left" data-test-subj="monitorSummaryViewLastTestRun" - href={`${basePath}/app/uptime/monitor/${btoa(monitor?.id ?? '')}`} + disabled={!historyIdParam} + href={`${basePath}/app/uptime/monitor/${btoa(historyIdParam ?? '')}`} > {i18n.translate('xpack.synthetics.monitorDetails.summary.viewHistory', { defaultMessage: 'View History', @@ -205,9 +208,10 @@ const TestDetailsLink = ({ const { euiTheme } = useEuiTheme(); const { basePath } = useSyntheticsSettingsContext(); + const format = useKibanaDateFormat(); const timestampText = ( - {formatTestRunAt(timestamp)} + {formatTestRunAt(timestamp, format)} ); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx index 76d8e5c216f01..a3e2bb6796d3b 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx @@ -36,6 +36,7 @@ import { BrowserStepsList } from '../../common/monitor_test_result/browser_steps import { SinglePingResult } from '../../common/monitor_test_result/single_ping_result'; import { parseBadgeStatus, StatusBadge } from '../../common/monitor_test_result/status_badge'; +import { useKibanaDateFormat } from '../../../../../hooks/use_kibana_date_format'; import { useJourneySteps } from '../hooks/use_journey_steps'; import { useSelectedMonitor } from '../hooks/use_selected_monitor'; @@ -103,9 +104,11 @@ const PanelHeader = ({ const { basePath } = useSyntheticsSettingsContext(); + const format = useKibanaDateFormat(); + const lastRunTimestamp = useMemo( - () => (latestPing?.timestamp ? formatTestRunAt(latestPing?.timestamp) : ''), - [latestPing?.timestamp] + () => (latestPing?.timestamp ? formatTestRunAt(latestPing?.timestamp, format) : ''), + [latestPing?.timestamp, format] ); const isBrowserMonitor = monitor?.[ConfigKey.MONITOR_TYPE] === DataStream.BROWSER; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_status.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_status.tsx index fd7583fe02fab..065b6a08f23e3 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_status.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_status.tsx @@ -9,8 +9,13 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer, EuiStat, EuiTitle } fro import { i18n } from '@kbn/i18n'; import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { clearOverviewStatusErrorAction, selectOverviewStatus } from '../../../../state'; +import { + clearOverviewStatusErrorAction, + fetchOverviewStatusAction, + selectOverviewStatus, +} from '../../../../state'; import { kibanaService } from '../../../../../../utils/kibana_service'; +import { useSyntheticsRefreshContext } from '../../../../contexts'; function title(t?: number) { return t ?? '-'; @@ -20,6 +25,12 @@ export function OverviewStatus() { const { status, statusError } = useSelector(selectOverviewStatus); const dispatch = useDispatch(); + const { lastRefresh } = useSyntheticsRefreshContext(); + + useEffect(() => { + dispatch(fetchOverviewStatusAction.get()); + }, [dispatch, lastRefresh]); + useEffect(() => { if (statusError) { dispatch(clearOverviewStatusErrorAction()); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx index 893850e76cb84..4eb864e7a2a3c 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx @@ -14,7 +14,6 @@ import { useEnablement } from '../../../hooks'; import { useSyntheticsRefreshContext } from '../../../contexts/synthetics_refresh_context'; import { fetchMonitorOverviewAction, - fetchOverviewStatusAction, selectOverviewState, selectServiceLocationsState, } from '../../../state'; @@ -53,7 +52,6 @@ export const OverviewPage: React.FC = () => { useEffect(() => { dispatch(fetchMonitorOverviewAction.get(pageState)); - dispatch(fetchOverviewStatusAction.get()); }, [dispatch, pageState]); const { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts b/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts index 33b62a6c65c27..ce9be57fe313d 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts @@ -6,7 +6,6 @@ */ import moment from 'moment'; -import { i18n } from '@kbn/i18n'; /** * Formats the microseconds (µ) into either milliseconds (ms) or seconds (s) based on the duration value @@ -31,27 +30,7 @@ export const formatTestDuration = (duration = 0, isMilli = false) => { return `${(duration / 1000).toFixed(0)} ms`; }; -export function formatTestRunAt(timestamp: string) { +export function formatTestRunAt(timestamp: string, format: string) { const stampedMoment = moment(timestamp); - const startOfToday = moment().startOf('day'); - const startOfYesterday = moment().add(-1, 'day'); - - const dateStr = - stampedMoment > startOfToday - ? `${TODAY_LABEL}` - : stampedMoment > startOfYesterday - ? `${YESTERDAY_LABEL}` - : `${stampedMoment.format('ll')} `; - - const timeStr = stampedMoment.format('HH:mm:ss'); - - return `${dateStr} @ ${timeStr}`; + return stampedMoment.format(format); } - -const TODAY_LABEL = i18n.translate('xpack.synthetics.monitorDetails.summary.today', { - defaultMessage: 'Today', -}); - -const YESTERDAY_LABEL = i18n.translate('xpack.synthetics.monitorDetails.summary.yesterday', { - defaultMessage: 'Yesterday', -}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_bulk_schema.ts b/x-pack/plugins/synthetics/public/hooks/use_kibana_date_format.ts similarity index 53% rename from x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_bulk_schema.ts rename to x-pack/plugins/synthetics/public/hooks/use_kibana_date_format.ts index 0472c62228c4d..1391933d94304 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_bulk_schema.ts +++ b/x-pack/plugins/synthetics/public/hooks/use_kibana_date_format.ts @@ -5,9 +5,10 @@ * 2.0. */ -import * as t from 'io-ts'; +import { kibanaService } from '../utils/kibana_service'; -import { patchRulesSchema } from './patch_rules_schema'; +const DEFAULT_FORMAT = 'MMM D, YYYY @ HH:mm:ss.SSS'; -export const patchRulesBulkSchema = t.array(patchRulesSchema); -export type PatchRulesBulkSchema = t.TypeOf; +export function useKibanaDateFormat() { + return kibanaService.core.uiSettings.get('dateFormat', DEFAULT_FORMAT); +} diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/alert_query_bar/query_bar.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/alert_query_bar/query_bar.tsx index f8ed9cb99fb7c..48932b5789743 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/alert_query_bar/query_bar.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/alerts/alert_query_bar/query_bar.tsx @@ -31,6 +31,7 @@ export const AlertQueryBar = ({ query = '', onChange }: Props) => { docLinks, uiSettings, data, + dataViews, unifiedSearch, storage, usageCollection, @@ -72,6 +73,7 @@ export const AlertQueryBar = ({ query = '', onChange }: Props) => { deps={{ unifiedSearch, data, + dataViews, storage, notifications, http, diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/query_bar/query_bar.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/query_bar/query_bar.tsx index 5ca63c2a758e6..139952c5c6302 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/query_bar/query_bar.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/query_bar/query_bar.tsx @@ -43,6 +43,7 @@ export const QueryBar = () => { docLinks, uiSettings, data, + dataViews, unifiedSearch, storage, usageCollection, @@ -100,6 +101,7 @@ export const QueryBar = () => { docLinks, uiSettings, data, + dataViews, storage, usageCollection, }} diff --git a/x-pack/plugins/synthetics/server/routes/common.ts b/x-pack/plugins/synthetics/server/routes/common.ts index 84a1a294f27e6..3ca580fb2da82 100644 --- a/x-pack/plugins/synthetics/server/routes/common.ts +++ b/x-pack/plugins/synthetics/server/routes/common.ts @@ -51,9 +51,9 @@ export const getMonitors = ( const locationFilter = parseLocationFilter(syntheticsService.locations, locations); const filters = - getFilter('tags', tags) + - getFilter('type', monitorType) + - getFilter('locations.id', locationFilter); + getKqlFilter('tags', tags) + + getKqlFilter('type', monitorType) + + getKqlFilter('locations.id', locationFilter); return savedObjectsClient.find({ type: syntheticsMonitorType, @@ -69,7 +69,7 @@ export const getMonitors = ( }); }; -const getFilter = (field: string, values?: string | string[], operator = 'OR') => { +export const getKqlFilter = (field: string, values?: string | string[], operator = 'OR') => { if (!values) { return ''; } diff --git a/x-pack/plugins/synthetics/server/routes/index.ts b/x-pack/plugins/synthetics/server/routes/index.ts index 8cff5dc88c918..c1c06215c8c16 100644 --- a/x-pack/plugins/synthetics/server/routes/index.ts +++ b/x-pack/plugins/synthetics/server/routes/index.ts @@ -18,6 +18,7 @@ import { getSyntheticsMonitorOverviewRoute, getSyntheticsMonitorRoute, } from './monitor_cruds/get_monitor'; +import { deleteSyntheticsMonitorProjectRoute } from './monitor_cruds/delete_monitor_project'; import { getSyntheticsProjectMonitorsRoute } from './monitor_cruds/get_monitor_project'; import { runOnceSyntheticsMonitorRoute } from './synthetics_service/run_once_monitor'; import { getServiceAllowedRoute } from './synthetics_service/get_service_allowed'; @@ -38,6 +39,7 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ addSyntheticsMonitorRoute, getSyntheticsEnablementRoute, deleteSyntheticsMonitorRoute, + deleteSyntheticsMonitorProjectRoute, disableSyntheticsRoute, editSyntheticsMonitorRoute, enableSyntheticsRoute, diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts index c156c73342cc1..862bab6915f36 100644 --- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts @@ -10,7 +10,13 @@ import { formatTelemetryDeleteEvent, sendTelemetryEvents, } from '../../telemetry/monitor_upgrade_sender'; -import { ConfigKey, MonitorFields, SyntheticsMonitor } from '../../../../common/runtime_types'; +import { + ConfigKey, + MonitorFields, + SyntheticsMonitor, + EncryptedSyntheticsMonitor, + EncryptedSyntheticsMonitorWithId, +} from '../../../../common/runtime_types'; import { UptimeServerSetup } from '../../../legacy_uptime/lib/adapters'; import { SyntheticsMonitorClient } from '../../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; import { syntheticsMonitorType } from '../../../../common/types/saved_objects'; @@ -24,7 +30,7 @@ export const deleteMonitorBulk = async ({ }: { savedObjectsClient: SavedObjectsClientContract; server: UptimeServerSetup; - monitors: Array>; + monitors: Array>; syntheticsMonitorClient: SyntheticsMonitorClient; request: KibanaRequest; }) => { @@ -35,10 +41,8 @@ export const deleteMonitorBulk = async ({ const deleteSyncPromise = syntheticsMonitorClient.deleteMonitors( monitors.map((normalizedMonitor) => ({ ...normalizedMonitor.attributes, - id: - (normalizedMonitor.attributes as MonitorFields)[ConfigKey.CUSTOM_HEARTBEAT_ID] || - normalizedMonitor.id, - })), + id: normalizedMonitor.attributes[ConfigKey.CUSTOM_HEARTBEAT_ID] || normalizedMonitor.id, + })) as EncryptedSyntheticsMonitorWithId[], request, savedObjectsClient, spaceId diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts new file mode 100644 index 0000000000000..3deb7a1be2170 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { schema } from '@kbn/config-schema'; +import { i18n } from '@kbn/i18n'; +import { ConfigKey } from '../../../common/runtime_types'; +import { SyntheticsRestApiRouteFactory } from '../../legacy_uptime/routes/types'; +import { API_URLS } from '../../../common/constants'; +import { syntheticsMonitorType } from '../../legacy_uptime/lib/saved_objects/synthetics_monitor'; +import { getMonitors, getKqlFilter } from '../common'; +import { INSUFFICIENT_FLEET_PERMISSIONS } from '../../synthetics_service/project_monitor/project_monitor_formatter'; +import { deleteMonitorBulk } from './bulk_cruds/delete_monitor_bulk'; + +export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory = () => ({ + method: 'DELETE', + path: API_URLS.SYNTHETICS_MONITORS_PROJECT, + validate: { + body: schema.object({ + monitors: schema.arrayOf(schema.string()), + }), + params: schema.object({ + projectName: schema.string(), + }), + }, + handler: async ({ + request, + response, + savedObjectsClient, + server, + syntheticsMonitorClient, + }): Promise => { + const { projectName } = request.params; + const { monitors: monitorsToDelete } = request.body; + const decodedProjectName = decodeURI(projectName); + if (monitorsToDelete.length > 250) { + return response.badRequest({ + body: { + message: REQUEST_TOO_LARGE, + }, + }); + } + + const { saved_objects: monitors } = await getMonitors( + { + filter: `${syntheticsMonitorType}.attributes.${ + ConfigKey.PROJECT_ID + }: "${decodedProjectName}" AND ${getKqlFilter( + 'journey_id', + monitorsToDelete.map((id: string) => `"${id}"`) + )}`, + fields: [], + perPage: 500, + }, + syntheticsMonitorClient.syntheticsService, + savedObjectsClient + ); + + const { + integrations: { writeIntegrationPolicies }, + } = await server.fleet.authz.fromRequest(request); + + const hasPrivateMonitor = monitors.some((monitor) => + monitor.attributes.locations.some((location) => !location.isServiceManaged) + ); + + if (!writeIntegrationPolicies && hasPrivateMonitor) { + return response.forbidden({ + body: { + message: INSUFFICIENT_FLEET_PERMISSIONS, + }, + }); + } + + await deleteMonitorBulk({ + monitors, + server, + savedObjectsClient, + syntheticsMonitorClient, + request, + }); + + return { + deleted_monitors: monitorsToDelete, + }; + }, +}); + +export const REQUEST_TOO_LARGE = i18n.translate('xpack.synthetics.server.project.delete.toolarge', { + defaultMessage: + 'Delete request payload is too large. Please send a max of 250 monitors to delete per request', +}); diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts index 16cbf3f33a8aa..6139b2fbe7959 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts @@ -6,13 +6,14 @@ */ import type { Subject } from 'rxjs'; import { isEqual } from 'lodash'; +import pMap from 'p-map'; import { KibanaRequest } from '@kbn/core/server'; import { SavedObjectsUpdateResponse, SavedObjectsClientContract, SavedObjectsFindResult, } from '@kbn/core/server'; -import pMap from 'p-map'; +import { i18n } from '@kbn/i18n'; import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; import { syncNewMonitorBulk } from '../../routes/monitor_cruds/bulk_cruds/add_monitor_bulk'; import { deleteMonitorBulk } from '../../routes/monitor_cruds/bulk_cruds/delete_monitor_bulk'; @@ -50,8 +51,13 @@ interface StaleMonitor { type StaleMonitorMap = Record; type FailedError = Array<{ id?: string; reason: string; details: string; payload?: object }>; -export const INSUFFICIENT_FLEET_PERMISSIONS = - 'Insufficient permissions. In order to configure private locations, you must have Fleet and Integrations write permissions. To resolve, please generate a new API key with a user who has Fleet and Integrations write permissions.'; +export const INSUFFICIENT_FLEET_PERMISSIONS = i18n.translate( + 'xpack.synthetics.service.projectMonitors.insufficientFleetPermissions', + { + defaultMessage: + 'Insufficient permissions. In order to configure private locations, you must have Fleet and Integrations write permissions. To resolve, please generate a new API key with a user who has Fleet and Integrations write permissions.', + } +); export class ProjectMonitorFormatter { private projectId: string; diff --git a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_monitor/synthetics_monitor_client.ts b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_monitor/synthetics_monitor_client.ts index 8af7fca704ab0..8218a6f0b3baf 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_monitor/synthetics_monitor_client.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_monitor/synthetics_monitor_client.ts @@ -13,6 +13,7 @@ import { ConfigKey, MonitorFields, SyntheticsMonitorWithId, + EncryptedSyntheticsMonitorWithId, HeartbeatConfig, PrivateLocation, EncryptedSyntheticsMonitor, @@ -120,19 +121,23 @@ export class SyntheticsMonitorClient { } } async deleteMonitors( - monitors: SyntheticsMonitorWithId[], + monitors: Array, request: KibanaRequest, savedObjectsClient: SavedObjectsClientContract, spaceId: string ) { + /* Type cast encrypted saved objects to decrypted saved objects for delete flow only. + * Deletion does not require all monitor fields */ const privateDeletePromise = this.privateLocationAPI.deleteMonitors( - monitors, + monitors as SyntheticsMonitorWithId[], request, savedObjectsClient, spaceId ); - const publicDeletePromise = this.syntheticsService.deleteConfigs(monitors); + const publicDeletePromise = this.syntheticsService.deleteConfigs( + monitors as SyntheticsMonitorWithId[] + ); const [pubicResponse] = await Promise.all([publicDeletePromise, privateDeletePromise]); return pubicResponse; diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 7b850a44528fd..5eb2c8d5a5869 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -9355,6 +9355,36 @@ "type": "integer" } } + }, + "osquery-pack": { + "properties": { + "usedTags": { + "type": "integer" + }, + "taggedObjects": { + "type": "integer" + } + } + }, + "osquery-pack-asset": { + "properties": { + "usedTags": { + "type": "integer" + }, + "taggedObjects": { + "type": "integer" + } + } + }, + "osquery-saved-query": { + "properties": { + "usedTags": { + "type": "integer" + }, + "taggedObjects": { + "type": "integer" + } + } } } } diff --git a/x-pack/plugins/timelines/common/types/timeline/actions/index.ts b/x-pack/plugins/timelines/common/types/timeline/actions/index.ts index 4cac68268abcc..cde9b04d0e707 100644 --- a/x-pack/plugins/timelines/common/types/timeline/actions/index.ts +++ b/x-pack/plugins/timelines/common/types/timeline/actions/index.ts @@ -92,7 +92,6 @@ export interface BulkActionsProps { onUpdateSuccess?: OnUpdateAlertStatusSuccess; onUpdateFailure?: OnUpdateAlertStatusError; customBulkActions?: CustomBulkActionProp[]; - scopeId?: string; } export interface HeaderActionProps { diff --git a/x-pack/plugins/timelines/public/components/index.tsx b/x-pack/plugins/timelines/public/components/index.tsx index 296e7841aa379..cc8446eea1411 100644 --- a/x-pack/plugins/timelines/public/components/index.tsx +++ b/x-pack/plugins/timelines/public/components/index.tsx @@ -6,18 +6,16 @@ */ import React from 'react'; -import { Provider } from 'react-redux'; import { I18nProvider } from '@kbn/i18n-react'; import type { Store } from 'redux'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import { createStore } from '../store/t_grid'; +import { Provider } from 'react-redux'; import { TGrid as TGridComponent } from './t_grid'; import type { TGridProps } from '../types'; import { DragDropContextWrapper } from './drag_and_drop'; -import { initialTGridState } from '../store/t_grid/reducer'; import type { TGridIntegratedProps } from './t_grid/integrated'; const EMPTY_BROWSER_FIELDS = {}; @@ -31,18 +29,13 @@ type TGridComponent = TGridProps & { export const TGrid = (props: TGridComponent) => { const { store, storage, setStore, ...tGridProps } = props; - let tGridStore = store; - if (!tGridStore && props.type === 'standalone') { - tGridStore = createStore(initialTGridState, storage); - setStore(tGridStore); - } let browserFields = EMPTY_BROWSER_FIELDS; if ((tGridProps as TGridIntegratedProps).browserFields != null) { browserFields = (tGridProps as TGridIntegratedProps).browserFields; } return ( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - + diff --git a/x-pack/plugins/timelines/public/components/t_grid/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/index.tsx index 058261e6386cc..7512edb776398 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/index.tsx @@ -9,13 +9,10 @@ import React from 'react'; import type { TGridProps } from '../../types'; import { TGridIntegrated, TGridIntegratedProps } from './integrated'; -import { TGridStandalone, TGridStandaloneProps } from './standalone'; export const TGrid = (props: TGridProps) => { const { type, ...componentsProps } = props; - if (type === 'standalone') { - return ; - } else if (type === 'embedded') { + if (type === 'embedded') { return ; } return null; diff --git a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx deleted file mode 100644 index 035027294f30f..0000000000000 --- a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx +++ /dev/null @@ -1,394 +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 { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; -import { isEmpty } from 'lodash/fp'; -import React, { useEffect, useMemo } from 'react'; -import styled from 'styled-components'; -import { useDispatch } from 'react-redux'; -import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { Filter, Query } from '@kbn/es-query'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { CoreStart } from '@kbn/core/public'; -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import { getEsQueryConfig } from '@kbn/data-plugin/common'; - -import type { Ecs } from '../../../../common/ecs'; -import { Direction, EntityType } from '../../../../common/search_strategy'; -import { TGridCellAction } from '../../../../common/types/timeline'; -import type { - CellValueElementProps, - ColumnHeaderOptions, - ControlColumnProps, - DataProvider, - RowRenderer, - SortColumnTable, - BulkActionsProp, - AlertStatus, -} from '../../../../common/types/timeline'; -import { useDeepEqualSelector } from '../../../hooks/use_selector'; -import { defaultHeaders } from '../body/column_headers/default_headers'; -import { getCombinedFilterQuery } from '../helpers'; -import { tGridActions, tGridSelectors } from '../../../store/t_grid'; -import type { State } from '../../../store/t_grid'; -import { useTimelineEvents } from '../../../container'; -import { StatefulBody } from '../body'; -import { LastUpdatedAt } from '../..'; -import { SELECTOR_TIMELINE_GLOBAL_CONTAINER, UpdatedFlexItem, UpdatedFlexGroup } from '../styles'; -import { InspectButton, InspectButtonContainer } from '../../inspect'; -import { useFetchIndex } from '../../../container/source'; -import { TGridLoading, TGridEmpty, TableContext } from '../shared'; - -const FullWidthFlexGroup = styled(EuiFlexGroup)<{ $visible: boolean }>` - overflow: hidden; - margin: 0; - display: ${({ $visible }) => ($visible ? 'flex' : 'none')}; -`; - -export const EVENTS_VIEWER_HEADER_HEIGHT = 90; // px -export const STANDALONE_ID = 'standalone-t-grid'; -const EMPTY_DATA_PROVIDERS: DataProvider[] = []; - -const TitleText = styled.span` - margin-right: 12px; -`; - -const AlertsTableWrapper = styled.div` - width: 100%; - height: 100%; -`; - -const EventsContainerLoading = styled.div.attrs(({ className = '' }) => ({ - className: `${SELECTOR_TIMELINE_GLOBAL_CONTAINER} ${className}`, -}))` - position: relative; - width: 100%; - overflow: hidden; - flex: 1; - display: flex; - flex-direction: column; -`; - -const ScrollableFlexItem = styled(EuiFlexItem)` - overflow: auto; -`; - -export interface TGridStandaloneProps { - columns: ColumnHeaderOptions[]; - dataViewId?: string | null; - defaultCellActions?: TGridCellAction[]; - deletedEventIds: Readonly; - disabledCellActions: string[]; - end: string; - entityType?: EntityType; - loadingText: React.ReactNode; - filters: Filter[]; - filterStatus?: AlertStatus; - getRowRenderer?: ({ - data, - rowRenderers, - }: { - data: Ecs; - rowRenderers: RowRenderer[]; - }) => RowRenderer | null; - hasAlertsCrudPermissions: ({ - ruleConsumer, - ruleProducer, - }: { - ruleConsumer: string; - ruleProducer?: string; - }) => boolean; - height?: number; - indexNames: string[]; - itemsPerPage?: number; - itemsPerPageOptions: number[]; - query: Query; - onRuleChange?: () => void; - onStateChange?: (state: State) => void; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - rowRenderers: RowRenderer[]; - runtimeMappings: MappingRuntimeFields; - setRefetch: (ref: () => void) => void; - start: string; - sort: SortColumnTable[]; - graphEventId?: string; - leadingControlColumns: ControlColumnProps[]; - trailingControlColumns: ControlColumnProps[]; - bulkActions?: BulkActionsProp; - data?: DataPublicPluginStart; - unit?: (total: number) => React.ReactNode; - showCheckboxes?: boolean; - queryFields?: string[]; -} - -const TGridStandaloneComponent: React.FC = ({ - columns, - dataViewId = null, - defaultCellActions, - deletedEventIds, - disabledCellActions, - end, - entityType = 'alerts', - loadingText, - filters, - filterStatus, - getRowRenderer, - hasAlertsCrudPermissions, - indexNames, - itemsPerPage, - itemsPerPageOptions, - onRuleChange, - query, - renderCellValue, - rowRenderers, - runtimeMappings, - setRefetch, - start, - sort, - graphEventId, - leadingControlColumns, - trailingControlColumns, - data, - unit, - showCheckboxes = true, - bulkActions = {}, - queryFields = [], -}) => { - const dispatch = useDispatch(); - const columnsHeader = isEmpty(columns) ? defaultHeaders : columns; - const { uiSettings } = useKibana().services; - const [indexPatternsLoading, { browserFields, indexPatterns }] = useFetchIndex(indexNames); - - const getTGrid = useMemo(() => tGridSelectors.getTGridByIdSelector(), []); - const { - itemsPerPage: itemsPerPageStore, - itemsPerPageOptions: itemsPerPageOptionsStore, - queryFields: queryFieldsFromState, - sort: sortStore, - title, - } = useDeepEqualSelector((state) => getTGrid(state, STANDALONE_ID ?? '')); - - const justTitle = useMemo(() => {title}, [title]); - const esQueryConfig = getEsQueryConfig(uiSettings); - - const filterQuery = useMemo( - () => - getCombinedFilterQuery({ - config: esQueryConfig, - browserFields, - dataProviders: EMPTY_DATA_PROVIDERS, - filters, - from: start, - indexPattern: indexPatterns, - kqlMode: 'search', - kqlQuery: query, - to: end, - }), - [esQueryConfig, indexPatterns, browserFields, filters, start, end, query] - ); - - const canQueryTimeline = useMemo( - () => - filterQuery != null && - indexPatternsLoading != null && - !indexPatternsLoading && - !isEmpty(start) && - !isEmpty(end), - [indexPatternsLoading, filterQuery, start, end] - ); - - const fields = useMemo( - () => [ - ...columnsHeader.reduce( - (acc, c) => (c.linkField != null ? [...acc, c.id, c.linkField] : [...acc, c.id]), - [] - ), - ...(queryFieldsFromState ?? []), - ], - [columnsHeader, queryFieldsFromState] - ); - - const sortField = useMemo( - () => - sortStore.map(({ columnId, columnType, esTypes, sortDirection }) => ({ - field: columnId, - type: columnType, - direction: sortDirection as Direction, - esTypes: esTypes ?? [], - })), - [sortStore] - ); - - const [ - loading, - { consumers, events, updatedAt, loadPage, pageInfo, refetch, totalCount = 0, inspect }, - ] = useTimelineEvents({ - dataViewId, - entityType, - excludeEcsData: true, - fields, - filterQuery, - id: STANDALONE_ID, - indexNames, - limit: itemsPerPageStore, - runtimeMappings, - sort: sortField, - startDate: start, - endDate: end, - skip: !canQueryTimeline, - data, - }); - setRefetch(refetch); - - useEffect(() => { - dispatch(tGridActions.updateIsLoading({ id: STANDALONE_ID, isLoading: loading })); - }, [dispatch, loading]); - - const { hasAlertsCrud, totalSelectAllAlerts } = useMemo(() => { - return Object.entries(consumers).reduce<{ - hasAlertsCrud: boolean; - totalSelectAllAlerts: number; - }>( - (acc, [ruleConsumer, nbrAlerts]) => { - const featureHasPermission = hasAlertsCrudPermissions({ ruleConsumer }); - return { - hasAlertsCrud: featureHasPermission || acc.hasAlertsCrud, - totalSelectAllAlerts: featureHasPermission - ? nbrAlerts + acc.totalSelectAllAlerts - : acc.totalSelectAllAlerts, - }; - }, - { - hasAlertsCrud: false, - totalSelectAllAlerts: 0, - } - ); - }, [consumers, hasAlertsCrudPermissions]); - - const totalCountMinusDeleted = useMemo( - () => (totalCount > 0 ? totalCount - deletedEventIds.length : 0), - [deletedEventIds.length, totalCount] - ); - const hasAlerts = totalCountMinusDeleted > 0; - - // Only show the table-spanning loading indicator when the query is loading and we - // don't have data (e.g. for the initial fetch). - // Subsequent fetches (e.g. for pagination) will show a small loading indicator on - // top of the table and the table will display the current page until the next page - // is fetched. This prevents a flicker when paginating. - const showFullLoading = loading && !hasAlerts; - - const nonDeletedEvents = useMemo( - () => events.filter((e) => !deletedEventIds.includes(e._id)), - [deletedEventIds, events] - ); - - useEffect(() => { - dispatch( - tGridActions.createTGrid({ - id: STANDALONE_ID, - columns, - indexNames, - itemsPerPage: itemsPerPage || itemsPerPageStore, - itemsPerPageOptions, - showCheckboxes, - defaultColumns: columns, - sort, - }) - ); - dispatch( - tGridActions.initializeTGridSettings({ - id: STANDALONE_ID, - defaultColumns: columns, - sort, - loadingText, - unit, - queryFields, - }) - ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const tableContext = { tableId: STANDALONE_ID }; - - // Clear checkbox selection when new events are fetched - useEffect(() => { - dispatch(tGridActions.clearSelected({ id: STANDALONE_ID })); - dispatch( - tGridActions.setTGridSelectAll({ - id: STANDALONE_ID, - selectAll: false, - }) - ); - }, [nonDeletedEvents, dispatch]); - - return ( - - - {showFullLoading && } - {canQueryTimeline ? ( - - - - - - - - - - - - {!hasAlerts && !loading && } - - {hasAlerts && ( - - - - - - )} - - - ) : null} - - - ); -}; - -export const TGridStandalone = React.memo(TGridStandaloneComponent); diff --git a/x-pack/plugins/timelines/public/components/t_grid/toolbar/bulk_actions/alert_bulk_actions.tsx b/x-pack/plugins/timelines/public/components/t_grid/toolbar/bulk_actions/alert_bulk_actions.tsx index ab77bd06e93e1..f03c9802d44b2 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/toolbar/bulk_actions/alert_bulk_actions.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/toolbar/bulk_actions/alert_bulk_actions.tsx @@ -127,7 +127,6 @@ export const AlertBulkActionsComponent = React.memo { - const { updateAlertStatus } = useUpdateAlertsStatus(scopeId !== STANDALONE_ID); + const { updateAlertStatus } = useUpdateAlertsStatus(true); const { addSuccess, addError, addWarning } = useAppToasts(); const { startTransaction } = useStartTransaction(); diff --git a/x-pack/plugins/timelines/public/methods/index.tsx b/x-pack/plugins/timelines/public/methods/index.tsx index 3605f07cc09a2..92d6bc5a8bd3b 100644 --- a/x-pack/plugins/timelines/public/methods/index.tsx +++ b/x-pack/plugins/timelines/public/methods/index.tsx @@ -49,7 +49,7 @@ export const getTGridLazy = ( ) => { initializeStore({ store, storage, setStore }); return ( - }> + }> ); diff --git a/x-pack/plugins/timelines/public/plugin.ts b/x-pack/plugins/timelines/public/plugin.ts index 91439d1928acf..27ca9de0cf034 100644 --- a/x-pack/plugins/timelines/public/plugin.ts +++ b/x-pack/plugins/timelines/public/plugin.ts @@ -6,8 +6,6 @@ */ import { Store, Unsubscribe } from 'redux'; -import { throttle } from 'lodash'; - import { Storage } from '@kbn/kibana-utils-plugin/public'; import type { CoreSetup, Plugin, CoreStart } from '@kbn/core/public'; import type { LastUpdatedAtProps, LoadingPanelProps } from './components'; @@ -40,20 +38,6 @@ export class TimelinesPlugin implements Plugin { } }, getTGrid: (props: TGridProps) => { - if (props.type === 'standalone' && this._store) { - const { getState } = this._store; - const state = getState(); - if (state && state.app) { - this._store = undefined; - } else { - if (props.onStateChange) { - this._storeUnsubscribe = this._store.subscribe( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - throttle(() => props.onStateChange!(getState()), 500) - ); - } - } - } return getTGridLazy(props, { store: this._store, storage: this._storage, diff --git a/x-pack/plugins/timelines/public/store/t_grid/model.ts b/x-pack/plugins/timelines/public/store/t_grid/model.ts index 42d22f74ea175..a2334db776a59 100644 --- a/x-pack/plugins/timelines/public/store/t_grid/model.ts +++ b/x-pack/plugins/timelines/public/store/t_grid/model.ts @@ -26,7 +26,7 @@ export interface TGridModelSettings { showCheckboxes: boolean; /** Specifies which column the timeline is sorted on, and the direction (ascending / descending) */ sort: SortColumnTable[]; - title: string; + title?: string; unit?: (n: number) => string | React.ReactNode; } export interface TGridModel extends TGridModelSettings { @@ -85,5 +85,6 @@ export type SubsetTGridModel = Readonly< | 'graphEventId' | 'sessionViewConfig' | 'queryFields' + | 'title' > >; diff --git a/x-pack/plugins/timelines/public/types.ts b/x-pack/plugins/timelines/public/types.ts index 66808ee40fb86..aec647934c2ad 100644 --- a/x-pack/plugins/timelines/public/types.ts +++ b/x-pack/plugins/timelines/public/types.ts @@ -21,7 +21,6 @@ import type { } from './components'; export type { SortDirection } from '../common/types'; import type { TGridIntegratedProps } from './components/t_grid/integrated'; -import type { TGridStandaloneProps } from './components/t_grid/standalone'; import type { UseAddToTimelineProps, UseAddToTimeline } from './hooks/use_add_to_timeline'; import { HoverActionsConfig } from './components/hover_actions'; export * from './store/t_grid'; @@ -52,19 +51,14 @@ export interface TimelinesStartPlugins { } export type TimelinesStartServices = CoreStart & TimelinesStartPlugins; -interface TGridStandaloneCompProps extends TGridStandaloneProps { - type: 'standalone'; -} interface TGridIntegratedCompProps extends TGridIntegratedProps { type: 'embedded'; } -export type TGridType = 'standalone' | 'embedded'; -export type GetTGridProps = T extends 'standalone' - ? TGridStandaloneCompProps - : T extends 'embedded' +export type TGridType = 'embedded'; +export type GetTGridProps = T extends 'embedded' ? TGridIntegratedCompProps : TGridIntegratedCompProps; -export type TGridProps = TGridStandaloneCompProps | TGridIntegratedCompProps; +export type TGridProps = TGridIntegratedCompProps; export interface StatefulEventContextType { tabType: string | undefined; diff --git a/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx b/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx index 91fb215c814b0..38e7456c5ba7f 100644 --- a/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx +++ b/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx @@ -11,6 +11,7 @@ import type { ScopedHistory } from '@kbn/core/public'; import { coreMock, themeServiceMock } from '@kbn/core/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { savedObjectsPluginMock } from '@kbn/saved-objects-plugin/public/mocks'; import { SharePluginStart } from '@kbn/share-plugin/public'; @@ -25,6 +26,7 @@ import type { GetMlSharedImportsReturnType } from '../../shared_imports'; const coreSetup = coreMock.createSetup(); const coreStart = coreMock.createStart(); const dataStart = dataPluginMock.createStartContract(); +const dataViewsStart = dataViewPluginMocks.createStartContract(); // Replace mock to support syntax using `.then()` as used in transform code. coreStart.savedObjects.client.find = jest.fn().mockResolvedValue({ savedObjects: [] }); @@ -33,6 +35,7 @@ const appDependencies: AppDependencies = { application: coreStart.application, chrome: coreStart.chrome, data: dataStart, + dataViews: dataViewsStart, docLinks: coreStart.docLinks, i18n: coreStart.i18n, notifications: coreSetup.notifications, diff --git a/x-pack/plugins/transform/public/app/app_dependencies.tsx b/x-pack/plugins/transform/public/app/app_dependencies.tsx index 4c3d2ededd2c3..e6caef788c59a 100644 --- a/x-pack/plugins/transform/public/app/app_dependencies.tsx +++ b/x-pack/plugins/transform/public/app/app_dependencies.tsx @@ -19,6 +19,7 @@ import type { } from '@kbn/core/public'; import type { SavedObjectsStart as SavedObjectsPluginStart } from '@kbn/saved-objects-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { ScopedHistory } from '@kbn/core/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; @@ -35,6 +36,7 @@ export interface AppDependencies { application: ApplicationStart; chrome: ChromeStart; data: DataPublicPluginStart; + dataViews: DataViewsPublicPluginStart; docLinks: DocLinksStart; http: HttpSetup; i18n: I18nStart; diff --git a/x-pack/plugins/transform/public/app/mount_management_section.ts b/x-pack/plugins/transform/public/app/mount_management_section.ts index d5b4f07c6ff4d..1ba7253f996fa 100644 --- a/x-pack/plugins/transform/public/app/mount_management_section.ts +++ b/x-pack/plugins/transform/public/app/mount_management_section.ts @@ -29,7 +29,7 @@ export async function mountManagementSection( const startServices = await getStartServices(); const [core, plugins] = startServices; const { application, chrome, docLinks, i18n, overlays, theme, savedObjects, uiSettings } = core; - const { data, share, spaces, triggersActionsUi, unifiedSearch } = plugins; + const { data, dataViews, share, spaces, triggersActionsUi, unifiedSearch } = plugins; const { docTitle } = chrome; // Initialize services @@ -42,6 +42,7 @@ export async function mountManagementSection( application, chrome, data, + dataViews, docLinks, http, i18n, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx index dfbfced03b949..c23d6ed475efc 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx @@ -35,6 +35,7 @@ export const SourceSearchBar: FC = ({ dataView, searchBar http, docLinks, data, + dataViews, storage, unifiedSearch, usageCollection, @@ -73,6 +74,7 @@ export const SourceSearchBar: FC = ({ dataView, searchBar docLinks, uiSettings, data, + dataViews, storage, usageCollection, }} diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 76d8a094a43a6..ead29476ba7f2 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -1051,7 +1051,6 @@ "data.mgmt.searchSessions.status.expiresSoonInHours": "Cette session expire dans {numHours} heures", "data.mgmt.searchSessions.status.expiresSoonInHoursTooltip": "{numHours} heures", "data.mgmt.searchSessions.status.message.createdOn": "Expire le {expireDate}", - "data.mgmt.searchSessions.status.message.error": "Erreur : {error}", "data.mgmt.searchSessions.status.message.expiredOn": "Expiré le {expireDate}", "data.painlessError.painlessScriptedFieldErrorMessage": "Erreur d'exécution du champ d'exécution ou du champ scripté sur le modèle d'indexation {indexPatternName}", "data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "Intervalle de calendrier non valide : {interval} ; la valeur doit être 1.", @@ -1097,8 +1096,6 @@ "data.search.searchSource.indexPatternIdDescription": "L'ID dans l'index {kibanaIndexPattern}.", "data.search.searchSource.queryTimeValue": "{queryTime} ms", "data.search.searchSource.requestTimeValue": "{requestTime} ms", - "data.search.statusError": "Recherche terminée avec un statut {errorCode}", - "data.search.statusThrow": "Le statut de la recherche a généré un statut d'erreur {message} ({errorCode})", "data.search.timeBuckets.dayLabel": "{amount, plural, one {un jour} other {# jours}}", "data.search.timeBuckets.hourLabel": "{amount, plural, one {une heure} other {# heures}}", "data.search.timeBuckets.millisecondLabel": "{amount, plural, one {une milliseconde} other {# millisecondes}}", @@ -2732,7 +2729,6 @@ "expressionXY.reusable.function.xyVis.errors.pointsRadiusForNonLineOrAreaChartError": "\"pointsRadius\" peut être appliqué uniquement aux graphiques linéaires ou aux graphiques en aires", "expressionXY.reusable.function.xyVis.errors.showPointsForNonLineOrAreaChartError": "\"showPoints\" peut être appliqué uniquement aux graphiques linéaires ou aux graphiques en aires", "expressionXY.reusable.function.xyVis.errors.timeMarkerForNotTimeChartsError": "Seuls les graphiques temporels peuvent avoir un repère de temps actuel", - "expressionXY.reusable.function.xyVis.errors.valueLabelsForNotBarsOrHistogramBarsChartsError": "L'argument \"valueLabels\" s'applique uniquement aux graphiques à barres qui ne sont pas des histogrammes.", "expressionXY.xAxisConfigFn.help": "Configurer la config de l'axe x du graphique xy", "expressionXY.xyChart.emptyXLabel": "(vide)", "expressionXY.xyChart.iconSelect.alertIconLabel": "Alerte", @@ -3102,15 +3098,6 @@ "home.breadcrumbs.integrationsAppTitle": "Intégrations", "home.exploreButtonLabel": "Explorer par moi-même", "home.exploreYourDataDescription": "Une fois toutes les étapes terminées, vous êtes prêt à explorer vos données.", - "home.guidedOnboarding.gettingStarted.observability.cardDescription": "Obtenez une observabilité de bout en bout de vos environnements en consolidant vos journaux, vos indicateurs et vos traces.", - "home.guidedOnboarding.gettingStarted.observability.cardTitle": "Monitorer mes environnements", - "home.guidedOnboarding.gettingStarted.observability.iconName": "Logo Observability", - "home.guidedOnboarding.gettingStarted.search.cardDescription": "Créez une expérience de recherche fine pour vos sites web, vos applications, votre contenu workplace, etc.", - "home.guidedOnboarding.gettingStarted.search.cardTitle": "Rechercher dans mes données", - "home.guidedOnboarding.gettingStarted.search.iconName": "Logo Entreprise Search", - "home.guidedOnboarding.gettingStarted.security.cardDescription": "Protégez votre environnement contre les menaces en unifiant SIEM, la sécurité des points de terminaison et la sécurité cloud en un seul endroit.", - "home.guidedOnboarding.gettingStarted.security.cardTitle": "Protéger mon environnement", - "home.guidedOnboarding.gettingStarted.security.iconName": "Logo Security", "home.guidedOnboarding.gettingStarted.skip.buttonLabel": "Non merci, je vais explorer par moi-même.", "home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle": "Sélectionnez un point de départ pour une visite rapide de la façon dont Elastic peut vous aider à faire encore plus avec vos données.", "home.guidedOnboarding.gettingStarted.useCaseSelectionTitle": "Par quoi voulez-vous commencer ?", @@ -7204,7 +7191,6 @@ "xpack.apm.error.prompt.body": "Veuillez consulter la console de développeur de votre navigateur pour plus de détails.", "xpack.apm.error.prompt.title": "Désolé, une erreur s'est produite :(", "xpack.apm.errorCountAlert.name": "Seuil de nombre d'erreurs", - "xpack.apm.errorCountAlertTrigger.errors": " erreurs", "xpack.apm.errorGroup.chart.ocurrences": "Occurrences", "xpack.apm.errorGroupDetails.culpritLabel": "Coupable", "xpack.apm.errorGroupDetails.errorOccurrenceTitle": "Occurrence d'erreur", @@ -7901,12 +7887,8 @@ "xpack.apm.transactionDurationAlert.aggregationType.99th": "99e centile", "xpack.apm.transactionDurationAlert.aggregationType.avg": "Moyenne", "xpack.apm.transactionDurationAlert.name": "Seuil de latence", - "xpack.apm.transactionDurationAlertTrigger.ms": "ms", - "xpack.apm.transactionDurationAlertTrigger.when": "Quand", - "xpack.apm.transactionDurationAnomalyAlertTrigger.anomalySeverity": "Comporte une anomalie avec sévérité", "xpack.apm.transactionDurationLabel": "Durée", "xpack.apm.transactionErrorRateAlert.name": "Seuil du taux de transactions ayant échoué", - "xpack.apm.transactionErrorRateAlertTrigger.isAbove": "est supérieur à", "xpack.apm.transactions.latency.chart.95thPercentileLabel": "95e centile", "xpack.apm.transactions.latency.chart.99thPercentileLabel": "99e centile", "xpack.apm.transactions.latency.chart.averageLabel": "Moyenne", @@ -17512,7 +17494,6 @@ "xpack.lens.formula.editorHelpInlineHideLabel": "Masquer la référence des fonctions", "xpack.lens.formula.editorHelpInlineHideToolTip": "Masquer la référence des fonctions", "xpack.lens.formula.editorHelpInlineShowToolTip": "Afficher la référence des fonctions", - "xpack.lens.formula.editorHelpOverlayToolTip": "Référence des fonctions", "xpack.lens.formula.fullScreenEnterLabel": "Développer", "xpack.lens.formula.fullScreenExitLabel": "Réduire", "xpack.lens.formula.kqlExtraArguments": "[kql]?: string, [lucene]?: string", @@ -17531,7 +17512,6 @@ "xpack.lens.formulaDocumentation.elasticsearchSection": "Elasticsearch", "xpack.lens.formulaDocumentation.elasticsearchSectionDescription": "Ces fonctions seront exécutées sur les documents bruts pour chaque ligne du tableau résultant, en agrégeant tous les documents correspondant aux dimensions de répartition en une seule valeur.", "xpack.lens.formulaDocumentation.filterRatio": "Rapport de filtre", - "xpack.lens.formulaDocumentation.header": "Référence de formule", "xpack.lens.formulaDocumentation.mathSection": "Mathématique", "xpack.lens.formulaDocumentation.mathSectionDescription": "Ces fonctions seront exécutées pour chaque ligne du tableau résultant en utilisant des valeurs uniques de la même ligne calculées à l'aide d'autres fonctions.", "xpack.lens.formulaDocumentation.percentOfTotal": "Pourcentage du total", @@ -17541,7 +17521,6 @@ "xpack.lens.formulaExampleMarkdown": "Exemples", "xpack.lens.formulaFrequentlyUsedHeading": "Formules courantes", "xpack.lens.formulaPlaceholderText": "Saisissez une formule en combinant des fonctions avec la fonction mathématique, telle que :", - "xpack.lens.formulaSearchPlaceholder": "Rechercher des fonctions", "xpack.lens.functions.collapse.args.byHelpText": "Colonnes selon lesquelles effectuer le regroupement - ces colonnes sont conservées telles quelles", "xpack.lens.functions.collapse.args.fnHelpText": "Fonction agrégée à appliquer", "xpack.lens.functions.collapse.args.metricHelpText": "Colonne pour laquelle calculer la fonction agrégée spécifiée", @@ -19188,7 +19167,6 @@ "xpack.ml.dataframe.analyticsList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "Une erreur s'est produite lors de la vérification de la possibilité pour un utilisateur de supprimer {destinationIndex} : {error}", "xpack.ml.dataframe.analyticsList.fetchSourceDataViewForCloneErrorMessage": "Une erreur s’est produite lors de la vérification de l’existence de la vue de données {dataView} : {error}", "xpack.ml.dataframe.analyticsList.forceStopModalBody": "{analyticsId} est en état d'échec. Vous devez arrêter la tâche et corriger la défaillance.", - "xpack.ml.dataframe.analyticsList.noSourceDataViewForClone": "Impossible de cloner la tâche d'analyse. Il n’existe aucune vue de données pour l’index {dataView}.", "xpack.ml.dataframe.analyticsList.progressOfPhase": "Progression de la phase {currentPhase} : {progress}%", "xpack.ml.dataframe.analyticsList.rowCollapse": "Masquer les détails pour {analyticsId}", "xpack.ml.dataframe.analyticsList.rowExpand": "Afficher les détails pour {analyticsId}", @@ -23587,7 +23565,6 @@ "xpack.observability.formatters.secondsTimeUnitLabel": "s", "xpack.observability.formatters.secondsTimeUnitLabelExtended": "secondes", "xpack.observability.home.addData": "Ajouter des intégrations", - "xpack.observability.hoverActions.filterForValue": "Filtrer sur la valeur", "xpack.observability.hoverActions.filterForValueButtonLabel": "Inclure", "xpack.observability.inspector.stats.dataViewDescription": "La vue de données qui se connecte aux index Elasticsearch.", "xpack.observability.inspector.stats.dataViewLabel": "Vue de données", @@ -25623,8 +25600,7 @@ "xpack.securitySolution.eventFilters.showingTotal": "Affichage de {total} {total, plural, one {filtre d'événement} other {filtres d'événement}}", "xpack.securitySolution.eventsTab.unit": "{totalCount, plural, =1 {alerte externe} other {alertes externes}}", "xpack.securitySolution.eventsViewer.unit": "{totalCount, plural, =1 {événement} other {événements}}", - "xpack.securitySolution.exceptions.dissasociateListSuccessText": "La liste d'exceptions ({id}) a été retirée avec succès", - "xpack.securitySolution.exceptions.exceptionItem.showCommentsLabel": "Afficher {comments, plural, =1 {commentaire} other {commentaires}} ({comments})", + "xpack.securitySolution.exceptions.disassociateListSuccessText": "La liste d'exceptions ({id}) a été retirée avec succès", "xpack.securitySolution.exceptions.failedLoadPolicies": "Une erreur s'est produite lors du chargement des politiques : \"{error}\"", "xpack.securitySolution.exceptions.fetch404Error": "La liste d'exceptions associée ({listId}) n'existe plus. Veuillez retirer la liste d'exceptions manquante pour ajouter des exceptions supplémentaires à la règle de détection.", "xpack.securitySolution.exceptions.hideCommentsLabel": "Masquer ({comments}) {comments, plural, =1 {commentaire} other {commentaires}}", @@ -26170,8 +26146,6 @@ "xpack.securitySolution.components.mlPopover.jobsTable.filters.showAllJobsLabel": "Tâches Elastic", "xpack.securitySolution.components.mlPopover.jobsTable.filters.showSiemJobsLabel": "Tâches personnalisées", "xpack.securitySolution.components.mlPopup.cloudLink": "déploiement sur le cloud", - "xpack.securitySolution.components.mlPopup.errors.createJobFailureTitle": "Échec de création de la tâche", - "xpack.securitySolution.components.mlPopup.errors.startJobFailureTitle": "Échec de démarrage de la tâche", "xpack.securitySolution.components.mlPopup.hooks.errors.indexPatternFetchFailureTitle": "Échec de récupération du modèle d'indexation", "xpack.securitySolution.components.mlPopup.hooks.errors.siemJobFetchFailureTitle": "Échec de récupération de la tâche Security", "xpack.securitySolution.components.mlPopup.jobsTable.createCustomJobButtonLabel": "Création d'une tâche personnalisée", @@ -26232,7 +26206,6 @@ "xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription": "Installation effectuée des modèles de chronologies prépackagées à partir d'Elastic", "xpack.securitySolution.containers.detectionEngine.rulesAndTimelines": "Impossible de récupérer les règles et les chronologies", "xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription": "Impossible de récupérer les balises", - "xpack.securitySolution.containers.errors.stopJobFailureTitle": "Échec d'arrêt de la tâche", "xpack.securitySolution.contextMenuItemByRouter.viewDetails": "Afficher les détails", "xpack.securitySolution.customizeEventRenderers.customizeEventRenderersDescription": "Les outils de rendu d'événement transmettent automatiquement les détails les plus pertinents d'un événement pour révéler son histoire", "xpack.securitySolution.customizeEventRenderers.customizeEventRenderersTitle": "Personnaliser les outils de rendu d'événement", @@ -27360,7 +27333,7 @@ "xpack.securitySolution.detectionEngine.rules.allRules.actions.deleteRuleDescription": "Supprimer la règle", "xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription": "Dupliquer la règle", "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsDescription": "Modifier les paramètres de règles", - "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip": "Vous ne disposez pas des privilèges d'actions Kibana", + "xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges": "Vous ne disposez pas des privilèges d'actions Kibana", "xpack.securitySolution.detectionEngine.rules.allRules.actions.exportRuleDescription": "Exporter la règle", "xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedImmutableTitle": "La sélection contient des règles immuables qui ne peuvent pas être supprimées", "xpack.securitySolution.detectionEngine.rules.allRules.batchActionsTitle": "Actions groupées", @@ -28164,58 +28137,14 @@ "xpack.securitySolution.eventsViewer.alerts.overviewTable.signalStatusTitle": "Statut", "xpack.securitySolution.eventsViewer.eventsLabel": "Événements", "xpack.securitySolution.eventsViewer.showingLabel": "Affichage", - "xpack.securitySolution.exceptions.addException.addEndpointException": "Ajouter une exception de point de terminaison", - "xpack.securitySolution.exceptions.addException.addException": "Ajouter une exception à une règle", - "xpack.securitySolution.exceptions.addException.bulkCloseLabel": "Fermer toutes les alertes qui correspondent à cette exception et ont été générées par cette règle", - "xpack.securitySolution.exceptions.addException.bulkCloseLabel.disabled": "Fermer toutes les alertes qui correspondent à cette exception et ont été générées par cette règle (les listes et les champs non ECS ne sont pas pris en charge)", - "xpack.securitySolution.exceptions.addException.cancel": "Annuler", - "xpack.securitySolution.exceptions.addException.endpointQuarantineText": "Sur tous les hôtes Endpoint, les fichiers en quarantaine qui correspondent à l'exception sont automatiquement restaurés à leur emplacement d'origine. Cette exception s'applique à toutes les règles utilisant les exceptions Endpoint.", - "xpack.securitySolution.exceptions.addException.error": "Impossible d'ajouter l'exception", - "xpack.securitySolution.exceptions.addException.infoLabel": "Les alertes sont générées lorsque les conditions de la règle sont remplies, sauf quand :", - "xpack.securitySolution.exceptions.addException.operatingSystemPlaceHolder": "Sélectionner un système d'exploitation", - "xpack.securitySolution.exceptions.addException.sequenceWarning": "La requête de cette règle contient une instruction de séquence EQL. L'exception créée s'appliquera à tous les événements de la séquence.", - "xpack.securitySolution.exceptions.addException.success": "Exception ajoutée avec succès", "xpack.securitySolution.exceptions.badge.readOnly.tooltip": "Impossible de créer, de modifier ou de supprimer des exceptions", "xpack.securitySolution.exceptions.cancelLabel": "Annuler", "xpack.securitySolution.exceptions.clearExceptionsLabel": "Retirer la liste d'exceptions", "xpack.securitySolution.exceptions.commentEventLabel": "a ajouté un commentaire", - "xpack.securitySolution.exceptions.dissasociateExceptionListError": "Impossible de retirer la liste d'exceptions", - "xpack.securitySolution.exceptions.editException.bulkCloseLabel": "Fermer toutes les alertes qui correspondent à cette exception et ont été générées par cette règle", - "xpack.securitySolution.exceptions.editException.bulkCloseLabel.disabled": "Fermer toutes les alertes qui correspondent à cette exception et ont été générées par cette règle (les listes et les champs non ECS ne sont pas pris en charge)", - "xpack.securitySolution.exceptions.editException.cancel": "Annuler", - "xpack.securitySolution.exceptions.editException.editEndpointExceptionTitle": "Modifier une exception de point de terminaison", - "xpack.securitySolution.exceptions.editException.editExceptionSaveButton": "Enregistrer", - "xpack.securitySolution.exceptions.editException.editExceptionTitle": "Modifier une exception à une règle", - "xpack.securitySolution.exceptions.editException.endpointQuarantineText": "Sur tous les hôtes Endpoint, les fichiers en quarantaine qui correspondent à l'exception sont automatiquement restaurés à leur emplacement d'origine. Cette exception s'applique à toutes les règles utilisant les exceptions Endpoint.", - "xpack.securitySolution.exceptions.editException.infoLabel": "Les alertes sont générées lorsque les conditions de la règle sont remplies, sauf quand :", - "xpack.securitySolution.exceptions.editException.sequenceWarning": "La requête de cette règle contient une instruction de séquence EQL. L'exception modifiée s'appliquera à tous les événements de la séquence.", - "xpack.securitySolution.exceptions.editException.success": "L'exception a été mise à jour avec succès", - "xpack.securitySolution.exceptions.editException.versionConflictDescription": "Cette exception semble avoir été mise à jour depuis que vous l'avez sélectionnée pour la modifier. Essayez de cliquer sur \"Annuler\" et de modifier à nouveau l'exception.", - "xpack.securitySolution.exceptions.editException.versionConflictTitle": "Désolé, une erreur est survenue", + "xpack.securitySolution.exceptions.disassociateExceptionListError": "Impossible de retirer la liste d'exceptions", "xpack.securitySolution.exceptions.errorLabel": "Erreur", "xpack.securitySolution.exceptions.fetchError": "Erreur lors de la récupération de la liste d'exceptions", "xpack.securitySolution.exceptions.modalErrorAccordionText": "Afficher les informations de référence de la règle :", - "xpack.securitySolution.exceptions.exceptionItem.conditions.and": "AND", - "xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator": "existe", - "xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator.not": "n'existe pas", - "xpack.securitySolution.exceptions.exceptionItem.conditions.linux": "Linux", - "xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator": "inclus dans", - "xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator.not": "n'est pas inclus dans", - "xpack.securitySolution.exceptions.exceptionItem.conditions.macos": "Mac", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator": "est l'une des options suivantes", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator.not": "n'est pas l'une des options suivantes", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator": "IS", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator.not": "N'EST PAS", - "xpack.securitySolution.exceptions.exceptionItem.conditions.nestedOperator": "a", - "xpack.securitySolution.exceptions.exceptionItem.conditions.os": "Système d'exploitation", - "xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardDoesNotMatchOperator": "NE CORRESPOND PAS À", - "xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardMatchesOperator": "CORRESPONDANCES", - "xpack.securitySolution.exceptions.exceptionItem.conditions.windows": "Windows", - "xpack.securitySolution.exceptions.exceptionItem.createdLabel": "Créé", - "xpack.securitySolution.exceptions.exceptionItem.deleteItemButton": "Supprimer un élément", - "xpack.securitySolution.exceptions.exceptionItem.editItemButton": "Modifier l’élément", - "xpack.securitySolution.exceptions.exceptionItem.metaDetailsBy": "par", - "xpack.securitySolution.exceptions.exceptionItem.updatedLabel": "Mis à jour", "xpack.securitySolution.exceptions.operatingSystemFullLabel": "Système d'exploitation", "xpack.securitySolution.exceptions.operatingSystemLinux": "Linux", "xpack.securitySolution.exceptions.operatingSystemMac": "macOS", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a03f2a024c213..5f867500f94b7 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1049,7 +1049,6 @@ "data.mgmt.searchSessions.status.expiresSoonInHours": "このセッションは{numHours}時間後に期限切れになります", "data.mgmt.searchSessions.status.expiresSoonInHoursTooltip": "{numHours}時間", "data.mgmt.searchSessions.status.message.createdOn": "有効期限:{expireDate}", - "data.mgmt.searchSessions.status.message.error": "エラー:{error}", "data.mgmt.searchSessions.status.message.expiredOn": "有効期限:{expireDate}", "data.painlessError.painlessScriptedFieldErrorMessage": "インデックスパターン{indexPatternName}でのランタイムフィールドまたはスクリプトフィールドの実行エラー", "data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "無効なカレンダー間隔:{interval}、1よりも大きな値が必要です", @@ -1095,8 +1094,6 @@ "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} インデックス内の ID です。", "data.search.searchSource.queryTimeValue": "{queryTime}ms", "data.search.searchSource.requestTimeValue": "{requestTime}ms", - "data.search.statusError": "検索は{errorCode}ステータスで完了しました", - "data.search.statusThrow": "検索ステータスはエラー{message}({errorCode})ステータスを返しました", "data.search.timeBuckets.dayLabel": "{amount, plural, other {# 日}}", "data.search.timeBuckets.hourLabel": "{amount, plural, other {# 時間}}", "data.search.timeBuckets.millisecondLabel": "{amount, plural, other {# ミリ秒}}", @@ -2728,7 +2725,6 @@ "expressionXY.reusable.function.xyVis.errors.pointsRadiusForNonLineOrAreaChartError": "pointsRadiusは折れ線グラフまたは面グラフでのみ適用できます。", "expressionXY.reusable.function.xyVis.errors.showPointsForNonLineOrAreaChartError": "showPointsは折れ線グラフまたは面グラフでのみ適用できます。", "expressionXY.reusable.function.xyVis.errors.timeMarkerForNotTimeChartsError": "現在時刻マーカーを設定できるのは、時系列グラフのみです", - "expressionXY.reusable.function.xyVis.errors.valueLabelsForNotBarsOrHistogramBarsChartsError": "valueLabels引数は棒グラフでのみ適用できます。これはヒストグラフではありません。", "expressionXY.xAxisConfigFn.help": "xyグラフのx軸設定を構成", "expressionXY.xyChart.emptyXLabel": "(空)", "expressionXY.xyChart.iconSelect.alertIconLabel": "アラート", @@ -3097,15 +3093,6 @@ "home.breadcrumbs.integrationsAppTitle": "統合", "home.exploreButtonLabel": "独りで閲覧", "home.exploreYourDataDescription": "すべてのステップを終えたら、データ閲覧準備の完了です。", - "home.guidedOnboarding.gettingStarted.observability.cardDescription": "ログ、メトリック、トレースを統合し、環境に対するエンドツーエンドのオブザーバビリティを実現します。", - "home.guidedOnboarding.gettingStarted.observability.cardTitle": "環境を監視", - "home.guidedOnboarding.gettingStarted.observability.iconName": "オブザーバビリティロゴ", - "home.guidedOnboarding.gettingStarted.search.cardDescription": "Webサイト、アプリケーション、workplaceコンテンツなどに合った、微調整された検索エクスペリエンスを作成します。", - "home.guidedOnboarding.gettingStarted.search.cardTitle": "データを検索", - "home.guidedOnboarding.gettingStarted.search.iconName": "エンタープライズ サーチロゴ", - "home.guidedOnboarding.gettingStarted.security.cardDescription": "SIEM、エンドポイントセキュリティ、クラウドセキュリティを一元化して統合することで、環境を脅威から守ります。", - "home.guidedOnboarding.gettingStarted.security.cardTitle": "環境を保護", - "home.guidedOnboarding.gettingStarted.security.iconName": "セキュリティロゴ", "home.guidedOnboarding.gettingStarted.skip.buttonLabel": "いいえ、結構です。自分で探します。", "home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle": "まず、スタートとしてクイックガイドを表示すると、どのようにElasticでデータに対して高度な操作を実行するのかを確認できます。", "home.guidedOnboarding.gettingStarted.useCaseSelectionTitle": "最初に何をしたいですか?", @@ -7192,7 +7179,6 @@ "xpack.apm.error.prompt.body": "詳細はブラウザの開発者コンソールをご確認ください。", "xpack.apm.error.prompt.title": "申し訳ございませんが、エラーが発生しました :(", "xpack.apm.errorCountAlert.name": "エラー数しきい値", - "xpack.apm.errorCountAlertTrigger.errors": " エラー", "xpack.apm.errorGroup.chart.ocurrences": "オカレンス", "xpack.apm.errorGroupDetails.culpritLabel": "原因", "xpack.apm.errorGroupDetails.errorOccurrenceTitle": "エラーのオカレンス", @@ -7888,12 +7874,8 @@ "xpack.apm.transactionDurationAlert.aggregationType.99th": "99 パーセンタイル", "xpack.apm.transactionDurationAlert.aggregationType.avg": "平均", "xpack.apm.transactionDurationAlert.name": "レイテンシしきい値", - "xpack.apm.transactionDurationAlertTrigger.ms": "ms", - "xpack.apm.transactionDurationAlertTrigger.when": "タイミング", - "xpack.apm.transactionDurationAnomalyAlertTrigger.anomalySeverity": "異常と重要度があります", "xpack.apm.transactionDurationLabel": "期間", "xpack.apm.transactionErrorRateAlert.name": "失敗したトランザクション率しきい値", - "xpack.apm.transactionErrorRateAlertTrigger.isAbove": "より大きい", "xpack.apm.transactions.latency.chart.95thPercentileLabel": "95 パーセンタイル", "xpack.apm.transactions.latency.chart.99thPercentileLabel": "99 パーセンタイル", "xpack.apm.transactions.latency.chart.averageLabel": "平均", @@ -17495,7 +17477,6 @@ "xpack.lens.formula.editorHelpInlineHideLabel": "関数リファレンスを非表示", "xpack.lens.formula.editorHelpInlineHideToolTip": "関数リファレンスを非表示", "xpack.lens.formula.editorHelpInlineShowToolTip": "関数リファレンスを表示", - "xpack.lens.formula.editorHelpOverlayToolTip": "機能リファレンス", "xpack.lens.formula.fullScreenEnterLabel": "拡張", "xpack.lens.formula.fullScreenExitLabel": "縮小", "xpack.lens.formula.kqlExtraArguments": "[kql]?:文字列、[lucene]?:文字列", @@ -17514,7 +17495,6 @@ "xpack.lens.formulaDocumentation.elasticsearchSection": "Elasticsearch", "xpack.lens.formulaDocumentation.elasticsearchSectionDescription": "これらの関数は結果テーブルの各行の未加工ドキュメントで実行され、内訳ディメンションと一致するすべてのドキュメントを単一の値に集約します。", "xpack.lens.formulaDocumentation.filterRatio": "フィルター比率", - "xpack.lens.formulaDocumentation.header": "式リファレンス", "xpack.lens.formulaDocumentation.mathSection": "数学処理", "xpack.lens.formulaDocumentation.mathSectionDescription": "これらの関数は、他の関数で計算された同じ行の単一の値を使用して、結果テーブルの各行で実行されます。", "xpack.lens.formulaDocumentation.percentOfTotal": "合計の割合", @@ -17524,7 +17504,6 @@ "xpack.lens.formulaExampleMarkdown": "例", "xpack.lens.formulaFrequentlyUsedHeading": "一般的な式", "xpack.lens.formulaPlaceholderText": "関数を演算と組み合わせて式を入力します。例:", - "xpack.lens.formulaSearchPlaceholder": "検索関数", "xpack.lens.functions.collapse.args.byHelpText": "グループ化の基準となる列。この列はそのまま保持されます", "xpack.lens.functions.collapse.args.fnHelpText": "適用する集計関数", "xpack.lens.functions.collapse.args.metricHelpText": "指定された集計関数を計算する列", @@ -19169,7 +19148,6 @@ "xpack.ml.dataframe.analyticsList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "ユーザーが{destinationIndex}を削除できるかどうかを確認するときにエラーが発生しました。{error}", "xpack.ml.dataframe.analyticsList.fetchSourceDataViewForCloneErrorMessage": "データビュー{dataView}が存在するかどうかを確認しているときにエラーが発生しました:{error}", "xpack.ml.dataframe.analyticsList.forceStopModalBody": "{analyticsId}は失敗状態です。ジョブを停止して、エラーを修正する必要があります。", - "xpack.ml.dataframe.analyticsList.noSourceDataViewForClone": "分析ジョブを複製できません。インデックス{dataView}のデータビューは存在しません。", "xpack.ml.dataframe.analyticsList.progressOfPhase": "フェーズ{currentPhase}の進捗:{progress}%", "xpack.ml.dataframe.analyticsList.rowCollapse": "{analyticsId}の詳細を非表示", "xpack.ml.dataframe.analyticsList.rowExpand": "{analyticsId}の詳細を表示", @@ -23566,7 +23544,6 @@ "xpack.observability.formatters.secondsTimeUnitLabel": "s", "xpack.observability.formatters.secondsTimeUnitLabelExtended": "秒", "xpack.observability.home.addData": "統合の追加", - "xpack.observability.hoverActions.filterForValue": "値でフィルター", "xpack.observability.hoverActions.filterForValueButtonLabel": "フィルタリング", "xpack.observability.inspector.stats.dataViewDescription": "Elasticsearchインデックスに接続したデータビューです。", "xpack.observability.inspector.stats.dataViewLabel": "データビュー", @@ -25598,8 +25575,7 @@ "xpack.securitySolution.eventFilters.showingTotal": "{total} {total, plural, other {個のイベントフィルター}}を表示中", "xpack.securitySolution.eventsTab.unit": "外部{totalCount, plural, other {アラート}}", "xpack.securitySolution.eventsViewer.unit": "{totalCount, plural, other {イベント}}", - "xpack.securitySolution.exceptions.dissasociateListSuccessText": "例外リスト({id})が正常に削除されました", - "xpack.securitySolution.exceptions.exceptionItem.showCommentsLabel": "{comments, plural, other {件のコメント}}を表示({comments})", + "xpack.securitySolution.exceptions.disassociateListSuccessText": "例外リスト({id})が正常に削除されました", "xpack.securitySolution.exceptions.failedLoadPolicies": "ポリシーの読み込みエラーが発生しました:\"{error}\"", "xpack.securitySolution.exceptions.fetch404Error": "関連付けられた例外リスト({listId})は存在しません。その他の例外を検出ルールに追加するには、見つからない例外リストを削除してください。", "xpack.securitySolution.exceptions.hideCommentsLabel": "({comments}){comments, plural, other {件のコメント}}を非表示", @@ -26145,8 +26121,6 @@ "xpack.securitySolution.components.mlPopover.jobsTable.filters.showAllJobsLabel": "Elastic ジョブ", "xpack.securitySolution.components.mlPopover.jobsTable.filters.showSiemJobsLabel": "カスタムジョブ", "xpack.securitySolution.components.mlPopup.cloudLink": "クラウド展開", - "xpack.securitySolution.components.mlPopup.errors.createJobFailureTitle": "ジョブ作成エラー", - "xpack.securitySolution.components.mlPopup.errors.startJobFailureTitle": "ジョブ開始エラー", "xpack.securitySolution.components.mlPopup.hooks.errors.indexPatternFetchFailureTitle": "インデックスパターン取得エラー", "xpack.securitySolution.components.mlPopup.hooks.errors.siemJobFetchFailureTitle": "セキュリティジョブ取得エラー", "xpack.securitySolution.components.mlPopup.jobsTable.createCustomJobButtonLabel": "カスタムジョブを作成", @@ -26207,7 +26181,6 @@ "xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription": "Elasticから事前にパッケージ化されているタイムラインテンプレートをインストールしました", "xpack.securitySolution.containers.detectionEngine.rulesAndTimelines": "ルールとタイムラインを取得できませんでした", "xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription": "タグを取得できませんでした", - "xpack.securitySolution.containers.errors.stopJobFailureTitle": "ジョブ停止エラー", "xpack.securitySolution.contextMenuItemByRouter.viewDetails": "詳細を表示", "xpack.securitySolution.customizeEventRenderers.customizeEventRenderersDescription": "イベントレンダラーは、イベントで最も関連性が高い詳細情報を自動的に表示し、ストーリーを明らかにします", "xpack.securitySolution.customizeEventRenderers.customizeEventRenderersTitle": "イベントレンダラーのカスタマイズ", @@ -27335,7 +27308,7 @@ "xpack.securitySolution.detectionEngine.rules.allRules.actions.deleteRuleDescription": "ルールの削除", "xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription": "ルールの複製", "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsDescription": "ルール設定の編集", - "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip": "Kibana アクション特権がありません", + "xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges": "Kibana アクション特権がありません", "xpack.securitySolution.detectionEngine.rules.allRules.actions.exportRuleDescription": "ルールのエクスポート", "xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedImmutableTitle": "選択には削除できないイミュータブルルールがあります", "xpack.securitySolution.detectionEngine.rules.allRules.batchActionsTitle": "一斉アクション", @@ -28139,57 +28112,13 @@ "xpack.securitySolution.eventsViewer.alerts.overviewTable.signalStatusTitle": "ステータス", "xpack.securitySolution.eventsViewer.eventsLabel": "イベント", "xpack.securitySolution.eventsViewer.showingLabel": "表示中", - "xpack.securitySolution.exceptions.addException.addEndpointException": "エンドポイント例外の追加", - "xpack.securitySolution.exceptions.addException.addException": "ルール例外の追加", - "xpack.securitySolution.exceptions.addException.bulkCloseLabel": "この例外一致し、このルールによって生成された、すべてのアラートを閉じる", - "xpack.securitySolution.exceptions.addException.bulkCloseLabel.disabled": "この例外と一致し、このルールによって生成された、すべてのアラートを閉じる(リストと非ECSフィールドはサポートされません)", - "xpack.securitySolution.exceptions.addException.cancel": "キャンセル", - "xpack.securitySolution.exceptions.addException.endpointQuarantineText": "すべてのエンドポイントホストで、例外と一致する隔離されたファイルは、自動的に元の場所に復元されます。この例外はエンドポイント例外を使用するすべてのルールに適用されます。", - "xpack.securitySolution.exceptions.addException.error": "例外を追加できませんでした", - "xpack.securitySolution.exceptions.addException.infoLabel": "ルールの条件が満たされるときにアラートが生成されます。例外:", - "xpack.securitySolution.exceptions.addException.operatingSystemPlaceHolder": "オペレーティングシステムを選択", - "xpack.securitySolution.exceptions.addException.sequenceWarning": "このルールのクエリにはEQLシーケンス文があります。作成された例外は、シーケンスのすべてのイベントに適用されます。", - "xpack.securitySolution.exceptions.addException.success": "正常に例外を追加しました", "xpack.securitySolution.exceptions.badge.readOnly.tooltip": "例外を作成、編集、削除できません", "xpack.securitySolution.exceptions.cancelLabel": "キャンセル", "xpack.securitySolution.exceptions.clearExceptionsLabel": "例外リストを削除", "xpack.securitySolution.exceptions.commentEventLabel": "コメントを追加しました", - "xpack.securitySolution.exceptions.dissasociateExceptionListError": "例外リストを削除できませんでした", - "xpack.securitySolution.exceptions.editException.bulkCloseLabel": "この例外一致し、このルールによって生成された、すべてのアラートを閉じる", - "xpack.securitySolution.exceptions.editException.bulkCloseLabel.disabled": "この例外と一致し、このルールによって生成された、すべてのアラートを閉じる(リストと非ECSフィールドはサポートされません)", - "xpack.securitySolution.exceptions.editException.cancel": "キャンセル", - "xpack.securitySolution.exceptions.editException.editEndpointExceptionTitle": "エンドポイント例外の編集", - "xpack.securitySolution.exceptions.editException.editExceptionSaveButton": "保存", - "xpack.securitySolution.exceptions.editException.editExceptionTitle": "ルール例外を編集", - "xpack.securitySolution.exceptions.editException.endpointQuarantineText": "すべてのエンドポイントホストで、例外と一致する隔離されたファイルは、自動的に元の場所に復元されます。この例外はエンドポイント例外を使用するすべてのルールに適用されます。", - "xpack.securitySolution.exceptions.editException.infoLabel": "ルールの条件が満たされるときにアラートが生成されます。例外:", - "xpack.securitySolution.exceptions.editException.sequenceWarning": "このルールのクエリにはEQLシーケンス文があります。修正された例外は、シーケンスのすべてのイベントに適用されます。", - "xpack.securitySolution.exceptions.editException.success": "正常に例外を更新しました", - "xpack.securitySolution.exceptions.editException.versionConflictDescription": "最初に編集することを選択したときからこの例外が更新されている可能性があります。[キャンセル]をクリックし、もう一度例外を編集してください。", - "xpack.securitySolution.exceptions.editException.versionConflictTitle": "申し訳ございません、エラーが発生しました", + "xpack.securitySolution.exceptions.disassociateExceptionListError": "例外リストを削除できませんでした", "xpack.securitySolution.exceptions.errorLabel": "エラー", "xpack.securitySolution.exceptions.fetchError": "例外リストの取得エラー", - "xpack.securitySolution.exceptions.exceptionItem.conditions.and": "AND", - "xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator": "存在する", - "xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator.not": "存在しない", - "xpack.securitySolution.exceptions.exceptionItem.conditions.linux": "Linux", - "xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator": "に含まれる", - "xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator.not": "に含まれない", - "xpack.securitySolution.exceptions.exceptionItem.conditions.macos": "Mac", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator": "is one of", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator.not": "is not one of", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator": "IS", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator.not": "IS NOT", - "xpack.securitySolution.exceptions.exceptionItem.conditions.nestedOperator": "がある", - "xpack.securitySolution.exceptions.exceptionItem.conditions.os": "OS", - "xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardDoesNotMatchOperator": "一致しない", - "xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardMatchesOperator": "一致", - "xpack.securitySolution.exceptions.exceptionItem.conditions.windows": "Windows", - "xpack.securitySolution.exceptions.exceptionItem.createdLabel": "作成済み", - "xpack.securitySolution.exceptions.exceptionItem.deleteItemButton": "アイテムを削除", - "xpack.securitySolution.exceptions.exceptionItem.editItemButton": "項目を編集", - "xpack.securitySolution.exceptions.exceptionItem.metaDetailsBy": "グループ基準", - "xpack.securitySolution.exceptions.exceptionItem.updatedLabel": "更新しました", "xpack.securitySolution.exceptions.modalErrorAccordionText": "ルール参照情報を表示:", "xpack.securitySolution.exceptions.operatingSystemFullLabel": "オペレーティングシステム", "xpack.securitySolution.exceptions.operatingSystemLinux": "Linux", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 193d57ba8f62b..002fdcf382100 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1051,7 +1051,6 @@ "data.mgmt.searchSessions.status.expiresSoonInHours": "此会话将于 {numHours} 小时后过期", "data.mgmt.searchSessions.status.expiresSoonInHoursTooltip": "{numHours} 小时", "data.mgmt.searchSessions.status.message.createdOn": "于 {expireDate}过期", - "data.mgmt.searchSessions.status.message.error": "错误:{error}", "data.mgmt.searchSessions.status.message.expiredOn": "已于 {expireDate}过期", "data.painlessError.painlessScriptedFieldErrorMessage": "在索引模式 {indexPatternName} 上执行运行时字段或脚本字段时出错", "data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "无效的日历时间间隔:{interval},值必须为 1", @@ -1097,8 +1096,6 @@ "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。", "data.search.searchSource.queryTimeValue": "{queryTime}ms", "data.search.searchSource.requestTimeValue": "{requestTime}ms", - "data.search.statusError": "搜索完成,状态为 {errorCode}", - "data.search.statusThrow": "搜索状态引发错误 {message} ({errorCode}) 状态", "data.search.timeBuckets.dayLabel": "{amount, plural, other {# 天}}", "data.search.timeBuckets.hourLabel": "{amount, plural, other {# 小时}}", "data.search.timeBuckets.millisecondLabel": "{amount, plural,other {# 毫秒}}", @@ -2732,7 +2729,6 @@ "expressionXY.reusable.function.xyVis.errors.pointsRadiusForNonLineOrAreaChartError": "`pointsRadius` 仅适用于折线图或面积图", "expressionXY.reusable.function.xyVis.errors.showPointsForNonLineOrAreaChartError": "`showPoints` 仅适用于折线图或面积图", "expressionXY.reusable.function.xyVis.errors.timeMarkerForNotTimeChartsError": "仅时间图表可以具有当前时间标记", - "expressionXY.reusable.function.xyVis.errors.valueLabelsForNotBarsOrHistogramBarsChartsError": "`valueLabels` 参数仅适用于条形图,它们并非直方图。", "expressionXY.xAxisConfigFn.help": "配置 xy 图表的 x 轴配置", "expressionXY.xyChart.emptyXLabel": "(空)", "expressionXY.xyChart.iconSelect.alertIconLabel": "告警", @@ -3102,15 +3098,6 @@ "home.breadcrumbs.integrationsAppTitle": "集成", "home.exploreButtonLabel": "自己浏览", "home.exploreYourDataDescription": "完成所有步骤后,您便可以随时浏览自己的数据。", - "home.guidedOnboarding.gettingStarted.observability.cardDescription": "通过整合您的日志、指标和跟踪,在您的环境中实现端到端可观测性。", - "home.guidedOnboarding.gettingStarted.observability.cardTitle": "监测我的环境", - "home.guidedOnboarding.gettingStarted.observability.iconName": "Observability 徽标", - "home.guidedOnboarding.gettingStarted.search.cardDescription": "为您的网站、应用程序、工作区内容等创建经过优化的搜索体验。", - "home.guidedOnboarding.gettingStarted.search.cardTitle": "搜索我的数据", - "home.guidedOnboarding.gettingStarted.search.iconName": "Enterprise Search 徽标", - "home.guidedOnboarding.gettingStarted.security.cardDescription": "通过在一个位置整合 SIEM、Endpoint Security 和云安全来保护您的环境,防止其受到威胁。", - "home.guidedOnboarding.gettingStarted.security.cardTitle": "保护我的环境", - "home.guidedOnboarding.gettingStarted.security.iconName": "安全徽标", "home.guidedOnboarding.gettingStarted.skip.buttonLabel": "不用了,谢谢,我会自己浏览。", "home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle": "选择快速教程的起点,了解 Elastic 如何帮助您利用数据完成更多任务。", "home.guidedOnboarding.gettingStarted.useCaseSelectionTitle": "您希望先做什么?", @@ -7208,7 +7195,6 @@ "xpack.apm.error.prompt.body": "有关详情,请查看您的浏览器开发者控制台。", "xpack.apm.error.prompt.title": "抱歉,发生错误 :(", "xpack.apm.errorCountAlert.name": "错误计数阈值", - "xpack.apm.errorCountAlertTrigger.errors": " 错误", "xpack.apm.errorGroup.chart.ocurrences": "发生次数", "xpack.apm.errorGroupDetails.culpritLabel": "原因", "xpack.apm.errorGroupDetails.errorOccurrenceTitle": "错误发生", @@ -7905,12 +7891,8 @@ "xpack.apm.transactionDurationAlert.aggregationType.99th": "第 99 个百分位", "xpack.apm.transactionDurationAlert.aggregationType.avg": "平均值", "xpack.apm.transactionDurationAlert.name": "延迟阈值", - "xpack.apm.transactionDurationAlertTrigger.ms": "ms", - "xpack.apm.transactionDurationAlertTrigger.when": "当", - "xpack.apm.transactionDurationAnomalyAlertTrigger.anomalySeverity": "有异常,严重性为", "xpack.apm.transactionDurationLabel": "持续时间", "xpack.apm.transactionErrorRateAlert.name": "失败事务率阈值", - "xpack.apm.transactionErrorRateAlertTrigger.isAbove": "高于", "xpack.apm.transactions.latency.chart.95thPercentileLabel": "第 95 个百分位", "xpack.apm.transactions.latency.chart.99thPercentileLabel": "第 99 个百分位", "xpack.apm.transactions.latency.chart.averageLabel": "平均值", @@ -17520,7 +17502,6 @@ "xpack.lens.formula.editorHelpInlineHideLabel": "隐藏函数引用", "xpack.lens.formula.editorHelpInlineHideToolTip": "隐藏函数引用", "xpack.lens.formula.editorHelpInlineShowToolTip": "显示函数引用", - "xpack.lens.formula.editorHelpOverlayToolTip": "函数引用", "xpack.lens.formula.fullScreenEnterLabel": "展开", "xpack.lens.formula.fullScreenExitLabel": "折叠", "xpack.lens.formula.kqlExtraArguments": "[kql]?: string, [lucene]?: string", @@ -17539,7 +17520,6 @@ "xpack.lens.formulaDocumentation.elasticsearchSection": "Elasticsearch", "xpack.lens.formulaDocumentation.elasticsearchSectionDescription": "在原始文档上结果列表的每行都将执行这些函数,从而将匹配分解维度的所有文档聚合成单值。", "xpack.lens.formulaDocumentation.filterRatio": "筛选比", - "xpack.lens.formulaDocumentation.header": "公式参考", "xpack.lens.formulaDocumentation.mathSection": "数学", "xpack.lens.formulaDocumentation.mathSectionDescription": "结果表的每行使用相同行中使用其他函数计算的单值执行这些函数。", "xpack.lens.formulaDocumentation.percentOfTotal": "总计的百分比", @@ -17549,7 +17529,6 @@ "xpack.lens.formulaExampleMarkdown": "示例", "xpack.lens.formulaFrequentlyUsedHeading": "常用公式", "xpack.lens.formulaPlaceholderText": "通过将函数与数学表达式组合来键入公式,如:", - "xpack.lens.formulaSearchPlaceholder": "搜索函数", "xpack.lens.functions.collapse.args.byHelpText": "要作为分组依据的列 - 这些列将保持原样", "xpack.lens.functions.collapse.args.fnHelpText": "要应用的聚合函数", "xpack.lens.functions.collapse.args.metricHelpText": "用于计算以下项的指定聚合函数的列", @@ -19195,7 +19174,6 @@ "xpack.ml.dataframe.analyticsList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "检查用户是否能够删除 {destinationIndex} 时发生错误:{error}", "xpack.ml.dataframe.analyticsList.fetchSourceDataViewForCloneErrorMessage": "检查数据视图 {dataView} 是否存在时发生错误:{error}", "xpack.ml.dataframe.analyticsList.forceStopModalBody": "{analyticsId} 处于失败状态。您必须停止该作业并修复失败问题。", - "xpack.ml.dataframe.analyticsList.noSourceDataViewForClone": "无法克隆分析作业。对于索引 {dataView},不存在数据视图。", "xpack.ml.dataframe.analyticsList.progressOfPhase": "阶段 {currentPhase} 的进度:{progress}%", "xpack.ml.dataframe.analyticsList.rowCollapse": "隐藏 {analyticsId} 的详情", "xpack.ml.dataframe.analyticsList.rowExpand": "显示 {analyticsId} 的详情", @@ -23597,7 +23575,6 @@ "xpack.observability.formatters.secondsTimeUnitLabel": "s", "xpack.observability.formatters.secondsTimeUnitLabelExtended": "秒", "xpack.observability.home.addData": "添加集成", - "xpack.observability.hoverActions.filterForValue": "筛留值", "xpack.observability.hoverActions.filterForValueButtonLabel": "筛选范围", "xpack.observability.inspector.stats.dataViewDescription": "连接到 Elasticsearch 索引的数据视图。", "xpack.observability.inspector.stats.dataViewLabel": "数据视图", @@ -25632,8 +25609,7 @@ "xpack.securitySolution.eventFilters.showingTotal": "正在显示 {total} 个{total, plural, other {事件筛选}}", "xpack.securitySolution.eventsTab.unit": "个外部{totalCount, plural, other {告警}}", "xpack.securitySolution.eventsViewer.unit": "{totalCount, plural, other {个事件}}", - "xpack.securitySolution.exceptions.dissasociateListSuccessText": "例外列表 ({id}) 已成功移除", - "xpack.securitySolution.exceptions.exceptionItem.showCommentsLabel": "显示{comments, plural, other {注释}} ({comments})", + "xpack.securitySolution.exceptions.disassociateListSuccessText": "例外列表 ({id}) 已成功移除", "xpack.securitySolution.exceptions.failedLoadPolicies": "加载策略时出错:“{error}”", "xpack.securitySolution.exceptions.fetch404Error": "关联的例外列表 ({listId}) 已不存在。请移除缺少的例外列表,以将其他例外添加到检测规则。", "xpack.securitySolution.exceptions.hideCommentsLabel": "隐藏 ({comments}) 个{comments, plural, other {注释}}", @@ -26179,8 +26155,6 @@ "xpack.securitySolution.components.mlPopover.jobsTable.filters.showAllJobsLabel": "Elastic 作业", "xpack.securitySolution.components.mlPopover.jobsTable.filters.showSiemJobsLabel": "定制作业", "xpack.securitySolution.components.mlPopup.cloudLink": "云部署", - "xpack.securitySolution.components.mlPopup.errors.createJobFailureTitle": "创建作业失败", - "xpack.securitySolution.components.mlPopup.errors.startJobFailureTitle": "启动作业失败", "xpack.securitySolution.components.mlPopup.hooks.errors.indexPatternFetchFailureTitle": "索引模式提取失败", "xpack.securitySolution.components.mlPopup.hooks.errors.siemJobFetchFailureTitle": "Security 作业提取失败", "xpack.securitySolution.components.mlPopup.jobsTable.createCustomJobButtonLabel": "创建定制作业", @@ -26241,7 +26215,6 @@ "xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription": "安装 Elastic 预先打包的时间线模板", "xpack.securitySolution.containers.detectionEngine.rulesAndTimelines": "无法提取规则和时间线", "xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription": "无法提取标签", - "xpack.securitySolution.containers.errors.stopJobFailureTitle": "停止作业失败", "xpack.securitySolution.contextMenuItemByRouter.viewDetails": "查看详情", "xpack.securitySolution.customizeEventRenderers.customizeEventRenderersDescription": "事件呈现器自动在事件中传送最相关的详情,以揭示其故事", "xpack.securitySolution.customizeEventRenderers.customizeEventRenderersTitle": "定制事件呈现器", @@ -27369,7 +27342,7 @@ "xpack.securitySolution.detectionEngine.rules.allRules.actions.deleteRuleDescription": "删除规则", "xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription": "复制规则", "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsDescription": "编辑规则设置", - "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip": "您没有 Kibana 操作权限", + "xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges": "您没有 Kibana 操作权限", "xpack.securitySolution.detectionEngine.rules.allRules.actions.exportRuleDescription": "导出规则", "xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedImmutableTitle": "选择内容包含无法删除的不可变规则", "xpack.securitySolution.detectionEngine.rules.allRules.batchActionsTitle": "批处理操作", @@ -28173,57 +28146,13 @@ "xpack.securitySolution.eventsViewer.alerts.overviewTable.signalStatusTitle": "状态", "xpack.securitySolution.eventsViewer.eventsLabel": "事件", "xpack.securitySolution.eventsViewer.showingLabel": "正在显示", - "xpack.securitySolution.exceptions.addException.addEndpointException": "添加终端例外", - "xpack.securitySolution.exceptions.addException.addException": "添加规则例外", - "xpack.securitySolution.exceptions.addException.bulkCloseLabel": "关闭所有与此例外匹配且根据此规则生成的告警", - "xpack.securitySolution.exceptions.addException.bulkCloseLabel.disabled": "关闭所有与此例外匹配且根据此规则生成的告警(不支持列表和非 ECS 字段)", - "xpack.securitySolution.exceptions.addException.cancel": "取消", - "xpack.securitySolution.exceptions.addException.endpointQuarantineText": "在所有终端主机上,与该例外匹配的已隔离文件会自动还原到其原始位置。此例外适用于使用终端例外的所有规则。", - "xpack.securitySolution.exceptions.addException.error": "添加例外失败", - "xpack.securitySolution.exceptions.addException.infoLabel": "满足规则的条件时生成告警,但以下情况除外:", - "xpack.securitySolution.exceptions.addException.operatingSystemPlaceHolder": "选择操作系统", - "xpack.securitySolution.exceptions.addException.sequenceWarning": "此规则的查询包含 EQL 序列语句。创建的例外将应用于序列中的所有事件。", - "xpack.securitySolution.exceptions.addException.success": "已成功添加例外", "xpack.securitySolution.exceptions.badge.readOnly.tooltip": "无法创建、编辑或删除例外", "xpack.securitySolution.exceptions.cancelLabel": "取消", "xpack.securitySolution.exceptions.clearExceptionsLabel": "移除例外列表", "xpack.securitySolution.exceptions.commentEventLabel": "已添加注释", - "xpack.securitySolution.exceptions.dissasociateExceptionListError": "无法移除例外列表", - "xpack.securitySolution.exceptions.editException.bulkCloseLabel": "关闭所有与此例外匹配且根据此规则生成的告警", - "xpack.securitySolution.exceptions.editException.bulkCloseLabel.disabled": "关闭所有与此例外匹配且根据此规则生成的告警(不支持列表和非 ECS 字段)", - "xpack.securitySolution.exceptions.editException.cancel": "取消", - "xpack.securitySolution.exceptions.editException.editEndpointExceptionTitle": "编辑终端例外", - "xpack.securitySolution.exceptions.editException.editExceptionSaveButton": "保存", - "xpack.securitySolution.exceptions.editException.editExceptionTitle": "编辑规则例外", - "xpack.securitySolution.exceptions.editException.endpointQuarantineText": "在所有终端主机上,与该例外匹配的已隔离文件会自动还原到其原始位置。此例外适用于使用终端例外的所有规则。", - "xpack.securitySolution.exceptions.editException.infoLabel": "满足规则的条件时生成告警,但以下情况除外:", - "xpack.securitySolution.exceptions.editException.sequenceWarning": "此规则的查询包含 EQL 序列语句。修改的例外将应用于序列中的所有事件。", - "xpack.securitySolution.exceptions.editException.success": "已成功更新例外", - "xpack.securitySolution.exceptions.editException.versionConflictDescription": "此例外可能自您首次选择编辑后已更新。尝试单击“取消”,重新编辑该例外。", - "xpack.securitySolution.exceptions.editException.versionConflictTitle": "抱歉,有错误", + "xpack.securitySolution.exceptions.disassociateExceptionListError": "无法移除例外列表", "xpack.securitySolution.exceptions.errorLabel": "错误", "xpack.securitySolution.exceptions.fetchError": "提取例外列表时出错", - "xpack.securitySolution.exceptions.exceptionItem.conditions.and": "且", - "xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator": "存在", - "xpack.securitySolution.exceptions.exceptionItem.conditions.existsOperator.not": "不存在", - "xpack.securitySolution.exceptions.exceptionItem.conditions.linux": "Linux", - "xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator": "包含在", - "xpack.securitySolution.exceptions.exceptionItem.conditions.listOperator.not": "未包括在", - "xpack.securitySolution.exceptions.exceptionItem.conditions.macos": "Mac", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator": "属于", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchAnyOperator.not": "不属于", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator": "是", - "xpack.securitySolution.exceptions.exceptionItem.conditions.matchOperator.not": "不是", - "xpack.securitySolution.exceptions.exceptionItem.conditions.nestedOperator": "具有", - "xpack.securitySolution.exceptions.exceptionItem.conditions.os": "OS", - "xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardDoesNotMatchOperator": "不匹配", - "xpack.securitySolution.exceptions.exceptionItem.conditions.wildcardMatchesOperator": "匹配", - "xpack.securitySolution.exceptions.exceptionItem.conditions.windows": "Windows", - "xpack.securitySolution.exceptions.exceptionItem.createdLabel": "创建时间", - "xpack.securitySolution.exceptions.exceptionItem.deleteItemButton": "删除项", - "xpack.securitySolution.exceptions.exceptionItem.editItemButton": "编辑项目", - "xpack.securitySolution.exceptions.exceptionItem.metaDetailsBy": "依据", - "xpack.securitySolution.exceptions.exceptionItem.updatedLabel": "已更新", "xpack.securitySolution.exceptions.modalErrorAccordionText": "显示规则引用信息:", "xpack.securitySolution.exceptions.operatingSystemFullLabel": "操作系统", "xpack.securitySolution.exceptions.operatingSystemLinux": "Linux", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.test.ts index 70987db3f2d49..53b75afd774da 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.test.ts @@ -10,17 +10,28 @@ import { getFilter } from './get_filter'; describe('getFilter', () => { test('should return message filter', () => { expect(getFilter({ message: 'test message' })).toEqual([ - 'message: "test message" OR error.message: "test message"', + '(message: "test message" OR error.message: "test message")', ]); }); test('should return outcome filter', () => { expect(getFilter({ outcomeFilter: ['failure', 'warning', 'success', 'unknown'] })).toEqual([ - 'event.outcome: failure OR kibana.alerting.outcome: warning OR kibana.alerting.outcome:success OR (event.outcome: success AND NOT kibana.alerting.outcome:*) OR event.outcome: unknown', + '(event.outcome: failure OR kibana.alerting.outcome: warning OR kibana.alerting.outcome:success OR (event.outcome: success AND NOT kibana.alerting.outcome:*) OR event.outcome: unknown)', ]); }); test('should return runId filter', () => { expect(getFilter({ runId: 'test' })).toEqual(['kibana.alert.rule.execution.uuid: test']); }); + + test('should return filter for both message and outcome', () => { + expect(getFilter({ message: 'test message', outcomeFilter: ['failure', 'warning'] })).toEqual([ + '(message: "test message" OR error.message: "test message")', + '(event.outcome: failure OR kibana.alerting.outcome: warning)', + ]); + }); + + test('should not return filter if outcome filter is invalid', () => { + expect(getFilter({ outcomeFilter: ['doesntexist'] })).toEqual([]); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.ts index 92bbdc38ae4bb..59ccef9734b65 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/get_filter.ts @@ -19,11 +19,14 @@ export const getFilter = ({ if (message) { const escapedMessage = message.replace(/([\)\(\<\>\}\{\"\:\\])/gm, '\\$&'); - filter.push(`message: "${escapedMessage}" OR error.message: "${escapedMessage}"`); + filter.push(`(message: "${escapedMessage}" OR error.message: "${escapedMessage}")`); } if (outcomeFilter && outcomeFilter.length) { - filter.push(getOutcomeFilter(outcomeFilter)); + const outcomeFilterKQL = getOutcomeFilter(outcomeFilter); + if (outcomeFilterKQL) { + filter.push(`(${outcomeFilterKQL})`); + } } if (runId) { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts index d06447be31fbc..56de4f5c4c890 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts @@ -117,7 +117,7 @@ describe('loadActionErrorLog', () => { "query": Object { "date_end": "2022-03-23T16:17:53.482Z", "date_start": "2022-03-23T16:17:53.482Z", - "filter": "message: \\"test\\" OR error.message: \\"test\\" and kibana.alert.rule.execution.uuid: 123", + "filter": "(message: \\"test\\" OR error.message: \\"test\\") and kibana.alert.rule.execution.uuid: 123", "page": 1, "per_page": 10, "sort": "[{\\"@timestamp\\":{\\"order\\":\\"asc\\"}}]", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.test.ts index c40f0a0b2735d..43655ff21e3bb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.test.ts @@ -47,7 +47,8 @@ describe('loadExecutionLogAggregations', () => { id: 'test-id', dateStart: '2022-03-23T16:17:53.482Z', dateEnd: '2022-03-23T16:17:53.482Z', - outcomeFilter: ['success'], + outcomeFilter: ['success', 'warning'], + message: 'test-message', perPage: 10, page: 0, sort: [sortTimestamp], @@ -84,7 +85,7 @@ describe('loadExecutionLogAggregations', () => { "query": Object { "date_end": "2022-03-23T16:17:53.482Z", "date_start": "2022-03-23T16:17:53.482Z", - "filter": "kibana.alerting.outcome:success OR (event.outcome: success AND NOT kibana.alerting.outcome:*)", + "filter": "(message: \\"test-message\\" OR error.message: \\"test-message\\") and (kibana.alerting.outcome:success OR (event.outcome: success AND NOT kibana.alerting.outcome:*) OR kibana.alerting.outcome: warning)", "page": 1, "per_page": 10, "sort": "[{\\"timestamp\\":{\\"order\\":\\"asc\\"}}]", diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts index df9fc34e17014..a645d89998093 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts @@ -26,7 +26,8 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('disable', () => { + // Failing: See https://github.com/elastic/kibana/issues/141849 + describe.skip('disable', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases/cases_webhook.ts index d56da37907974..481f82546f7be 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases/cases_webhook.ts @@ -456,7 +456,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { expect(resp.body).to.eql({ connector_id: simulatedActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: '[Action][Webhook - Case Management]: Unable to create case. Error: JSON Error: Create case JSON body must be valid JSON. ', @@ -486,7 +486,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { expect(resp.body).to.eql({ connector_id: simulatedActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: '[Action][Webhook - Case Management]: Unable to update case with id 12345. Error: JSON Error: Update case JSON body must be valid JSON. ', @@ -553,7 +553,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { expect(resp.body).to.eql({ connector_id: simulatedActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: '[Action][Webhook - Case Management]: Unable to create comment at case with id 123. Error: JSON Error: Create comment JSON body must be valid JSON. ', @@ -620,7 +620,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { expect(resp.body).to.eql({ connector_id: simulatedActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: '[Action][Webhook - Case Management]: Unable to create case. Error: Invalid Create case URL: Error: Invalid protocol. ', @@ -650,7 +650,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { expect(resp.body).to.eql({ connector_id: simulatedActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: '[Action][Webhook - Case Management]: Unable to update case with id 12345. Error: Invalid Update case URL: Error: Invalid URL. ', @@ -717,7 +717,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { expect(resp.body).to.eql({ connector_id: simulatedActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: '[Action][Webhook - Case Management]: Unable to create comment at case with id 123. Error: Invalid Create comment URL: Error: Invalid URL. ', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/stack/opsgenie.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/stack/opsgenie.ts index e1011059b8532..adce611ec3d1d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/stack/opsgenie.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/stack/opsgenie.ts @@ -181,7 +181,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ connector_id: opsgenieActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: `Sub action "invalidAction" is not registered. Connector id: ${opsgenieActionId}. Connector name: Opsgenie. Connector type: .opsgenie`, }); @@ -199,7 +199,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ connector_id: opsgenieActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: 'Request validation failed (Error: [message]: expected value of type [string] but got [undefined])', @@ -218,7 +218,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ connector_id: opsgenieActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: 'Request validation failed (Error: [alias]: expected value of type [string] but got [undefined])', @@ -250,7 +250,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ connector_id: opsgenieActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: 'Request validation failed (Error: [responders.0]: types that failed validation:\n- [responders.0.0.type]: types that failed validation:\n - [responders.0.type.0]: expected value to equal [team]\n - [responders.0.type.1]: expected value to equal [user]\n - [responders.0.type.2]: expected value to equal [escalation]\n - [responders.0.type.3]: expected value to equal [schedule]\n- [responders.0.1.id]: expected value of type [string] but got [undefined])', @@ -279,7 +279,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ connector_id: opsgenieActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: 'Request validation failed (Error: [responders.0]: types that failed validation:\n- [responders.0.0.name]: expected value of type [string] but got [undefined]\n- [responders.0.1.id]: expected value of type [string] but got [undefined])', @@ -381,7 +381,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ connector_id: opsgenieActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: 'Request validation failed (Error: [visibleTo.0]: types that failed validation:\n- [visibleTo.0.0.type]: expected value to equal [team]\n- [visibleTo.0.1.id]: expected value of type [string] but got [undefined]\n- [visibleTo.0.2.id]: expected value of type [string] but got [undefined]\n- [visibleTo.0.3.username]: expected value of type [string] but got [undefined])', @@ -445,7 +445,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ connector_id: opsgenieActionId, status: 'error', - retry: false, + retry: true, message: 'an error occurred while running the action', service_message: 'Request validation failed (Error: [details.bananas]: expected value of type [string] but got [number])', @@ -680,7 +680,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ status: 'error', message: 'an error occurred while running the action', - retry: false, + retry: true, connector_id: opsgenieActionId, service_message: 'Status code: undefined. Message: Message: failed', }); @@ -702,7 +702,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { expect(body).to.eql({ status: 'error', message: 'an error occurred while running the action', - retry: false, + retry: true, connector_id: opsgenieActionId, service_message: 'Status code: undefined. Message: Message: failed', }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts index 350361d58a395..bbf97b016f2ba 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts @@ -166,7 +166,7 @@ export default function createActionTests({ getService }: FtrProviderContext) { expect(execRes.body).to.eql({ status: 'error', message: 'an error occurred while running the action', - retry: false, + retry: true, connector_id: res.body.id, service_message: 'Request validation failed (Error: [id]: expected value of type [string] but got [undefined])', @@ -245,7 +245,7 @@ export default function createActionTests({ getService }: FtrProviderContext) { expect(execRes.body).to.eql({ status: 'error', message: 'an error occurred while running the action', - retry: false, + retry: true, connector_id: res.body.id, service_message: `Sub action \"notRegistered\" is not registered. Connector id: ${res.body.id}. Connector name: Test: Sub action connector. Connector type: .test-sub-action-connector`, }); @@ -265,7 +265,7 @@ export default function createActionTests({ getService }: FtrProviderContext) { expect(execRes.body).to.eql({ status: 'error', message: 'an error occurred while running the action', - retry: false, + retry: true, connector_id: res.body.id, service_message: `Method \"notAFunction\" does not exists in service. Sub action: \"notAFunction\". Connector id: ${res.body.id}. Connector name: Test: Sub action connector. Connector type: .test-sub-action-connector`, }); @@ -285,7 +285,7 @@ export default function createActionTests({ getService }: FtrProviderContext) { expect(execRes.body).to.eql({ status: 'error', message: 'an error occurred while running the action', - retry: false, + retry: true, connector_id: res.body.id, service_message: `Method \"notExist\" does not exists in service. Sub action: \"notExist\". Connector id: ${res.body.id}. Connector name: Test: Sub action connector. Connector type: .test-sub-action-connector`, }); @@ -308,7 +308,7 @@ export default function createActionTests({ getService }: FtrProviderContext) { expect(execRes.body).to.eql({ status: 'error', message: 'an error occurred while running the action', - retry: false, + retry: true, connector_id: res.body.id, service_message: 'You should register at least one subAction for your connector type', }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/enqueue.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/enqueue.ts index 084c105aa723a..9f0eea9d91929 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/enqueue.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/enqueue.ts @@ -70,7 +70,7 @@ export default function ({ getService }: FtrProviderContext) { await esTestIndexTool.waitForDocs('action:test.index-record', reference, 1); }); - it('should cleanup task after a failure', async () => { + it('should retry task after a failure', async () => { const testStart = new Date().toISOString(); const { body: createdAction } = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) @@ -85,6 +85,7 @@ export default function ({ getService }: FtrProviderContext) { objectRemover.add(Spaces.space1.id, createdAction.id, 'action', 'actions'); const reference = `actions-enqueue-2:${Spaces.space1.id}:${createdAction.id}`; + let runAt: number; await supertest .post( `${getUrlPrefix(Spaces.space1.id)}/api/alerts_fixture/${createdAction.id}/enqueue_action` @@ -96,7 +97,10 @@ export default function ({ getService }: FtrProviderContext) { index: ES_TEST_INDEX_NAME, }, }) - .expect(204); + .expect(204) + .then(() => { + runAt = Date.now(); + }); await esTestIndexTool.waitForDocs('action:test.failing', reference, 1); await retry.try(async () => { @@ -123,7 +127,9 @@ export default function ({ getService }: FtrProviderContext) { }, }, }); - expect((searchResult.hits.total as estypes.SearchTotalHits).value).to.eql(0); + const hit = searchResult.hits.hits as Array>; + expect(Date.parse(hit[0]._source.task.runAt)).to.greaterThan(runAt); + expect(Date.parse(hit[0]._source.task.attempts)).to.greaterThan(1); }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts index c6330e660aa24..40b574063fbe5 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts @@ -133,7 +133,7 @@ export default function ({ getService }: FtrProviderContext) { status: 'error', message: 'an error occurred while running the action', service_message: `expected failure for ${ES_TEST_INDEX_NAME} ${reference}`, - retry: false, + retry: true, }); await validateEventLog({ @@ -142,7 +142,7 @@ export default function ({ getService }: FtrProviderContext) { actionTypeId: 'test.failing', outcome: 'failure', message: `action execution failure: test.failing:${createdAction.id}: failing action`, - errorMessage: `an error occurred while running the action: expected failure for .kibana-alerting-test-data actions-failure-1:space1`, + errorMessage: `an error occurred while running the action: expected failure for .kibana-alerting-test-data actions-failure-1:space1; retry: true`, }); }); @@ -327,7 +327,7 @@ export default function ({ getService }: FtrProviderContext) { status: 'error', message: 'an error occurred while running the action', serviceMessage: `expected failure for ${ES_TEST_INDEX_NAME} ${reference}`, - retry: false, + retry: true, }); }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts index 4dae8cdccd1cb..5a3de02ab9794 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts @@ -37,7 +37,8 @@ export default function ruleTests({ getService }: FtrProviderContext) { const esTestIndexTool = new ESTestIndexTool(es, retry); const esTestIndexToolOutput = new ESTestIndexTool(es, retry, ES_TEST_OUTPUT_INDEX_NAME); - describe('rule', async () => { + // Failing: See https://github.com/elastic/kibana/issues/142335 + describe.skip('rule', async () => { let endDate: string; let connectorId: string; const objectRemover = new ObjectRemover(supertest); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_action_error_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_action_error_log.ts index 19c2270d07880..78d6a09ac41e3 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_action_error_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_action_error_log.ts @@ -115,7 +115,7 @@ export default function createGetActionErrorLogTests({ getService }: FtrProvider for (const errors of response.body.errors) { expect(errors.type).to.equal('actions'); expect(errors.message).to.equal( - `action execution failure: test.throw:${createdConnector.id}: connector that throws - an error occurred while running the action: this action is intended to fail` + `action execution failure: test.throw:${createdConnector.id}: connector that throws - an error occurred while running the action: this action is intended to fail; retry: true` ); } }); diff --git a/x-pack/test/api_integration/apis/uptime/rest/delete_monitor_project.ts b/x-pack/test/api_integration/apis/uptime/rest/delete_monitor_project.ts new file mode 100644 index 0000000000000..25afc4e665180 --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/delete_monitor_project.ts @@ -0,0 +1,524 @@ +/* + * 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 uuid from 'uuid'; +import expect from '@kbn/expect'; +import { format as formatUrl } from 'url'; +import { ConfigKey, ProjectMonitorsRequest } from '@kbn/synthetics-plugin/common/runtime_types'; +import { INSUFFICIENT_FLEET_PERMISSIONS } from '@kbn/synthetics-plugin/server/synthetics_service/project_monitor/project_monitor_formatter'; +import { REQUEST_TOO_LARGE } from '@kbn/synthetics-plugin/server/routes/monitor_cruds/delete_monitor_project'; +import { API_URLS } from '@kbn/synthetics-plugin/common/constants'; +import { syntheticsMonitorType } from '@kbn/synthetics-plugin/server/legacy_uptime/lib/saved_objects/synthetics_monitor'; +import { PackagePolicy } from '@kbn/fleet-plugin/common'; +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { getFixtureJson } from './helper/get_fixture_json'; +import { PrivateLocationTestService } from './services/private_location_test_service'; +import { parseStreamApiResponse } from './add_monitor_project'; + +export default function ({ getService }: FtrProviderContext) { + describe('DeleteProjectMonitors', function () { + this.tags('skipCloud'); + + const supertest = getService('supertest'); + const config = getService('config'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const security = getService('security'); + const kibanaServerUrl = formatUrl(config.get('servers.kibana')); + const kibanaServer = getService('kibanaServer'); + const projectMonitorEndpoint = kibanaServerUrl + API_URLS.SYNTHETICS_MONITORS_PROJECT_LEGACY; + + let projectMonitors: ProjectMonitorsRequest; + + let testPolicyId = ''; + const testPrivateLocations = new PrivateLocationTestService(getService); + + const setUniqueIds = (request: ProjectMonitorsRequest) => { + return { + ...request, + monitors: request.monitors.map((monitor) => ({ ...monitor, id: uuid.v4() })), + }; + }; + + before(async () => { + await supertest.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200); + await supertest + .post('/api/fleet/epm/packages/synthetics/0.10.3') + .set('kbn-xsrf', 'true') + .send({ force: true }) + .expect(200); + + const testPolicyName = 'Fleet test server policy' + Date.now(); + const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName); + testPolicyId = apiResponse.body.item.id; + await testPrivateLocations.setTestLocations([testPolicyId]); + }); + + beforeEach(() => { + projectMonitors = setUniqueIds(getFixtureJson('project_browser_monitor')); + }); + + it('only allows 250 requests at a time', async () => { + const project = 'test-brower-suite'; + const monitors = []; + for (let i = 0; i < 251; i++) { + monitors.push({ + ...projectMonitors.monitors[0], + id: `test-id-${i}`, + name: `test-name-${i}`, + }); + } + + try { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + monitors, + }) + ); + + const savedObjectsResponse = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true'); + const { total } = savedObjectsResponse.body; + expect(total).to.eql(251); + const monitorsToDelete = monitors.map((monitor) => monitor.id); + + const response = await supertest + .delete(API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .set('kbn-xsrf', 'true') + .send({ monitors: monitorsToDelete }) + .expect(400); + const { message } = response.body; + expect(message).to.eql(REQUEST_TOO_LARGE); + } finally { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: [], + }) + ); + } + }); + + it('project monitors - handles browser monitors', async () => { + const monitorToDelete = 'second-monitor-id'; + const monitors = [ + projectMonitors.monitors[0], + { + ...projectMonitors.monitors[0], + id: monitorToDelete, + }, + ]; + const project = 'test-brower-suite'; + + try { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + monitors, + }) + ); + + const savedObjectsResponse = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total } = savedObjectsResponse.body; + expect(total).to.eql(2); + const monitorsToDelete = [monitorToDelete]; + + const response = await supertest + .delete(API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .set('kbn-xsrf', 'true') + .send({ monitors: monitorsToDelete }) + .expect(200); + + expect(response.body.deleted_monitors).to.eql(monitorsToDelete); + + const responseAfterDeletion = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total: totalAfterDeletion } = responseAfterDeletion.body; + expect(totalAfterDeletion).to.eql(1); + } finally { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: [], + }) + ); + } + }); + + it('does not delete monitors from a different project', async () => { + const monitors = [...projectMonitors.monitors]; + const project = 'test-brower-suite'; + const secondProject = 'second-project'; + + try { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + monitors, + }) + ); + + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project: secondProject, + monitors, + }) + ); + + const savedObjectsResponse = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const secondProjectSavedObjectResponse = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${secondProject}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total } = savedObjectsResponse.body; + const { total: secondProjectTotal } = secondProjectSavedObjectResponse.body; + expect(total).to.eql(monitors.length); + expect(secondProjectTotal).to.eql(monitors.length); + const monitorsToDelete = monitors.map((monitor) => monitor.id); + + const response = await supertest + .delete(API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .set('kbn-xsrf', 'true') + .send({ monitors: monitorsToDelete }) + .expect(200); + + expect(response.body.deleted_monitors).to.eql(monitorsToDelete); + + const responseAfterDeletion = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const secondResponseAfterDeletion = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${secondProject}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total: totalAfterDeletion } = responseAfterDeletion.body; + const { total: secondProjectTotalAfterDeletion } = secondResponseAfterDeletion.body; + expect(totalAfterDeletion).to.eql(0); + expect(secondProjectTotalAfterDeletion).to.eql(monitors.length); + } finally { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: [], + }) + ); + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project: secondProject, + keep_stale: false, + monitors: [], + }) + ); + } + }); + + it('does not delete monitors from the same project in a different space project', async () => { + const monitors = [...projectMonitors.monitors]; + const project = 'test-brower-suite'; + const SPACE_ID = `test-space-${uuid.v4()}`; + const SPACE_NAME = `test-space-name ${uuid.v4()}`; + const secondSpaceProjectMonitorApiRoute = `${kibanaServerUrl}/s/${SPACE_ID}${API_URLS.SYNTHETICS_MONITORS_PROJECT_LEGACY}`; + await kibanaServer.spaces.create({ id: SPACE_ID, name: SPACE_NAME }); + + try { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + monitors, + }) + ); + + await parseStreamApiResponse( + secondSpaceProjectMonitorApiRoute, + JSON.stringify({ + ...projectMonitors, + project, + monitors, + }) + ); + + const savedObjectsResponse = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const secondSpaceProjectSavedObjectResponse = await supertest + .get(`/s/${SPACE_ID}${API_URLS.SYNTHETICS_MONITORS}`) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total } = savedObjectsResponse.body; + const { total: secondSpaceTotal } = secondSpaceProjectSavedObjectResponse.body; + + expect(total).to.eql(monitors.length); + expect(secondSpaceTotal).to.eql(monitors.length); + const monitorsToDelete = monitors.map((monitor) => monitor.id); + + const response = await supertest + .delete( + `/s/${SPACE_ID}${API_URLS.SYNTHETICS_MONITORS_PROJECT.replace( + '{projectName}', + project + )}` + ) + .set('kbn-xsrf', 'true') + .send({ monitors: monitorsToDelete }) + .expect(200); + + expect(response.body.deleted_monitors).to.eql(monitorsToDelete); + + const responseAfterDeletion = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const secondSpaceResponseAfterDeletion = await supertest + .get(`/s/${SPACE_ID}${API_URLS.SYNTHETICS_MONITORS}`) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total: totalAfterDeletion } = responseAfterDeletion.body; + const { total: secondProjectTotalAfterDeletion } = secondSpaceResponseAfterDeletion.body; + expect(totalAfterDeletion).to.eql(monitors.length); + expect(secondProjectTotalAfterDeletion).to.eql(0); + } finally { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: [], + }) + ); + await parseStreamApiResponse( + secondSpaceProjectMonitorApiRoute, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: [], + }) + ); + } + }); + + it('deletes integration policies when project monitors are deleted', async () => { + const monitors = [ + { ...projectMonitors.monitors[0], privateLocations: ['Test private location 0'] }, + ]; + const project = 'test-brower-suite'; + + try { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + monitors, + }) + ); + + const savedObjectsResponse = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total } = savedObjectsResponse.body; + expect(total).to.eql(monitors.length); + const apiResponsePolicy = await supertest.get( + '/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics' + ); + + const packagePolicy = apiResponsePolicy.body.items.find( + (pkgPolicy: PackagePolicy) => + pkgPolicy.id === + savedObjectsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID] + + '-' + + testPolicyId + ); + expect(packagePolicy.policy_id).to.be(testPolicyId); + + const monitorsToDelete = monitors.map((monitor) => monitor.id); + + const response = await supertest + .delete(API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .set('kbn-xsrf', 'true') + .send({ monitors: monitorsToDelete }) + .expect(200); + + expect(response.body.deleted_monitors).to.eql(monitorsToDelete); + + const responseAfterDeletion = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total: totalAfterDeletion } = responseAfterDeletion.body; + expect(totalAfterDeletion).to.eql(0); + const apiResponsePolicy2 = await supertest.get( + '/api/fleet/package_policies?page=1&perPage=2000&kuery=ingest-package-policies.package.name%3A%20synthetics' + ); + + const packagePolicy2 = apiResponsePolicy2.body.items.find( + (pkgPolicy: PackagePolicy) => + pkgPolicy.id === + savedObjectsResponse.body.monitors[0].attributes[ConfigKey.CUSTOM_HEARTBEAT_ID] + + '-' + + testPolicyId + ); + expect(packagePolicy2).to.be(undefined); + } finally { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: [], + }) + ); + } + }); + + it('returns 403 when a user without fleet permissions attempts to delete a project monitor with a private location', async () => { + const project = 'test-brower-suite'; + const secondMonitor = { + ...projectMonitors.monitors[0], + id: 'test-id-2', + privateLocations: ['Test private location 0'], + }; + const testMonitors = [projectMonitors.monitors[0], secondMonitor]; + const monitorsToDelete = testMonitors.map((monitor) => monitor.id); + const username = 'admin'; + const roleName = 'uptime read only'; + const password = `${username} - password`; + try { + await security.role.create(roleName, { + kibana: [ + { + feature: { + uptime: ['all'], + }, + spaces: ['*'], + }, + ], + }); + await security.user.create(username, { + password, + roles: [roleName], + full_name: 'a kibana user', + }); + + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: testMonitors, + }) + ); + + const savedObjectsResponse = await supertest + .get(API_URLS.SYNTHETICS_MONITORS) + .query({ + filter: `${syntheticsMonitorType}.attributes.project_id: "${project}"`, + }) + .set('kbn-xsrf', 'true') + .expect(200); + const { total } = savedObjectsResponse.body; + expect(total).to.eql(2); + + const { + body: { message }, + } = await supertestWithoutAuth + .delete(API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .set('kbn-xsrf', 'true') + .auth(username, password) + .send({ monitors: monitorsToDelete }) + .expect(403); + expect(message).to.eql(INSUFFICIENT_FLEET_PERMISSIONS); + } finally { + await parseStreamApiResponse( + projectMonitorEndpoint, + JSON.stringify({ + ...projectMonitors, + project, + keep_stale: false, + monitors: [], + }) + ); + await security.user.delete(username); + await security.role.delete(roleName); + } + }); + }); +} diff --git a/x-pack/test/api_integration/apis/uptime/rest/index.ts b/x-pack/test/api_integration/apis/uptime/rest/index.ts index e1fd22c2baf8a..2e3e6f21f34c2 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/index.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/index.ts @@ -82,6 +82,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./add_monitor_private_location')); loadTestFile(require.resolve('./edit_monitor')); loadTestFile(require.resolve('./delete_monitor')); + loadTestFile(require.resolve('./delete_monitor_project')); loadTestFile(require.resolve('./synthetics_enablement')); }); }); diff --git a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts index 53c5fec2bd5bf..295f38e5db9bb 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts @@ -8,7 +8,7 @@ import { apm, timerange } from '@kbn/apm-synthtrace'; import expect from '@kbn/expect'; import { range } from 'lodash'; -import { AlertType } from '@kbn/apm-plugin/common/alert_types'; +import { ApmRuleType } from '@kbn/apm-plugin/common/rules/apm_rule_types'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createAndRunApmMlJob } from '../../common/utils/create_and_run_apm_ml_job'; import { waitForRuleStatus } from './wait_for_rule_status'; @@ -96,7 +96,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, tags: ['apm', 'service.name:service-a'], name: 'Latency anomaly | service-a', - rule_type_id: AlertType.Anomaly, + rule_type_id: ApmRuleType.Anomaly, notify_when: 'onActiveAlert', actions: [], }); diff --git a/x-pack/test/apm_api_integration/tests/alerts/chart_preview.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/chart_preview.spec.ts index 10808560f562c..89dc5e5f41089 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/chart_preview.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/chart_preview.spec.ts @@ -33,7 +33,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('transaction_error_rate (without data)', async () => { const options = getOptions(); const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', ...options, }); @@ -41,12 +41,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(response.body.errorRateChartPreview).to.eql([]); }); - it('transaction_error_count (without data)', async () => { + it('error_count (without data)', async () => { const options = getOptions(); options.params.query.transactionType = undefined; const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_count', + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', ...options, }); @@ -58,7 +58,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = getOptions(); const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_duration', + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', ...options, }); @@ -71,7 +71,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('transaction_error_rate (with data)', async () => { const options = getOptions(); const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_rate', + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', ...options, }); @@ -83,12 +83,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { ).to.equal(true); }); - it('transaction_error_count (with data)', async () => { + it('error_count (with data)', async () => { const options = getOptions(); options.params.query.transactionType = undefined; const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_count', + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', ...options, }); @@ -104,7 +104,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = getOptions(); const response = await apmApiClient.readUser({ ...options, - endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_duration', + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', }); expect(response.status).to.be(200); diff --git a/x-pack/test/apm_api_integration/tests/suggestions/generate_data.ts b/x-pack/test/apm_api_integration/tests/suggestions/generate_data.ts new file mode 100644 index 0000000000000..13d6359e0a733 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/suggestions/generate_data.ts @@ -0,0 +1,77 @@ +/* + * 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 { apm, timerange } from '@kbn/apm-synthtrace'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import { times } from 'lodash'; + +export async function generateData({ + synthtraceEsClient, + start, + end, +}: { + synthtraceEsClient: ApmSynthtraceEsClient; + start: number; + end: number; +}) { + const services = times(5).flatMap((serviceId) => { + return ['go', 'java'].flatMap((agentName) => { + return ['production', 'development', 'staging'].flatMap((environment) => { + return times(5).flatMap((envId) => { + const service = apm + .service({ + name: `${agentName}-${serviceId}`, + environment: `${environment}-${envId}`, + agentName, + }) + .instance('instance-a'); + + return service; + }); + }); + }); + }); + + const transactionNames = [ + 'GET /api/product/:id', + 'PUT /api/product/:id', + 'GET /api/user/:id', + 'PUT /api/user/:id', + ]; + + const phpService = apm + .service({ + name: `custom-php-service`, + environment: `custom-php-environment`, + agentName: 'php', + }) + .instance('instance-a'); + + const docs = timerange(start, end) + .ratePerMinute(1) + .generator((timestamp) => { + const autoGeneratedDocs = services.flatMap((service) => { + return transactionNames.flatMap((transactionName) => { + return service + .transaction({ transactionName, transactionType: 'my-custom-type' }) + .timestamp(timestamp) + .duration(1000); + }); + }); + + const customDoc = phpService + .transaction({ + transactionName: 'GET /api/php/memory', + transactionType: 'custom-php-type', + }) + .timestamp(timestamp) + .duration(1000); + + return [...autoGeneratedDocs, customDoc]; + }); + + return await synthtraceEsClient.index(docs); +} diff --git a/x-pack/test/apm_api_integration/tests/suggestions/suggestions.spec.ts b/x-pack/test/apm_api_integration/tests/suggestions/suggestions.spec.ts index 692cd1c0cf7f1..db15db23776c7 100644 --- a/x-pack/test/apm_api_integration/tests/suggestions/suggestions.spec.ts +++ b/x-pack/test/apm_api_integration/tests/suggestions/suggestions.spec.ts @@ -7,139 +7,286 @@ import { SERVICE_ENVIRONMENT, SERVICE_NAME, + TRANSACTION_NAME, TRANSACTION_TYPE, } from '@kbn/apm-plugin/common/elasticsearch_fieldnames'; -import archives_metadata from '../../common/fixtures/es_archiver/archives_metadata'; +import expect from '@kbn/expect'; import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { generateData } from './generate_data'; + +const startNumber = new Date('2021-01-01T00:00:00.000Z').getTime(); +const endNumber = new Date('2021-01-01T00:05:00.000Z').getTime() - 1; + +const start = new Date(startNumber).toISOString(); +const end = new Date(endNumber).toISOString(); export default function suggestionsTests({ getService }: FtrProviderContext) { const registry = getService('registry'); const apmApiClient = getService('apmApiClient'); - const archiveName = 'apm_8.0.0'; - const { start, end } = archives_metadata[archiveName]; - - registry.when( - 'suggestions when data is loaded', - { config: 'basic', archives: [archiveName] }, - () => { - describe('with environment', () => { - describe('with an empty string parameter', () => { - it('returns all environments', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/suggestions', - params: { query: { fieldName: SERVICE_ENVIRONMENT, fieldValue: '', start, end } }, - }); - - expectSnapshot(body).toMatchInline(` - Object { - "terms": Array [ - "production", - "testing", - ], - } - `); + const synthtraceEsClient = getService('synthtraceEsClient'); + + registry.when('suggestions when data is loaded', { config: 'basic', archives: [] }, async () => { + before(async () => { + await generateData({ + synthtraceEsClient, + start: startNumber, + end: endNumber, + }); + }); + + after(() => synthtraceEsClient.clean()); + + describe(`field: ${SERVICE_ENVIRONMENT}`, () => { + describe('when fieldValue is empty', () => { + it('returns all environments', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { + query: { fieldName: SERVICE_ENVIRONMENT, fieldValue: '', start, end }, + }, + }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "custom-php-environment", + "development-0", + "development-1", + "development-2", + "development-3", + "development-4", + "production-0", + "production-1", + "production-2", + "production-3", + "production-4", + "staging-0", + "staging-1", + "staging-2", + "staging-3", + "staging-4", + ] + `); + }); + }); + + describe('when fieldValue is not empty', () => { + it('returns environments that start with the fieldValue', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: SERVICE_ENVIRONMENT, fieldValue: 'prod', start, end } }, + }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "production-0", + "production-1", + "production-2", + "production-3", + "production-4", + ] + `); + }); + + it('returns environments that contain the fieldValue', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { + query: { fieldName: SERVICE_ENVIRONMENT, fieldValue: 'evelopment', start, end }, + }, + }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "development-0", + "development-1", + "development-2", + "development-3", + "development-4", + ] + `); + }); + + it('returns no results if nothing matches', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { + query: { fieldName: SERVICE_ENVIRONMENT, fieldValue: 'foobar', start, end }, + }, + }); + + expect(body.terms).to.eql([]); + }); + }); + }); + + describe(`field: ${SERVICE_NAME}`, () => { + describe('when fieldValue is empty', () => { + it('returns all service names', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: SERVICE_NAME, fieldValue: '', start, end } }, + }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "custom-php-service", + "go-0", + "go-1", + "go-2", + "go-3", + "go-4", + "java-0", + "java-1", + "java-2", + "java-3", + "java-4", + ] + `); + }); + }); + + describe('when fieldValue is not empty', () => { + it('returns services that start with the fieldValue', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: SERVICE_NAME, fieldValue: 'java', start, end } }, + }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "java-0", + "java-1", + "java-2", + "java-3", + "java-4", + ] + `); + }); + + it('returns services that contains the fieldValue', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: SERVICE_NAME, fieldValue: '1', start, end } }, }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "go-1", + "java-1", + ] + `); }); + }); + }); + + describe(`field: ${TRANSACTION_TYPE}`, () => { + describe('when fieldValue is empty', () => { + it('returns all transaction types', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: TRANSACTION_TYPE, fieldValue: '', start, end } }, + }); - describe('with a string parameter', () => { - it('returns items matching the string parameter', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/suggestions', - params: { query: { fieldName: SERVICE_ENVIRONMENT, fieldValue: 'pr', start, end } }, - }); - - expectSnapshot(body).toMatchInline(` - Object { - "terms": Array [ - "production", - ], - } + expectSnapshot(body.terms).toMatchInline(` + Array [ + "custom-php-type", + "my-custom-type", + ] `); + }); + }); + + describe('with a string parameter', () => { + it('returns items matching the string parameter', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: TRANSACTION_TYPE, fieldValue: 'custom', start, end } }, }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "custom-php-type", + ] + `); }); }); + }); - describe('with service name', () => { - describe('with an empty string parameter', () => { - it('returns all services', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/suggestions', - params: { query: { fieldName: SERVICE_NAME, fieldValue: '', start, end } }, - }); - - expectSnapshot(body).toMatchInline(` - Object { - "terms": Array [ - "auditbeat", - "opbeans-dotnet", - "opbeans-go", - "opbeans-java", - "opbeans-node", - "opbeans-python", - "opbeans-ruby", - "opbeans-rum", - ], - } - `); + describe(`field: ${TRANSACTION_NAME}`, () => { + describe('when fieldValue is empty', () => { + it('returns all transaction names', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: TRANSACTION_NAME, fieldValue: '', start, end } }, }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "GET /api/php/memory", + "GET /api/product/:id", + "GET /api/user/:id", + "PUT /api/product/:id", + "PUT /api/user/:id", + ] + `); }); + }); - describe('with a string parameter', () => { - it('returns items matching the string parameter', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/suggestions', - params: { query: { fieldName: SERVICE_NAME, fieldValue: 'aud', start, end } }, - }); - - expectSnapshot(body).toMatchInline(` - Object { - "terms": Array [ - "auditbeat", - ], - } - `); + describe('with a string parameter', () => { + it('returns items matching the string parameter', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { query: { fieldName: TRANSACTION_NAME, fieldValue: 'product', start, end } }, }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "GET /api/product/:id", + "PUT /api/product/:id", + ] + `); }); }); - describe('with transaction type', () => { - describe('with an empty string parameter', () => { - it('returns all transaction types', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/suggestions', - params: { query: { fieldName: TRANSACTION_TYPE, fieldValue: '', start, end } }, - }); - - expectSnapshot(body).toMatchInline(` - Object { - "terms": Array [ - "Worker", - "celery", - "page-load", - "request", - ], - } - `); + describe('when limiting the suggestions to a specific service', () => { + it('returns items matching the string parameter', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { + query: { + serviceName: 'custom-php-service', + fieldName: TRANSACTION_NAME, + fieldValue: '', + start, + end, + }, + }, }); + + expectSnapshot(body.terms).toMatchInline(` + Array [ + "GET /api/php/memory", + ] + `); }); - describe('with a string parameter', () => { - it('returns items matching the string parameter', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/suggestions', - params: { query: { fieldName: TRANSACTION_TYPE, fieldValue: 'w', start, end } }, - }); - - expectSnapshot(body).toMatchInline(` - Object { - "terms": Array [ - "Worker", - ], - } - `); + it('does not return transactions from other services', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/suggestions', + params: { + query: { + serviceName: 'custom-php-service', + fieldName: TRANSACTION_NAME, + fieldValue: 'product', + start, + end, + }, + }, }); + + expect(body.terms).to.eql([]); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts index c2b53a008f43a..574a843a858d7 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts @@ -162,21 +162,19 @@ export default ({ getService }: FtrProviderContext): void => { auth: { user: superUser, space: 'space1' }, }); - const [_, caseWithDeleteAssignee1, caseWithDeleteAssignee2] = await Promise.all([ - createCase(supertest, postCaseReq), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profile[0].uid }], - }) - ), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profile[0].uid }], - }) - ), - ]); + await createCase(supertest, postCaseReq); + const caseWithDeleteAssignee1 = await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profile[0].uid }], + }) + ); + const caseWithDeleteAssignee2 = await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profile[0].uid }], + }) + ); const cases = await findCases({ supertest, @@ -202,21 +200,19 @@ export default ({ getService }: FtrProviderContext): void => { auth: { user: superUser, space: 'space1' }, }); - const [_, caseWithDeleteAssignee1, caseWithDeleteAssignee2] = await Promise.all([ - createCase(supertest, postCaseReq), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profileUidsToFilter[0].uid }], - }) - ), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profileUidsToFilter[1].uid }], - }) - ), - ]); + await createCase(supertest, postCaseReq); + const caseWithDeleteAssignee1 = await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profileUidsToFilter[0].uid }], + }) + ); + const caseWithDeleteAssignee2 = await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profileUidsToFilter[1].uid }], + }) + ); const cases = await findCases({ supertest, @@ -242,21 +238,20 @@ export default ({ getService }: FtrProviderContext): void => { auth: { user: superUser, space: 'space1' }, }); - const [caseWithNoAssignees] = await Promise.all([ - createCase(supertest, postCaseReq), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profile[0].uid }], - }) - ), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profile[0].uid }], - }) - ), - ]); + const caseWithNoAssignees = await createCase(supertest, postCaseReq); + await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profile[0].uid }], + }) + ); + + await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profile[0].uid }], + }) + ); const cases = await findCases({ supertest, @@ -282,21 +277,20 @@ export default ({ getService }: FtrProviderContext): void => { auth: { user: superUser, space: 'space1' }, }); - const [caseWithNoAssignees, caseWithDeleteAssignee1] = await Promise.all([ - createCase(supertest, postCaseReq), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profileUidsToFilter[0].uid }], - }) - ), - createCase( - supertest, - getPostCaseRequest({ - assignees: [{ uid: profileUidsToFilter[1].uid }], - }) - ), - ]); + const caseWithNoAssignees = await createCase(supertest, postCaseReq); + const caseWithDeleteAssignee1 = await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profileUidsToFilter[0].uid }], + }) + ); + + await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: profileUidsToFilter[1].uid }], + }) + ); const cases = await findCases({ supertest, diff --git a/x-pack/test/common/lib/test_data_loader.ts b/x-pack/test/common/lib/test_data_loader.ts index 64a69a5ac8170..280c959e691bd 100644 --- a/x-pack/test/common/lib/test_data_loader.ts +++ b/x-pack/test/common/lib/test_data_loader.ts @@ -5,6 +5,10 @@ * 2.0. */ +import { LegacyUrlAlias } from '@kbn/core-saved-objects-base-server-internal'; +import Fs from 'fs/promises'; +import { FtrProviderContext } from '../ftr_provider_context'; + export const SPACE_1 = { id: 'space_1', name: 'Space 1', @@ -19,6 +23,13 @@ export const SPACE_2 = { disabledFeatures: [], }; +async function parseLegacyUrlAliases(path: string): Promise { + return (await Fs.readFile(path, 'utf-8')) + .split(/\r?\n\r?\n/) + .filter((line) => !!line) + .map((line) => JSON.parse(line)); +} + // Objects can only be imported in one space at a time. To have test saved objects // that are shared in multiple spaces we should import all objects in the "original" // spaces first and then share them to other spaces as a subsequent operation. @@ -62,8 +73,7 @@ const OBJECTS_TO_SHARE: Array<{ }, ]; -// @ts-ignore -export function getTestDataLoader({ getService }) { +export function getTestDataLoader({ getService }: Pick) { const spacesService = getService('spaces'); const kbnServer = getService('kibanaServer'); const supertest = getService('supertest'); @@ -112,6 +122,40 @@ export function getTestDataLoader({ getService }) { } }, + createLegacyUrlAliases: async ( + spaceData: Array<{ spaceName: string | null; dataUrl: string; disabled?: boolean }> + ) => { + await Promise.all( + spaceData.map(async (data) => { + const spaceString = data.spaceName ?? 'default'; + + const aliases = await parseLegacyUrlAliases(data.dataUrl); + log.info('creating', aliases.length, 'legacy URL aliases', { + space: spaceString, + }); + + await Promise.all( + aliases.map(async (alias) => { + await es.create({ + id: `legacy-url-alias:${spaceString}:${alias.targetType}:${alias.sourceId}`, + index: '.kibana', + refresh: 'wait_for', + document: { + type: 'legacy-url-alias', + updated_at: '2017-09-21T18:51:23.794Z', + 'legacy-url-alias': { + ...alias, + targetNamespace: spaceString, + ...(data.disabled && { disabled: data.disabled }), + }, + }, + }); + }) + ); + }) + ); + }, + deleteFtrSavedObjectsData: async () => { const allSpacesIds = [ ...(await spacesService.getAll()).map((space: { id: string }) => space.id), @@ -131,6 +175,7 @@ export function getTestDataLoader({ getService }) { index: '.kibana', wait_for_completion: true, body: { + // @ts-expect-error conflicts: 'proceed', query: { bool: { diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/add_prepackaged_rules.ts b/x-pack/test/detection_engine_api_integration/basic/tests/add_prepackaged_rules.ts index 70ee954bd9166..7f7d023fe2727 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/add_prepackaged_rules.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/add_prepackaged_rules.ts @@ -6,9 +6,12 @@ */ import expect from '@kbn/expect'; -import { PrePackagedRulesAndTimelinesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/response'; +import { + PREBUILT_RULES_STATUS_URL, + PREBUILT_RULES_URL, + InstallPrebuiltRulesAndTimelinesResponse, +} from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; -import { DETECTION_ENGINE_PREPACKAGED_URL } from '@kbn/security-solution-plugin/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, @@ -43,7 +46,7 @@ export default ({ getService }: FtrProviderContext): void => { await waitFor( async () => { const { body, status } = await supertest - .put(DETECTION_ENGINE_PREPACKAGED_URL) + .put(PREBUILT_RULES_URL) .set('kbn-xsrf', 'true') .send(); if (status === 200) { @@ -51,11 +54,11 @@ export default ({ getService }: FtrProviderContext): void => { } return status === 200; }, - DETECTION_ENGINE_PREPACKAGED_URL, + PREBUILT_RULES_URL, log ); - const prepackagedRules = responseBody as PrePackagedRulesAndTimelinesSchema; + const prepackagedRules = responseBody as InstallPrebuiltRulesAndTimelinesResponse; expect(prepackagedRules.rules_installed).to.be.greaterThan(0); expect(prepackagedRules.rules_updated).to.eql(0); expect(Object.keys(prepackagedRules)).to.eql([ @@ -74,12 +77,12 @@ export default ({ getService }: FtrProviderContext): void => { await waitFor( async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .expect(200); return body.rules_not_installed === 0; }, - `${DETECTION_ENGINE_PREPACKAGED_URL}/_status`, + PREBUILT_RULES_STATUS_URL, log ); @@ -87,7 +90,7 @@ export default ({ getService }: FtrProviderContext): void => { await waitFor( async () => { const { body, status } = await supertest - .put(DETECTION_ENGINE_PREPACKAGED_URL) + .put(PREBUILT_RULES_URL) .set('kbn-xsrf', 'true') .send(); if (status === 200) { @@ -95,11 +98,11 @@ export default ({ getService }: FtrProviderContext): void => { } return status === 200; }, - DETECTION_ENGINE_PREPACKAGED_URL, + PREBUILT_RULES_URL, log ); - const prepackagedRules = responseBody as PrePackagedRulesAndTimelinesSchema; + const prepackagedRules = responseBody as InstallPrebuiltRulesAndTimelinesResponse; expect(prepackagedRules.rules_installed).to.eql(0); expect(prepackagedRules.timelines_installed).to.eql(0); }); diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts b/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts index 6c4f73285e64f..55183b48d78f9 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; @@ -60,7 +60,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should create a single rule without an input index', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { name: 'Simple Rule Query', description: 'Simple Rule Query', enabled: true, diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/get_prepackaged_rules_status.ts b/x-pack/test/detection_engine_api_integration/basic/tests/get_prepackaged_rules_status.ts index c3b2eb3568ccb..ce75086a2deea 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/get_prepackaged_rules_status.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/get_prepackaged_rules_status.ts @@ -7,10 +7,12 @@ import expect from '@kbn/expect'; +import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { - DETECTION_ENGINE_PREPACKAGED_URL, - DETECTION_ENGINE_RULES_URL, -} from '@kbn/security-solution-plugin/common/constants'; + PREBUILT_RULES_STATUS_URL, + PREBUILT_RULES_URL, +} from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; + import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, @@ -40,7 +42,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return expected JSON keys of the pre-packaged rules and pre-packaged timelines status', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -58,7 +60,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that rules_not_installed are greater than zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -67,7 +69,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that timelines_not_installed are greater than zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -76,7 +78,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that rules_custom_installed, rules_installed, and rules_not_updated are zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -87,7 +89,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that timelines_installed, and timelines_not_updated are zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -103,7 +105,7 @@ export default ({ getService }: FtrProviderContext): void => { .expect(200); const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -115,14 +117,10 @@ export default ({ getService }: FtrProviderContext): void => { }); it('should show rules and timelines are installed when adding pre-packaged rules', async () => { - await supertest - .put(DETECTION_ENGINE_PREPACKAGED_URL) - .set('kbn-xsrf', 'true') - .send() - .expect(200); + await supertest.put(PREBUILT_RULES_URL).set('kbn-xsrf', 'true').send().expect(200); const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_actions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_actions.ts index 90c80c172fcfa..94a8b58ff70a0 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_actions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_actions.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; -import { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, @@ -86,7 +86,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); // create a rule with the action attached and a meta field - const ruleWithAction: CreateRulesSchema = { + const ruleWithAction: RuleCreateProps = { ...getRuleWithWebHookAction(hookAction.id, true), meta: {}, }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_prepackaged_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_prepackaged_rules.ts index 512863e039e3a..f90b1f8c8949b 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_prepackaged_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/add_prepackaged_rules.ts @@ -6,9 +6,12 @@ */ import expect from '@kbn/expect'; -import { PrePackagedRulesAndTimelinesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/response'; +import { + PREBUILT_RULES_STATUS_URL, + PREBUILT_RULES_URL, + InstallPrebuiltRulesAndTimelinesResponse, +} from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; -import { DETECTION_ENGINE_PREPACKAGED_URL } from '@kbn/security-solution-plugin/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, @@ -42,7 +45,7 @@ export default ({ getService }: FtrProviderContext): void => { await waitFor( async () => { const { body, status } = await supertest - .put(DETECTION_ENGINE_PREPACKAGED_URL) + .put(PREBUILT_RULES_URL) .set('kbn-xsrf', 'true') .send(); if (status === 200) { @@ -50,11 +53,11 @@ export default ({ getService }: FtrProviderContext): void => { } return status === 200; }, - DETECTION_ENGINE_PREPACKAGED_URL, + PREBUILT_RULES_URL, log ); - const prepackagedRules = responseBody as PrePackagedRulesAndTimelinesSchema; + const prepackagedRules = responseBody as InstallPrebuiltRulesAndTimelinesResponse; expect(prepackagedRules.rules_installed).to.be.greaterThan(0); expect(prepackagedRules.rules_updated).to.eql(0); expect(Object.keys(prepackagedRules)).to.eql([ @@ -73,12 +76,12 @@ export default ({ getService }: FtrProviderContext): void => { await waitFor( async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .expect(200); return body.rules_not_installed === 0; }, - `${DETECTION_ENGINE_PREPACKAGED_URL}/_status`, + PREBUILT_RULES_STATUS_URL, log ); @@ -86,7 +89,7 @@ export default ({ getService }: FtrProviderContext): void => { await waitFor( async () => { const { body, status } = await supertest - .put(DETECTION_ENGINE_PREPACKAGED_URL) + .put(PREBUILT_RULES_URL) .set('kbn-xsrf', 'true') .send(); if (status === 200) { @@ -94,11 +97,11 @@ export default ({ getService }: FtrProviderContext): void => { } return status === 200; }, - DETECTION_ENGINE_PREPACKAGED_URL, + PREBUILT_RULES_URL, log ); - const prepackagedRules = responseBody as PrePackagedRulesAndTimelinesSchema; + const prepackagedRules = responseBody as InstallPrebuiltRulesAndTimelinesResponse; expect(prepackagedRules.rules_installed).to.eql(0); expect(prepackagedRules.timelines_installed).to.eql(0); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/check_privileges.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/check_privileges.ts index d208b522a1d44..0b7de71969a7b 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/check_privileges.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/check_privileges.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { ROLES } from '@kbn/security-solution-plugin/common/test'; import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; -import { ThresholdCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { ThresholdRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, @@ -86,7 +86,7 @@ export default ({ getService }: FtrProviderContext) => { }); it(`for threshold rule with index param: ${index}`, async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(index), threshold: { field: [], diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_ml.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_ml.ts index a29963ec3b6cb..e1a3d4f0796c4 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_ml.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_ml.ts @@ -17,7 +17,7 @@ import { SPACE_IDS, VERSION, } from '@kbn/rule-data-utils'; -import { MachineLearningCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { MachineLearningRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { ALERT_ANCESTORS, ALERT_DEPTH, @@ -47,7 +47,7 @@ export default ({ getService }: FtrProviderContext) => { const siemModule = 'security_linux_v3'; const mlJobId = 'v3_linux_anomalous_network_activity'; - const testRule: MachineLearningCreateSchema = { + const testRule: MachineLearningRuleCreateProps = { name: 'Test ML rule', description: 'Test ML rule description', risk_score: 50, @@ -185,7 +185,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should create 7 alerts from ML rule when records meet anomaly_threshold', async () => { - const rule: MachineLearningCreateSchema = { + const rule: MachineLearningRuleCreateProps = { ...testRule, anomaly_threshold: 20, }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_new_terms.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_new_terms.ts index 7c97505307cd0..bfb369e0091b5 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_new_terms.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_new_terms.ts @@ -8,10 +8,10 @@ import { orderBy } from 'lodash'; import expect from '@kbn/expect'; -import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; -import { NewTermsCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; -import { getCreateNewTermsRulesSchemaMock } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request/rule_schemas.mock'; +import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; +import { NewTermsRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; +import { getCreateNewTermsRulesSchemaMock } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema/mocks'; import { DetectionAlert } from '@kbn/security-solution-plugin/common/detection_engine/schemas/alerts'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { @@ -114,7 +114,7 @@ export default ({ getService }: FtrProviderContext) => { // suricata-sensor-san-francisco appears in a document at 2019-02-19T20:42:08.230Z, but also appears // in earlier documents so is not new. An alert should not be generated for that term. it('should generate 1 alert with 1 selected field', async () => { - const rule: NewTermsCreateSchema = { + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), new_terms_fields: ['host.name'], from: '2019-02-19T20:42:00.000Z', @@ -258,7 +258,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate 3 alerts when 1 document has 3 new values', async () => { - const rule: NewTermsCreateSchema = { + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), new_terms_fields: ['host.ip'], from: '2019-02-19T20:42:00.000Z', @@ -289,7 +289,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate alerts for every term when history window is small', async () => { - const rule: NewTermsCreateSchema = { + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), new_terms_fields: ['host.name'], from: '2019-02-19T20:42:00.000Z', @@ -337,7 +337,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate the correct alerts', async () => { - const rule: NewTermsCreateSchema = { + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), // myfakeindex-3 does not have event.ingested mapped so we can test if the runtime field // 'kibana.combined_timestamp' handles unmapped fields properly @@ -364,7 +364,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should apply exceptions', async () => { - const rule: NewTermsCreateSchema = { + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), new_terms_fields: ['host.name'], from: '2019-02-19T20:42:00.000Z', @@ -402,7 +402,7 @@ export default ({ getService }: FtrProviderContext) => { it('should work for max signals > 100', async () => { const maxSignals = 200; - const rule: NewTermsCreateSchema = { + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), new_terms_fields: ['process.pid'], from: '2018-02-19T20:42:00.000Z', @@ -445,7 +445,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should be enriched with host risk score', async () => { - const rule: NewTermsCreateSchema = { + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), new_terms_fields: ['host.name'], from: '2019-02-19T20:42:00.000Z', diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts index 082d8afab9dd1..a1da5d5697b1e 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; -import { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { ROLES } from '@kbn/security-solution-plugin/common/test'; @@ -161,7 +161,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should create a single rule without an input index', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { name: 'Simple Rule Query', description: 'Simple Rule Query', enabled: true, @@ -273,7 +273,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not create a rule if trying to add more than one default rule exception list', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { name: 'Simple Rule Query', description: 'Simple Rule Query', enabled: true, diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_threat_matching.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_threat_matching.ts index 906cc94f224d8..b18f716d17d4e 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_threat_matching.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_threat_matching.ts @@ -22,10 +22,11 @@ import { flattenWithPrefix } from '@kbn/securitysolution-rules'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; -import { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; - -import { getCreateThreatMatchRulesSchemaMock } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request/rule_schemas.mock'; -import { getThreatMatchingSchemaPartialMock } from '@kbn/security-solution-plugin/common/detection_engine/schemas/response/rules_schema.mocks'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; +import { + getCreateThreatMatchRulesSchemaMock, + getThreatMatchingSchemaPartialMock, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema/mocks'; import { ENRICHMENT_TYPES } from '@kbn/security-solution-plugin/common/cti/constants'; import { Ancestor } from '@kbn/security-solution-plugin/server/lib/detection_engine/signals/types'; import { @@ -146,7 +147,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should be able to execute and get 10 signals when doing a specific query', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -332,7 +333,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return 0 matches if the mapping does not match against anything in the mapping', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -367,7 +368,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return 0 signals when using an AND and one of the clauses does not have data', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -406,7 +407,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return 0 signals when using an AND and one of the clauses has a made up value that does not exist', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -447,7 +448,7 @@ export default ({ getService }: FtrProviderContext) => { describe('timeout behavior', () => { // Flaky it.skip('will return an error if a rule execution exceeds the rule interval', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a short interval', severity: 'high', @@ -503,7 +504,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('enriches signals with the single indicator that matched', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -594,7 +595,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('enriches signals with multiple indicators if several matched', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -674,7 +675,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('adds a single indicator that matched multiple fields', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -786,7 +787,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates multiple signals with multiple matches', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -936,7 +937,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('enriches signals with the single indicator that matched', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -1027,7 +1028,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('enriches signals with multiple indicators if several matched', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -1107,7 +1108,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('adds a single indicator that matched multiple fields', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -1219,7 +1220,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates multiple signals with multiple matches', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -1369,7 +1370,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should be enriched with host risk score', async () => { - const rule: CreateRulesSchema = { + const rule: RuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/find_rule_exception_references.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/find_rule_exception_references.ts index 7619c6f3e359a..6ddc5dafaafa1 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/find_rule_exception_references.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/find_rule_exception_references.ts @@ -9,13 +9,17 @@ import expect from '@kbn/expect'; -import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '@kbn/security-solution-plugin/common/constants'; import { CreateExceptionListSchema, ExceptionListTypeEnum, } from '@kbn/securitysolution-io-ts-list-types'; + import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { RuleReferencesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/response'; +import { + DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL, + RuleReferencesSchema, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_exceptions'; + import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createRule, @@ -210,7 +214,7 @@ export default ({ getService }: FtrProviderContext) => { .get(DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL) .set('kbn-xsrf', 'true') .query({ - namespace_types: `${exceptionList.namespace_type},${exceptionList2.namespace_type}`, + namespace_types: 'single,agnostic', }) .expect(200); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/generating_signals.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/generating_signals.ts index b71cd23063550..60e4cef77c896 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/generating_signals.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/generating_signals.ts @@ -25,11 +25,11 @@ import { orderBy, get } from 'lodash'; import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; import { - EqlCreateSchema, - QueryCreateSchema, - SavedQueryCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + EqlRuleCreateProps, + QueryRuleCreateProps, + SavedQueryRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { Ancestor } from '@kbn/security-solution-plugin/server/lib/detection_engine/signals/types'; import { ALERT_ANCESTORS, @@ -92,7 +92,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should have the specific audit record for _id or none of these tests below will pass', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; @@ -105,7 +105,7 @@ export default ({ getService }: FtrProviderContext) => { it('should abide by max_signals > 100', async () => { const maxSignals = 500; - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), max_signals: maxSignals, }; @@ -117,7 +117,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should have recorded the rule_id within the signal', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; @@ -129,7 +129,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should query and get back expected signal structure using a basic KQL query', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; @@ -162,7 +162,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should query and get back expected signal structure using a saved query rule', async () => { - const rule: SavedQueryCreateSchema = { + const rule: SavedQueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), type: 'saved_query', query: `_id:${ID}`, @@ -196,7 +196,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should query and get back expected signal structure when it is a signal on a signal', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; @@ -205,7 +205,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [createdId]); // Run signals on top of that 1 signal which should create a single signal (on top of) a signal - const ruleForSignals: QueryCreateSchema = { + const ruleForSignals: QueryRuleCreateProps = { ...getRuleForSignalTesting([`.alerts-security.alerts-default*`]), rule_id: 'signal-on-signal', }; @@ -260,7 +260,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates a correctly formatted signal from EQL non-sequence queries', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'configuration where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', }; @@ -364,7 +364,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates up to max_signals for non-sequence EQL queries', async () => { - const rule: EqlCreateSchema = getEqlRuleForSignalTesting(['auditbeat-*']); + const rule: EqlRuleCreateProps = getEqlRuleForSignalTesting(['auditbeat-*']); const { id } = await createRule(supertest, log, rule); await waitForRuleSuccessOrStatus(supertest, log, id); await waitForSignalsToBePresent(supertest, log, 100, [id]); @@ -376,7 +376,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('uses the provided event_category_override', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'config_change where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', event_category_override: 'auditd.message_type', @@ -449,7 +449,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('uses the provided timestamp_field', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['fake.index.1']), query: 'any where true', timestamp_field: 'created_at', @@ -465,7 +465,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('uses the provided tiebreaker_field', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['fake.index.1']), query: 'any where true', tiebreaker_field: 'locale', @@ -481,7 +481,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates building block signals from EQL sequences in the expected form', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'sequence by host.name [anomoly where true] [any where true]', // TODO: spelling }; @@ -629,7 +629,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates shell signals from EQL sequences in the expected form', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'sequence by host.name [anomoly where true] [any where true]', }; @@ -715,7 +715,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates up to max_signals with an EQL rule', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'sequence by host.name [any where true] [any where true]', max_signals: 200, @@ -739,7 +739,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates signals when an index name contains special characters to encode', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*', '']), query: 'configuration where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', }; @@ -751,7 +751,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('uses the provided filters', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'any where true', filters: [ @@ -808,7 +808,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should be enriched with host risk score', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'configuration where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', }; @@ -829,7 +829,7 @@ export default ({ getService }: FtrProviderContext) => { describe('Threshold Rules', () => { it('generates 1 signal from Threshold rules when threshold is met', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: ['host.id'], @@ -877,7 +877,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates 2 signals from Threshold rules when threshold is met', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: 'host.id', @@ -892,7 +892,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('applies the provided query before bucketing ', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), query: 'host.id:"2ab45fc1c41e4c84bbd02202a7e5761f"', threshold: { @@ -908,7 +908,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates no signals from Threshold rules when threshold is met and cardinality is not met', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: 'host.id', @@ -927,7 +927,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates no signals from Threshold rules when cardinality is met and threshold is not met', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: 'host.id', @@ -946,7 +946,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates signals from Threshold rules when threshold and cardinality are both met', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: 'host.id', @@ -1004,7 +1004,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not generate signals if only one field meets the threshold requirement', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: ['host.id', 'process.name'], @@ -1017,7 +1017,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates signals from Threshold rules when bucketing by multiple fields', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: ['host.id', 'process.name', 'event.module'], @@ -1086,7 +1086,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('applies timestamp override when using single field', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['timestamp-fallback-test']), threshold: { field: 'host.name', @@ -1116,7 +1116,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('applies timestamp override when using multiple fields', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['timestamp-fallback-test']), threshold: { field: ['host.name', 'source.ip'], @@ -1156,7 +1156,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should be enriched with host risk score', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: 'host.name', @@ -1181,7 +1181,7 @@ export default ({ getService }: FtrProviderContext) => { describe('Enrich alerts: query rule', () => { describe('without index avalable', () => { it('should do not have risk score fields', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; @@ -1206,7 +1206,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should host have risk score field and do not have user risk score', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID} or _id:GBbXBmkBR346wHgn5_eR or _id:x10zJ2oE9v5HJNSHhyxi`, }; @@ -1247,7 +1247,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should have host and user risk score fields', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; @@ -1282,7 +1282,7 @@ export default ({ getService }: FtrProviderContext) => { ); }); - const executeRuleAndGetSignals = async (rule: QueryCreateSchema) => { + const executeRuleAndGetSignals = async (rule: QueryRuleCreateProps) => { const { id } = await createRule(supertest, log, rule); await waitForRuleSuccessOrStatus(supertest, log, id); await waitForSignalsToBePresent(supertest, log, 4, [id]); @@ -1293,7 +1293,7 @@ export default ({ getService }: FtrProviderContext) => { }; it('should get default severity and risk score if there is no mapping', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['signal_overrides']), severity: 'medium', risk_score: 75, @@ -1312,7 +1312,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should get overridden severity if the rule has a mapping for it', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['signal_overrides']), severity: 'medium', severity_mapping: [ @@ -1347,7 +1347,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should get overridden risk score if the rule has a mapping for it', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['signal_overrides']), severity: 'medium', risk_score: 75, @@ -1380,7 +1380,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should get overridden severity and risk score if the rule has both mappings', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['signal_overrides']), severity: 'medium', severity_mapping: [ @@ -1440,7 +1440,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate signals with name_override field', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), rule_name_override: 'event.action', }; @@ -1503,7 +1503,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not generate duplicate signals', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_prepackaged_rules_status.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_prepackaged_rules_status.ts index c3b2eb3568ccb..ce75086a2deea 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_prepackaged_rules_status.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_prepackaged_rules_status.ts @@ -7,10 +7,12 @@ import expect from '@kbn/expect'; +import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { - DETECTION_ENGINE_PREPACKAGED_URL, - DETECTION_ENGINE_RULES_URL, -} from '@kbn/security-solution-plugin/common/constants'; + PREBUILT_RULES_STATUS_URL, + PREBUILT_RULES_URL, +} from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; + import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, @@ -40,7 +42,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return expected JSON keys of the pre-packaged rules and pre-packaged timelines status', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -58,7 +60,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that rules_not_installed are greater than zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -67,7 +69,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that timelines_not_installed are greater than zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -76,7 +78,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that rules_custom_installed, rules_installed, and rules_not_updated are zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -87,7 +89,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return that timelines_installed, and timelines_not_updated are zero', async () => { const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -103,7 +105,7 @@ export default ({ getService }: FtrProviderContext): void => { .expect(200); const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -115,14 +117,10 @@ export default ({ getService }: FtrProviderContext): void => { }); it('should show rules and timelines are installed when adding pre-packaged rules', async () => { - await supertest - .put(DETECTION_ENGINE_PREPACKAGED_URL) - .set('kbn-xsrf', 'true') - .send() - .expect(200); + await supertest.put(PREBUILT_RULES_URL).set('kbn-xsrf', 'true').send().expect(200); const { body } = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) + .get(PREBUILT_RULES_STATUS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts index 8ee61c0705452..11ad72b505f1f 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { omit } from 'lodash'; -import { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, @@ -31,7 +31,7 @@ import { } from '../../utils'; // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: -// x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json +// x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json const RULE_ID = '9a1a2dae-0b5f-4c3d-8305-a268d404c306'; // eslint-disable-next-line import/no-default-export @@ -107,7 +107,7 @@ export default ({ getService }: FtrProviderContext) => { const hookAction = await createNewAction(supertest, log); const rule = getSimpleRule(); await createRule(supertest, log, rule); - const ruleToUpdate: CreateRulesSchema = { + const ruleToUpdate: RuleCreateProps = { ...getRuleWithWebHookAction(hookAction.id, true, rule), meta: {}, // create a rule with the action attached and a meta field }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts index e2ee8395d98c6..d3739473a5985 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; -import { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; @@ -230,7 +230,7 @@ export default ({ getService }: FtrProviderContext): void => { const { body } = await supertest .post(`${DETECTION_ENGINE_RULES_URL}/_import`) .set('kbn-xsrf', 'true') - .attach('file', ruleToNdjson(rule as CreateRulesSchema), 'rules.ndjson') + .attach('file', ruleToNdjson(rule as RuleCreateProps), 'rules.ndjson') .expect(200); expect(body.errors[0]).to.eql({ diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts index 77655b8ba150b..30b378d2a7eea 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts @@ -6,35 +6,33 @@ */ import expect from '@kbn/expect'; - import { DETECTION_ENGINE_RULES_BULK_ACTION, DETECTION_ENGINE_RULES_URL, NOTIFICATION_THROTTLE_NO_ACTIONS, NOTIFICATION_THROTTLE_RULE, } from '@kbn/security-solution-plugin/common/constants'; - +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { BulkAction, BulkActionEditType, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request/perform_bulk_action_schema'; -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +} from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { binaryToString, + createLegacyRuleAction, createRule, createSignalsIndex, deleteAllAlerts, deleteSignalsIndex, - getSimpleRule, - getSimpleRuleOutput, - removeServerGeneratedProperties, - createLegacyRuleAction, getLegacyActionSO, - installPrePackagedRules, getSimpleMlRule, - getWebHookAction, + getSimpleRule, + getSimpleRuleOutput, getSlackAction, + getWebHookAction, + installPrePackagedRules, + removeServerGeneratedProperties, } from '../../utils'; // eslint-disable-next-line import/no-default-export @@ -374,7 +372,7 @@ export default ({ getService }: FtrProviderContext): void => { expect(rulesResponse.total).to.eql(2); - rulesResponse.data.forEach((rule: FullResponseSchema) => { + rulesResponse.data.forEach((rule: RuleResponse) => { expect(rule.actions).to.eql([ { action_type_id: '.slack', diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts index e9c3b3b68487d..b893f38f20310 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts @@ -4,25 +4,24 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import expect from 'expect'; - import { DETECTION_ENGINE_RULES_BULK_ACTION, DETECTION_ENGINE_RULES_URL, } from '@kbn/security-solution-plugin/common/constants'; +import expect from 'expect'; import { BulkAction, BulkActionEditType, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request/perform_bulk_action_schema'; +} from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createRule, createSignalsIndex, deleteAllAlerts, deleteSignalsIndex, + getSimpleMlRule, getSimpleRule, installPrePackagedRules, - getSimpleMlRule, } from '../../utils'; // eslint-disable-next-line import/no-default-export diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/throttle.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/throttle.ts index 9a459b1ffb0e1..fc3dc32483ba4 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/throttle.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/throttle.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; -import { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL, NOTIFICATION_THROTTLE_NO_ACTIONS, @@ -73,7 +73,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('When creating throttle with "NOTIFICATION_THROTTLE_NO_ACTIONS" set and no actions, the rule should have its kibana alerting "mute_all" set to "true" and notify_when set to "onActiveAlert"', async () => { - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getSimpleRule(), throttle: NOTIFICATION_THROTTLE_NO_ACTIONS, }; @@ -93,7 +93,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getWebHookAction()) .expect(200); - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getRuleWithWebHookAction(hookAction.id), throttle: NOTIFICATION_THROTTLE_NO_ACTIONS, }; @@ -106,7 +106,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('When creating throttle with "NOTIFICATION_THROTTLE_RULE" set and no actions, the rule should have its kibana alerting "mute_all" set to "false" and notify_when set to "onActiveAlert"', async () => { - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getSimpleRule(), throttle: NOTIFICATION_THROTTLE_RULE, }; @@ -120,7 +120,7 @@ export default ({ getService }: FtrProviderContext) => { // NOTE: This shows A side effect of how we do not set data on side cars anymore where the user is told they have no actions since the array is empty. it('When creating throttle with "NOTIFICATION_THROTTLE_RULE" set and no actions, since we do not have any actions, we should get back a throttle of "NOTIFICATION_THROTTLE_NO_ACTIONS"', async () => { - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getSimpleRule(), throttle: NOTIFICATION_THROTTLE_RULE, }; @@ -136,7 +136,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getWebHookAction()) .expect(200); - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getRuleWithWebHookAction(hookAction.id), throttle: NOTIFICATION_THROTTLE_RULE, }; @@ -149,7 +149,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('When creating throttle with "1h" set and no actions, the rule should have its kibana alerting "mute_all" set to "false" and notify_when set to "onThrottleInterval"', async () => { - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getSimpleRule(), throttle: '1h', }; @@ -169,7 +169,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getWebHookAction()) .expect(200); - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getRuleWithWebHookAction(hookAction.id), throttle: '1h', }; @@ -197,7 +197,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('When creating throttle with "NOTIFICATION_THROTTLE_NO_ACTIONS" set and no actions, we should return "NOTIFICATION_THROTTLE_NO_ACTIONS" when doing a read', async () => { - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getSimpleRule(), throttle: NOTIFICATION_THROTTLE_NO_ACTIONS, }; @@ -208,7 +208,7 @@ export default ({ getService }: FtrProviderContext) => { // NOTE: This shows A side effect of how we do not set data on side cars anymore where the user is told they have no actions since the array is empty. it('When creating throttle with "NOTIFICATION_THROTTLE_RULE" set and no actions, since we do not have any actions, we should get back a throttle of "NOTIFICATION_THROTTLE_NO_ACTIONS" when doing a read', async () => { - const ruleWithThrottle: CreateRulesSchema = { + const ruleWithThrottle: RuleCreateProps = { ...getSimpleRule(), throttle: NOTIFICATION_THROTTLE_RULE, }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/timestamps.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/timestamps.ts index db7ed86b97f71..df0d9fb17e47a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/timestamps.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/timestamps.ts @@ -9,9 +9,9 @@ import expect from '@kbn/expect'; import { orderBy } from 'lodash'; import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; import { - EqlCreateSchema, - QueryCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + EqlRuleCreateProps, + QueryRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { ALERT_ORIGINAL_TIME } from '@kbn/security-solution-plugin/common/field_maps/field_names'; import { FtrProviderContext } from '../../common/ftr_provider_context'; @@ -77,7 +77,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should still use the @timestamp field even with an override field. It should never use the override field', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['myfakeindex-5']), timestamp_override: 'event.ingested', }; @@ -106,7 +106,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should still use the @timestamp field even with an override field. It should never use the override field', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['myfakeindex-5']), timestamp_override: 'event.ingested', }; @@ -165,7 +165,7 @@ export default ({ getService }: FtrProviderContext) => { describe('KQL', () => { it('should generate signals with event.ingested, @timestamp and (event.ingested + timestamp)', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['myfa*']), timestamp_override: 'event.ingested', }; @@ -187,7 +187,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate 2 signals with event.ingested when timestamp fallback is disabled', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['myfa*']), rule_id: 'rule-without-timestamp-fallback', timestamp_override: 'event.ingested', @@ -211,7 +211,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate 2 signals with @timestamp', async () => { - const rule: QueryCreateSchema = getRuleForSignalTesting(['myfa*']); + const rule: QueryRuleCreateProps = getRuleForSignalTesting(['myfa*']); const { id } = await createRule(supertest, log, rule); @@ -230,7 +230,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate 2 signals when timestamp override does not exist', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['myfa*']), timestamp_override: 'event.fakeingestfield', }; @@ -251,7 +251,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not generate any signals when timestamp override does not exist and timestamp fallback is disabled', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['myfa*']), rule_id: 'rule-without-timestamp-fallback', timestamp_override: 'event.fakeingestfield', @@ -276,7 +276,7 @@ export default ({ getService }: FtrProviderContext) => { * and we add a new timestamp to the signal. */ it('should NOT use the timestamp override as the "original_time"', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['myfakeindex-2']), timestamp_override: 'event.ingested', }; @@ -294,7 +294,7 @@ export default ({ getService }: FtrProviderContext) => { describe('EQL', () => { it('should generate 2 signals with @timestamp', async () => { - const rule: EqlCreateSchema = getEqlRuleForSignalTesting(['myfa*']); + const rule: EqlRuleCreateProps = getEqlRuleForSignalTesting(['myfa*']); const { id } = await createRule(supertest, log, rule); @@ -313,7 +313,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate 2 signals when timestamp override does not exist', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['myfa*']), timestamp_override: 'event.fakeingestfield', }; @@ -334,7 +334,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should not generate any signals when timestamp override does not exist and timestamp fallback is disabled', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['myfa*']), timestamp_override: 'event.fakeingestfield', timestamp_override_fallback_disabled: true, @@ -383,7 +383,7 @@ export default ({ getService }: FtrProviderContext) => { * ref: https://github.com/elastic/elasticsearch/issues/28806#issuecomment-369303620 */ it('should generate 200 signals when timestamp override does not exist', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), timestamp_override: 'event.fakeingested', max_signals: 200, 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 2f5fb63382552..a3f6812f6a0b0 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 @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL, @@ -158,7 +158,7 @@ export default ({ getService }: FtrProviderContext) => { updatedRule2.throttle = '1d'; // update both rule names - const { body }: { body: FullResponseSchema[] } = await supertest + const { body }: { body: RuleResponse[] } = await supertest .put(DETECTION_ENGINE_RULES_BULK_UPDATE) .set('kbn-xsrf', 'true') .send([updatedRule1, updatedRule2]) @@ -220,7 +220,7 @@ export default ({ getService }: FtrProviderContext) => { updatedRule2.name = 'some other name'; // update both rule names - const { body }: { body: FullResponseSchema[] } = await supertest + const { body }: { body: RuleResponse[] } = await supertest .put(DETECTION_ENGINE_RULES_BULK_UPDATE) .set('kbn-xsrf', 'true') .send([updatedRule1, updatedRule2]) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group3/create_exceptions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group3/create_exceptions.ts index cc97253bfaf67..f6ea0fc02747b 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group3/create_exceptions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group3/create_exceptions.ts @@ -11,12 +11,12 @@ import expect from '@kbn/expect'; import type { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { - CreateRulesSchema, - EqlCreateSchema, - QueryCreateSchema, - ThreatMatchCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleCreateProps, + EqlRuleCreateProps, + QueryRuleCreateProps, + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; @@ -92,7 +92,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getCreateExceptionListMinimalSchemaMock()) .expect(200); - const ruleWithException: CreateRulesSchema = { + const ruleWithException: RuleCreateProps = { ...getSimpleRule(), exceptions_list: [ { @@ -129,7 +129,7 @@ export default ({ getService }: FtrProviderContext) => { .send(getCreateExceptionListMinimalSchemaMock()) .expect(200); - const ruleWithException: CreateRulesSchema = { + const ruleWithException: RuleCreateProps = { ...getSimpleRule(), enabled: true, exceptions_list: [ @@ -165,7 +165,7 @@ export default ({ getService }: FtrProviderContext) => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to use const immutableRule = await getRule( supertest, @@ -199,7 +199,7 @@ export default ({ getService }: FtrProviderContext) => { ); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to use const immutableRule = await getRule( supertest, @@ -239,7 +239,7 @@ export default ({ getService }: FtrProviderContext) => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to use const immutableRule = await getRule( supertest, @@ -277,7 +277,7 @@ export default ({ getService }: FtrProviderContext) => { ); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule const immutableRule = await getRule( supertest, @@ -326,7 +326,7 @@ export default ({ getService }: FtrProviderContext) => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule const immutableRule = await getRule( supertest, @@ -361,7 +361,7 @@ export default ({ getService }: FtrProviderContext) => { ); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule const immutableRule = await getRule( supertest, @@ -418,7 +418,7 @@ export default ({ getService }: FtrProviderContext) => { ); // Rule id of "eb079c62-4481-4d6e-9643-3ca499df7aaa" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/external_alerts.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/external_alerts.json // since this rule does not have existing exceptions_list that we are going to use for tests const immutableRule = await getRule( supertest, @@ -472,7 +472,7 @@ export default ({ getService }: FtrProviderContext) => { ); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to use const immutableRule = await getRule( supertest, @@ -522,7 +522,7 @@ export default ({ getService }: FtrProviderContext) => { ); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint.json // This rule has an existing exceptions_list that we are going to use const immutableRule = await getRule( supertest, @@ -623,7 +623,7 @@ export default ({ getService }: FtrProviderContext) => { }; await createExceptionListItem(supertest, log, exceptionListItem); - const ruleWithException: CreateRulesSchema = { + const ruleWithException: RuleCreateProps = { name: 'Simple Rule Query', description: 'Simple Rule Query', enabled: true, @@ -651,7 +651,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should be able to execute against an exception list that does include valid entries and get back 0 signals', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { name: 'Simple Rule Query', description: 'Simple Rule Query', enabled: true, @@ -678,7 +678,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates no signals when an exception is added for an EQL rule', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'configuration where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', }; @@ -697,7 +697,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates no signals when an exception is added for a threshold rule', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['auditbeat-*']), threshold: { field: 'host.id', @@ -719,7 +719,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('generates no signals when an exception is added for a threat match rule', async () => { - const rule: ThreatMatchCreateSchema = { + const rule: ThreatMatchRuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -772,7 +772,7 @@ export default ({ getService }: FtrProviderContext) => { it('generates no signals when a value list exception is added for a query rule', async () => { const valueListId = 'value-list-id'; await importFile(supertest, log, 'keyword', ['suricata-sensor-amsterdam'], valueListId); - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { name: 'Simple Rule Query', description: 'Simple Rule Query', enabled: true, @@ -804,7 +804,7 @@ export default ({ getService }: FtrProviderContext) => { it('generates no signals when a value list exception is added for a threat match rule', async () => { const valueListId = 'value-list-id'; await importFile(supertest, log, 'keyword', ['zeek-sensor-amsterdam'], valueListId); - const rule: ThreatMatchCreateSchema = { + const rule: ThreatMatchRuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -852,7 +852,7 @@ export default ({ getService }: FtrProviderContext) => { it('generates no signals when a value list exception is added for a threshold rule', async () => { const valueListId = 'value-list-id'; await importFile(supertest, log, 'keyword', ['zeek-sensor-amsterdam'], valueListId); - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', @@ -889,7 +889,7 @@ export default ({ getService }: FtrProviderContext) => { it('generates no signals when a value list exception is added for an EQL rule', async () => { const valueListId = 'value-list-id'; await importFile(supertest, log, 'keyword', ['zeek-sensor-amsterdam'], valueListId); - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['auditbeat-*']), query: 'configuration where host.name=="zeek-sensor-amsterdam"', }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts index eb5f5c9a923bb..36f5b84a50c3d 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts @@ -33,7 +33,7 @@ export default ({ getService }: FtrProviderContext) => { const retry = getService('retry'); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json // This rule has an existing exceptions_list that we are going to use. const IMMUTABLE_RULE_ID = '9a1a2dae-0b5f-4c3d-8305-a268d404c306'; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rule_status.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rule_status.ts index dea6703d2fef4..0581c97802f03 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rule_status.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rule_status.ts @@ -10,9 +10,9 @@ import type { MlJobUsageMetric } from '@kbn/security-solution-plugin/server/usag import type { RulesTypeUsage } from '@kbn/security-solution-plugin/server/usage/detections/rules/types'; import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types'; import type { - ThreatMatchCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getInitialMlJobUsage } from '@kbn/security-solution-plugin/server/usage/detections/ml_jobs/get_initial_usage'; import { getInitialDetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/get_initial_usage'; import { @@ -444,7 +444,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"threshold" rule type', () => { let stats: DetectionMetrics | undefined; before(async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['telemetry']), threshold: { field: 'keyword', @@ -644,7 +644,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"indicator_match/threat_match" rule type', () => { let stats: DetectionMetrics | undefined; before(async () => { - const rule: ThreatMatchCreateSchema = { + const rule: ThreatMatchRuleCreateProps = { ...getSimpleThreatMatch('rule-1', true), index: ['telemetry'], threat_index: ['telemetry'], diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts index 7f7b0d3d30788..1d059e02ed5cc 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts @@ -8,9 +8,9 @@ import expect from '@kbn/expect'; import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types'; import type { - ThreatMatchCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getInitialDetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/get_initial_usage'; import { getInitialEventLogUsage } from '@kbn/security-solution-plugin/server/usage/detections/rules/get_initial_usage'; import type { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -512,7 +512,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"threshold" rule type', () => { it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), threshold: { field: 'keyword', @@ -552,7 +552,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['telemetry']), threshold: { field: 'keyword', @@ -600,7 +600,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), threshold: { field: 'keyword', @@ -641,7 +641,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['telemetry']), threshold: { field: 'keyword', @@ -686,7 +686,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), threshold: { field: 'keyword', @@ -727,7 +727,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['telemetry']), threshold: { field: 'keyword', @@ -1029,7 +1029,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { - const rule: ThreatMatchCreateSchema = { + const rule: ThreatMatchRuleCreateProps = { ...getSimpleThreatMatch('rule-1', true), index: ['telemetry'], threat_index: ['telemetry'], @@ -1121,7 +1121,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThreatMatchCreateSchema = { + const rule: ThreatMatchRuleCreateProps = { ...getSimpleThreatMatch('rule-1', true), index: ['telemetry'], threat_index: ['telemetry'], @@ -1210,7 +1210,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThreatMatchCreateSchema = { + const rule: ThreatMatchRuleCreateProps = { ...getSimpleThreatMatch('rule-1', true), index: ['telemetry'], threat_index: ['telemetry'], @@ -1303,7 +1303,7 @@ export default ({ getService }: FtrProviderContext) => { await retry.try(async () => { const stats = await getStats(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id const foundRule = stats.detection_rules.detection_rule_detail.find( (rule) => rule.rule_id === '9a1a2dae-0b5f-4c3d-8305-a268d404c306' @@ -1334,7 +1334,7 @@ export default ({ getService }: FtrProviderContext) => { it('should show "notifications_disabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); const hookAction = await createNewAction(supertest, log); const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); @@ -1388,7 +1388,7 @@ export default ({ getService }: FtrProviderContext) => { it('should show "notifications_enabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); const hookAction = await createNewAction(supertest, log); const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); @@ -1442,7 +1442,7 @@ export default ({ getService }: FtrProviderContext) => { it('should show "legacy_notifications_disabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); const hookAction = await createNewAction(supertest, log); const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, false); @@ -1496,7 +1496,7 @@ export default ({ getService }: FtrProviderContext) => { it('should show "legacy_notifications_enabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + // x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); const hookAction = await createNewAction(supertest, log); const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, true); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/const_keyword.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/const_keyword.ts index 011ed04376281..f0290b8258dd8 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/const_keyword.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/const_keyword.ts @@ -7,9 +7,9 @@ import expect from '@kbn/expect'; import { - EqlCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + EqlRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; @@ -86,7 +86,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"eql" rule type', () => { it('should detect the "dataset_name_1" from "event.dataset" and have 4 signals', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['const_keyword']), query: 'any where event.dataset=="dataset_name_1"', }; @@ -99,7 +99,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should copy the "dataset_name_1" from "event.dataset"', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['const_keyword']), query: 'any where event.dataset=="dataset_name_1"', }; @@ -120,7 +120,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"threshold" rule type', async () => { it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['const_keyword']), threshold: { field: 'event.dataset', diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword.ts index c07f0efb1df98..ef8126015c758 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword.ts @@ -8,10 +8,10 @@ import expect from '@kbn/expect'; import { - EqlCreateSchema, - QueryCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + EqlRuleCreateProps, + QueryRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { @@ -53,7 +53,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"kql" rule type', () => { it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['keyword']), query: 'event.dataset: "dataset_name_1"', }; @@ -73,7 +73,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"eql" rule type', () => { it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['keyword']), query: 'any where event.dataset=="dataset_name_1"', }; @@ -94,7 +94,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"threshold" rule type', async () => { it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getThresholdRuleForSignalTesting(['keyword']), threshold: { field: 'event.dataset', diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword_mixed_with_const.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword_mixed_with_const.ts index 52c5ae615da95..5949770ef23f9 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword_mixed_with_const.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword_mixed_with_const.ts @@ -7,9 +7,9 @@ import expect from '@kbn/expect'; import { - EqlCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + EqlRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; @@ -91,7 +91,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"eql" rule type', () => { it('should detect the "dataset_name_1" from "event.dataset" and have 8 signals, 4 from each index', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['keyword', 'const_keyword']), query: 'any where event.dataset=="dataset_name_1"', }; @@ -104,7 +104,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should copy the "dataset_name_1" from "event.dataset"', async () => { - const rule: EqlCreateSchema = { + const rule: EqlRuleCreateProps = { ...getEqlRuleForSignalTesting(['keyword', 'const_keyword']), query: 'any where event.dataset=="dataset_name_1"', }; @@ -129,7 +129,7 @@ export default ({ getService }: FtrProviderContext) => { describe('"threshold" rule type', async () => { it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...getRuleForSignalTesting(['keyword', 'const_keyword']), rule_id: 'threshold-rule', type: 'threshold', diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group6/alerts/alerts_compatibility.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group6/alerts/alerts_compatibility.ts index ba8c9ea88cd17..343de21a3ebf5 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group6/alerts/alerts_compatibility.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group6/alerts/alerts_compatibility.ts @@ -14,12 +14,12 @@ import { } from '@kbn/security-solution-plugin/common/constants'; import { ThreatEcs } from '@kbn/security-solution-plugin/common/ecs/threat'; import { - EqlCreateSchema, - QueryCreateSchema, - SavedQueryCreateSchema, - ThreatMatchCreateSchema, - ThresholdCreateSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + EqlRuleCreateProps, + QueryRuleCreateProps, + SavedQueryRuleCreateProps, + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { createRule, createSignalsIndex, @@ -181,7 +181,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with legacy index pattern', async () => { - const rule: ThreatMatchCreateSchema = getThreatMatchRuleForSignalTesting([ + const rule: ThreatMatchRuleCreateProps = getThreatMatchRuleForSignalTesting([ '.siem-signals-*', ]); const { id } = await createRule(supertest, log, rule); @@ -194,7 +194,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with AAD index pattern', async () => { - const rule: ThreatMatchCreateSchema = getThreatMatchRuleForSignalTesting([ + const rule: ThreatMatchRuleCreateProps = getThreatMatchRuleForSignalTesting([ `.alerts-security.alerts-default`, ]); const { id } = await createRule(supertest, log, rule); @@ -222,7 +222,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with legacy index pattern', async () => { - const rule: QueryCreateSchema = getRuleForSignalTesting([`.siem-signals-*`]); + const rule: QueryRuleCreateProps = getRuleForSignalTesting([`.siem-signals-*`]); const { id } = await createRule(supertest, log, rule); await waitForRuleSuccessOrStatus(supertest, log, id); await waitForSignalsToBePresent(supertest, log, 1, [id]); @@ -389,7 +389,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with AAD index pattern', async () => { - const rule: QueryCreateSchema = getRuleForSignalTesting([ + const rule: QueryRuleCreateProps = getRuleForSignalTesting([ `.alerts-security.alerts-default`, ]); const { id } = await createRule(supertest, log, rule); @@ -573,7 +573,9 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with legacy index pattern', async () => { - const rule: SavedQueryCreateSchema = getSavedQueryRuleForSignalTesting([`.siem-signals-*`]); + const rule: SavedQueryRuleCreateProps = getSavedQueryRuleForSignalTesting([ + `.siem-signals-*`, + ]); const { id } = await createRule(supertest, log, rule); await waitForRuleSuccessOrStatus(supertest, log, id); await waitForSignalsToBePresent(supertest, log, 1, [id]); @@ -584,7 +586,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with AAD index pattern', async () => { - const rule: SavedQueryCreateSchema = getSavedQueryRuleForSignalTesting([ + const rule: SavedQueryRuleCreateProps = getSavedQueryRuleForSignalTesting([ `.alerts-security.alerts-default`, ]); const { id } = await createRule(supertest, log, rule); @@ -612,7 +614,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with legacy index pattern', async () => { - const rule: EqlCreateSchema = getEqlRuleForSignalTesting(['.siem-signals-*']); + const rule: EqlRuleCreateProps = getEqlRuleForSignalTesting(['.siem-signals-*']); const { id } = await createRule(supertest, log, rule); await waitForRuleSuccessOrStatus(supertest, log, id); await waitForSignalsToBePresent(supertest, log, 1, [id]); @@ -623,7 +625,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with AAD index pattern', async () => { - const rule: EqlCreateSchema = getEqlRuleForSignalTesting([ + const rule: EqlRuleCreateProps = getEqlRuleForSignalTesting([ `.alerts-security.alerts-default`, ]); const { id } = await createRule(supertest, log, rule); @@ -651,10 +653,10 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with legacy index pattern', async () => { - const baseRule: ThresholdCreateSchema = getThresholdRuleForSignalTesting([ + const baseRule: ThresholdRuleCreateProps = getThresholdRuleForSignalTesting([ '.siem-signals-*', ]); - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...baseRule, threshold: { ...baseRule.threshold, @@ -672,10 +674,10 @@ export default ({ getService }: FtrProviderContext) => { }); it('should generate a signal-on-legacy-signal with AAD index pattern', async () => { - const baseRule: ThresholdCreateSchema = getThresholdRuleForSignalTesting([ + const baseRule: ThresholdRuleCreateProps = getThresholdRuleForSignalTesting([ `.alerts-security.alerts-default`, ]); - const rule: ThresholdCreateSchema = { + const rule: ThresholdRuleCreateProps = { ...baseRule, threshold: { ...baseRule.threshold, diff --git a/x-pack/test/detection_engine_api_integration/utils/create_rule.ts b/x-pack/test/detection_engine_api_integration/utils/create_rule.ts index ab162724ecb68..278bf0a92b40f 100644 --- a/x-pack/test/detection_engine_api_integration/utils/create_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/create_rule.ts @@ -8,9 +8,9 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; import type { - CreateRulesSchema, - FullResponseSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleCreateProps, + RuleResponse, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { deleteRule } from './delete_rule'; @@ -27,8 +27,8 @@ import { deleteRule } from './delete_rule'; export const createRule = async ( supertest: SuperTest.SuperTest, log: ToolingLog, - rule: CreateRulesSchema -): Promise => { + rule: RuleCreateProps +): Promise => { const response = await supertest .post(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') diff --git a/x-pack/test/detection_engine_api_integration/utils/create_rule_with_auth.ts b/x-pack/test/detection_engine_api_integration/utils/create_rule_with_auth.ts index 266d01166d1b7..daa8ad420e4ca 100644 --- a/x-pack/test/detection_engine_api_integration/utils/create_rule_with_auth.ts +++ b/x-pack/test/detection_engine_api_integration/utils/create_rule_with_auth.ts @@ -9,9 +9,9 @@ import type SuperTest from 'supertest'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import type { - CreateRulesSchema, - FullResponseSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleCreateProps, + RuleResponse, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * Helper to cut down on the noise in some of the tests. @@ -20,9 +20,9 @@ import type { */ export const createRuleWithAuth = async ( supertest: SuperTest.SuperTest, - rule: CreateRulesSchema, + rule: RuleCreateProps, auth: { user: string; pass: string } -): Promise => { +): Promise => { const { body } = await supertest .post(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') diff --git a/x-pack/test/detection_engine_api_integration/utils/create_rule_with_exception_entries.ts b/x-pack/test/detection_engine_api_integration/utils/create_rule_with_exception_entries.ts index 5b47de64d9c0f..d7f203eef82a4 100644 --- a/x-pack/test/detection_engine_api_integration/utils/create_rule_with_exception_entries.ts +++ b/x-pack/test/detection_engine_api_integration/utils/create_rule_with_exception_entries.ts @@ -9,9 +9,9 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; import type { NonEmptyEntriesArray, OsTypeArray } from '@kbn/securitysolution-io-ts-list-types'; import type { - CreateRulesSchema, - FullResponseSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleCreateProps, + RuleResponse, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { createContainerWithEntries } from './create_container_with_entries'; @@ -31,13 +31,13 @@ import { createRule } from './create_rule'; export const createRuleWithExceptionEntries = async ( supertest: SuperTest.SuperTest, log: ToolingLog, - rule: CreateRulesSchema, + rule: RuleCreateProps, entries: NonEmptyEntriesArray[], endpointEntries?: Array<{ entries: NonEmptyEntriesArray; osTypes: OsTypeArray | undefined; }> -): Promise => { +): Promise => { const maybeExceptionList = await createContainerWithEntries(supertest, log, entries); const maybeEndpointList = await createContainerWithEndpointEntries( supertest, @@ -49,7 +49,7 @@ export const createRuleWithExceptionEntries = async ( // the rule to sometimes not filter correctly the first time with an exception list // or other timing issues. Then afterwards wait for the rule to have succeeded before // returning. - const ruleWithException: CreateRulesSchema = { + const ruleWithException: RuleCreateProps = { ...rule, enabled: false, exceptions_list: [...maybeExceptionList, ...maybeEndpointList], diff --git a/x-pack/test/detection_engine_api_integration/utils/delete_exception_list.ts b/x-pack/test/detection_engine_api_integration/utils/delete_exception_list.ts index 499f5b94a9752..fdb6975aae5de 100644 --- a/x-pack/test/detection_engine_api_integration/utils/delete_exception_list.ts +++ b/x-pack/test/detection_engine_api_integration/utils/delete_exception_list.ts @@ -8,7 +8,7 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * Helper to cut down on the noise in some of the tests. Does a delete of an exception list. @@ -21,7 +21,7 @@ export const deleteExceptionList = async ( supertest: SuperTest.SuperTest, log: ToolingLog, listId: string -): Promise => { +): Promise => { const response = await supertest .delete(`${EXCEPTION_LIST_URL}?list_id=${listId}`) .set('kbn-xsrf', 'true'); diff --git a/x-pack/test/detection_engine_api_integration/utils/delete_rule.ts b/x-pack/test/detection_engine_api_integration/utils/delete_rule.ts index 2e01c61c33595..a1678464def71 100644 --- a/x-pack/test/detection_engine_api_integration/utils/delete_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/delete_rule.ts @@ -7,7 +7,7 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; @@ -22,7 +22,7 @@ export const deleteRule = async ( supertest: SuperTest.SuperTest, log: ToolingLog, ruleId: string -): Promise => { +): Promise => { const response = await supertest .delete(`${DETECTION_ENGINE_RULES_URL}?rule_id=${ruleId}`) .set('kbn-xsrf', 'true'); diff --git a/x-pack/test/detection_engine_api_integration/utils/find_immutable_rule_by_id.ts b/x-pack/test/detection_engine_api_integration/utils/find_immutable_rule_by_id.ts index 0e6fe73685c48..40d3557bba6d4 100644 --- a/x-pack/test/detection_engine_api_integration/utils/find_immutable_rule_by_id.ts +++ b/x-pack/test/detection_engine_api_integration/utils/find_immutable_rule_by_id.ts @@ -7,7 +7,7 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; @@ -24,7 +24,7 @@ export const findImmutableRuleById = async ( page: number; perPage: number; total: number; - data: FullResponseSchema[]; + data: RuleResponse[]; }> => { const response = await supertest .get( diff --git a/x-pack/test/detection_engine_api_integration/utils/get_complex_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_complex_rule.ts index 4f5cfdcd3ba56..381f727f84585 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_complex_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_complex_rule.ts @@ -5,13 +5,13 @@ * 2.0. */ -import type { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This will return a complex rule with all the outputs possible * @param ruleId The ruleId to set which is optional and defaults to rule-1 */ -export const getComplexRule = (ruleId = 'rule-1'): CreateRulesSchema => ({ +export const getComplexRule = (ruleId = 'rule-1'): RuleCreateProps => ({ actions: [], author: [], name: 'Complex Rule Query', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts b/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts index 1491829b33999..a8f5916c3598d 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; // TODO: Follow up https://github.com/elastic/kibana/pull/137628 and add an explicit type to this object // without using Partial @@ -13,7 +13,7 @@ import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/de * This will return a complex rule with all the outputs possible * @param ruleId The ruleId to set which is optional and defaults to rule-1 */ -export const getComplexRuleOutput = (ruleId = 'rule-1'): Partial => ({ +export const getComplexRuleOutput = (ruleId = 'rule-1'): Partial => ({ actions: [], author: [], created_by: 'elastic', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_eql_rule_for_signal_testing.ts b/x-pack/test/detection_engine_api_integration/utils/get_eql_rule_for_signal_testing.ts index 21a8509a16460..4e9d48916ff68 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_eql_rule_for_signal_testing.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_eql_rule_for_signal_testing.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { EqlCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { EqlRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getRuleForSignalTesting } from './get_rule_for_signal_testing'; /** @@ -19,7 +19,7 @@ export const getEqlRuleForSignalTesting = ( index: string[], ruleId = 'eql-rule', enabled = true -): EqlCreateSchema => ({ +): EqlRuleCreateProps => ({ ...getRuleForSignalTesting(index, ruleId, enabled), type: 'eql', language: 'eql', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notification_so.ts b/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notification_so.ts index 9a084d800a2d8..836ad5390250e 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notification_so.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notification_so.ts @@ -6,9 +6,9 @@ */ import type { Client } from '@elastic/elasticsearch'; -import { SavedObjectReference } from '@kbn/core/server'; import type { SearchResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { LegacyRuleNotificationAlertTypeParams } from '@kbn/security-solution-plugin/server/lib/detection_engine/notifications/legacy_types'; +import { SavedObjectReference } from '@kbn/core/server'; +import { LegacyRuleNotificationAlertTypeParams } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions_legacy'; interface LegacyActionNotificationSO extends LegacyRuleNotificationAlertTypeParams { references: SavedObjectReference[]; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notifications_so_by_id.ts b/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notifications_so_by_id.ts index 3120e85e899bf..2e104a454bf78 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notifications_so_by_id.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_notifications_so_by_id.ts @@ -6,9 +6,9 @@ */ import type { Client } from '@elastic/elasticsearch'; -import { SavedObjectReference } from '@kbn/core/server'; import type { SearchResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { LegacyRuleNotificationAlertTypeParams } from '@kbn/security-solution-plugin/server/lib/detection_engine/notifications/legacy_types'; +import { SavedObjectReference } from '@kbn/core/server'; +import { LegacyRuleNotificationAlertTypeParams } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions_legacy'; interface LegacyActionNotificationSO extends LegacyRuleNotificationAlertTypeParams { references: SavedObjectReference[]; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_so.ts b/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_so.ts index 2c714614f9caa..57cf8b5efe71a 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_so.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_legacy_action_so.ts @@ -7,7 +7,7 @@ import type { Client } from '@elastic/elasticsearch'; import type { SearchResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SavedObjectReference } from '@kbn/core/server'; -import type { LegacyRuleActions } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions/legacy_types'; +import type { LegacyRuleActions } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions_legacy'; interface LegacyActionSO extends LegacyRuleActions { references: SavedObjectReference[]; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_legacy_actions_so_by_id.ts b/x-pack/test/detection_engine_api_integration/utils/get_legacy_actions_so_by_id.ts index 48ea142aa28ca..1be0506359172 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_legacy_actions_so_by_id.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_legacy_actions_so_by_id.ts @@ -6,9 +6,9 @@ */ import type { Client } from '@elastic/elasticsearch'; -import { SavedObjectReference } from '@kbn/core/server'; import type { SearchResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { LegacyRuleActions } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions/legacy_types'; +import { SavedObjectReference } from '@kbn/core/server'; +import type { LegacyRuleActions } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions_legacy'; interface LegacyActionSO extends LegacyRuleActions { references: SavedObjectReference[]; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_open_signals.ts b/x-pack/test/detection_engine_api_integration/utils/get_open_signals.ts index f5d880cb3433e..ae370cb5886ea 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_open_signals.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_open_signals.ts @@ -9,7 +9,7 @@ import type SuperTest from 'supertest'; import type { Client } from '@elastic/elasticsearch'; import type { ToolingLog } from '@kbn/tooling-log'; import { RuleExecutionStatus } from '@kbn/security-solution-plugin/common/detection_engine/rule_monitoring'; -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { waitForRuleSuccessOrStatus } from './wait_for_rule_success_or_status'; import { refreshIndex } from './refresh_index'; @@ -19,7 +19,7 @@ export const getOpenSignals = async ( supertest: SuperTest.SuperTest, log: ToolingLog, es: Client, - rule: FullResponseSchema, + rule: RuleResponse, status: RuleExecutionStatus = RuleExecutionStatus.succeeded, size?: number ) => { diff --git a/x-pack/test/detection_engine_api_integration/utils/get_prepackaged_rule_status.ts b/x-pack/test/detection_engine_api_integration/utils/get_prepackaged_rule_status.ts index b6771cbb85f9c..df680cc12e9c8 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_prepackaged_rule_status.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_prepackaged_rule_status.ts @@ -7,9 +7,10 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; -import type { PrePackagedRulesAndTimelinesStatusSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/response'; - -import { DETECTION_ENGINE_PREPACKAGED_URL } from '@kbn/security-solution-plugin/common/constants'; +import { + PREBUILT_RULES_STATUS_URL, + GetPrebuiltRulesAndTimelinesStatusResponse, +} from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; /** * Helper to cut down on the noise in some of the tests. This @@ -19,11 +20,8 @@ import { DETECTION_ENGINE_PREPACKAGED_URL } from '@kbn/security-solution-plugin/ export const getPrePackagedRulesStatus = async ( supertest: SuperTest.SuperTest, log: ToolingLog -): Promise => { - const response = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) - .set('kbn-xsrf', 'true') - .send(); +): Promise => { + const response = await supertest.get(PREBUILT_RULES_STATUS_URL).set('kbn-xsrf', 'true').send(); if (response.status !== 200) { log.error( diff --git a/x-pack/test/detection_engine_api_integration/utils/get_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_rule.ts index b1036e1f8b682..0c9e77179709e 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_rule.ts @@ -7,7 +7,7 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; @@ -21,7 +21,7 @@ export const getRule = async ( supertest: SuperTest.SuperTest, log: ToolingLog, ruleId: string -): Promise => { +): Promise => { const response = await supertest .get(`${DETECTION_ENGINE_RULES_URL}?rule_id=${ruleId}`) .set('kbn-xsrf', 'true'); diff --git a/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing.ts b/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing.ts index ee07daad625c7..321e821682878 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { QueryCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { QueryRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a typical signal testing rule that is easy for most basic testing of output of signals. @@ -18,7 +18,7 @@ export const getRuleForSignalTesting = ( index: string[], ruleId = 'rule-1', enabled = true -): QueryCreateSchema => ({ +): QueryRuleCreateProps => ({ name: 'Signal Testing Query', description: 'Tests a simple query', enabled, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing_with_timestamp_override.ts b/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing_with_timestamp_override.ts index d742e727137c5..24ac2298ab68f 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing_with_timestamp_override.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_rule_for_signal_testing_with_timestamp_override.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { QueryCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { QueryRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; export const getRuleForSignalTestingWithTimestampOverride = ( index: string[], ruleId = 'rule-1', enabled = true, timestampOverride = 'event.ingested' -): QueryCreateSchema => ({ +): QueryRuleCreateProps => ({ name: 'Signal Testing Query', description: 'Tests a simple query', enabled, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_rule_with_web_hook_action.ts b/x-pack/test/detection_engine_api_integration/utils/get_rule_with_web_hook_action.ts index 02aaf938b0003..838ef235638e6 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_rule_with_web_hook_action.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_rule_with_web_hook_action.ts @@ -6,16 +6,16 @@ */ import type { - CreateRulesSchema, - UpdateRulesSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleCreateProps, + RuleUpdateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getSimpleRule } from './get_simple_rule'; export const getRuleWithWebHookAction = ( id: string, enabled = false, - rule?: CreateRulesSchema -): CreateRulesSchema | UpdateRulesSchema => { + rule?: RuleCreateProps +): RuleCreateProps | RuleUpdateProps => { const finalRule = rule != null ? { ...rule, enabled } : getSimpleRule('rule-1', enabled); return { ...finalRule, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_saved_query_rule_for_signal_testing.ts b/x-pack/test/detection_engine_api_integration/utils/get_saved_query_rule_for_signal_testing.ts index da6c17d5a4026..12bca0207d4d6 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_saved_query_rule_for_signal_testing.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_saved_query_rule_for_signal_testing.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { SavedQueryCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { SavedQueryRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getRuleForSignalTesting } from './get_rule_for_signal_testing'; /** @@ -19,7 +19,7 @@ export const getSavedQueryRuleForSignalTesting = ( index: string[], ruleId = 'saved-query-rule', enabled = true -): SavedQueryCreateSchema => ({ +): SavedQueryRuleCreateProps => ({ ...getRuleForSignalTesting(index, ruleId, enabled), type: 'saved_query', saved_id: 'abcd', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule.ts index 5cf6c1c41aff4..7c70774847c87 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a representative ML rule payload as expected by the server * @param ruleId The rule id * @param enabled Set to tru to enable it, by default it is off */ -export const getSimpleMlRule = (ruleId = 'rule-1', enabled = false): CreateRulesSchema => ({ +export const getSimpleMlRule = (ruleId = 'rule-1', enabled = false): RuleCreateProps => ({ name: 'Simple ML Rule', description: 'Simple Machine Learning Rule', enabled, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_output.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_output.ts index 56afa355b0482..754dbb1cd1149 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_output.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_output.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { MachineLearningResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { MachineLearningRule } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getMockSharedResponseSchema } from './get_simple_rule_output'; import { removeServerGeneratedProperties } from './remove_server_generated_properties'; -const getBaseMlRuleOutput = (ruleId = 'rule-1'): MachineLearningResponseSchema => { +const getBaseMlRuleOutput = (ruleId = 'rule-1'): MachineLearningRule => { return { ...getMockSharedResponseSchema(ruleId), name: 'Simple ML Rule', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_update.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_update.ts index b5200ddd86357..219fb3e425255 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_update.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_ml_rule_update.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { UpdateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleUpdateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a representative ML rule payload as expected by the server for an update * @param ruleId The rule id * @param enabled Set to tru to enable it, by default it is off */ -export const getSimpleMlRuleUpdate = (ruleId = 'rule-1', enabled = false): UpdateRulesSchema => ({ +export const getSimpleMlRuleUpdate = (ruleId = 'rule-1', enabled = false): RuleUpdateProps => ({ name: 'Simple ML Rule', description: 'Simple Machine Learning Rule', enabled, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_preview_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_preview_rule.ts index fa67ae3eeba80..985728e9bec80 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_preview_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_preview_rule.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PreviewRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { PreviewRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a typical simple preview rule for testing that is easy for most basic testing diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts index a7e53a368b93c..e630ba9859e2f 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { QueryCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { QueryRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a typical simple rule for testing that is easy for most basic testing * @param ruleId * @param enabled Enables the rule on creation or not. Defaulted to true. */ -export const getSimpleRule = (ruleId = 'rule-1', enabled = false): QueryCreateSchema => ({ +export const getSimpleRule = (ruleId = 'rule-1', enabled = false): QueryRuleCreateProps => ({ name: 'Simple Rule Query', description: 'Simple Rule Query', enabled, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts index 8d8cca2e71133..9e869a91bf0b1 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts @@ -6,15 +6,15 @@ */ import type { - FullResponseSchema, - SharedResponseSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleResponse, + SharedResponseProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { removeServerGeneratedProperties } from './remove_server_generated_properties'; export const getMockSharedResponseSchema = ( ruleId = 'rule-1', enabled = false -): SharedResponseSchema => ({ +): SharedResponseProps => ({ actions: [], author: [], created_by: 'elastic', @@ -61,7 +61,7 @@ export const getMockSharedResponseSchema = ( namespace: undefined, }); -const getQueryRuleOutput = (ruleId = 'rule-1', enabled = false): FullResponseSchema => ({ +const getQueryRuleOutput = (ruleId = 'rule-1', enabled = false): RuleResponse => ({ ...getMockSharedResponseSchema(ruleId, enabled), index: ['auditbeat-*'], language: 'kuery', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_preview_output.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_preview_output.ts index 26fe0eafd1456..88f1efad4239e 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_preview_output.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_preview_output.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RulePreviewLogs } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RulePreviewLogs } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is the typical output of a simple rule preview, with errors and warnings coming up from the rule diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_update.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_update.ts index f4365386a8328..43da256b4e793 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_update.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_update.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { UpdateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleUpdateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a typical simple rule for testing that is easy for most basic testing * @param ruleId The rule id * @param enabled Set to true to enable it, by default it is off */ -export const getSimpleRuleUpdate = (ruleId = 'rule-1', enabled = false): UpdateRulesSchema => ({ +export const getSimpleRuleUpdate = (ruleId = 'rule-1', enabled = false): RuleUpdateProps => ({ name: 'Simple Rule Query', description: 'Simple Rule Query', enabled, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_without_rule_id.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_without_rule_id.ts index 25994c8e6e14b..254cc044cbbe0 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_without_rule_id.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_without_rule_id.ts @@ -5,13 +5,13 @@ * 2.0. */ -import type { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getSimpleRule } from './get_simple_rule'; /** * This is a typical simple rule for testing that is easy for most basic testing */ -export const getSimpleRuleWithoutRuleId = (): CreateRulesSchema => { +export const getSimpleRuleWithoutRuleId = (): RuleCreateProps => { const simpleRule = getSimpleRule(); // eslint-disable-next-line @typescript-eslint/naming-convention const { rule_id, ...ruleWithoutId } = simpleRule; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_saved_query_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_saved_query_rule.ts index 2fdd157c9c0d4..56571463f85e3 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_saved_query_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_saved_query_rule.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { SavedQueryCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { SavedQueryRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a typical simple saved_query rule for e2e testing @@ -15,7 +15,7 @@ import type { SavedQueryCreateSchema } from '@kbn/security-solution-plugin/commo export const getSimpleSavedQueryRule = ( ruleId = 'rule-1', enabled = false -): SavedQueryCreateSchema => ({ +): SavedQueryRuleCreateProps => ({ name: 'Simple Saved Query Rule', description: 'Simple Saved Query Rule', enabled, diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_threat_match.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_threat_match.ts index 57cca015d2c4b..d3013be402377 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_threat_match.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_threat_match.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ThreatMatchCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { ThreatMatchRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * This is a typical simple indicator match/threat match for testing that is easy for most basic testing @@ -15,7 +15,7 @@ import { ThreatMatchCreateSchema } from '@kbn/security-solution-plugin/common/de export const getSimpleThreatMatch = ( ruleId = 'rule-1', enabled = false -): ThreatMatchCreateSchema => ({ +): ThreatMatchRuleCreateProps => ({ description: 'Detecting root and admin users', name: 'Query with a rule id', severity: 'high', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_threat_match_rule_for_signal_testing.ts b/x-pack/test/detection_engine_api_integration/utils/get_threat_match_rule_for_signal_testing.ts index 3e663607c1186..24fa49c72cd09 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_threat_match_rule_for_signal_testing.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_threat_match_rule_for_signal_testing.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { ThreatMatchCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { ThreatMatchRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getRuleForSignalTesting } from './get_rule_for_signal_testing'; /** @@ -19,7 +19,7 @@ export const getThreatMatchRuleForSignalTesting = ( index: string[], ruleId = 'threat-match-rule', enabled = true -): ThreatMatchCreateSchema => ({ +): ThreatMatchRuleCreateProps => ({ ...getRuleForSignalTesting(index, ruleId, enabled), type: 'threat_match', language: 'kuery', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_threshold_rule_for_signal_testing.ts b/x-pack/test/detection_engine_api_integration/utils/get_threshold_rule_for_signal_testing.ts index aea1a5746bf78..d37ec2084d5a0 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_threshold_rule_for_signal_testing.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_threshold_rule_for_signal_testing.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { ThresholdCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { ThresholdRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { getRuleForSignalTesting } from './get_rule_for_signal_testing'; /** @@ -19,7 +19,7 @@ export const getThresholdRuleForSignalTesting = ( index: string[], ruleId = 'threshold-rule', enabled = true -): ThresholdCreateSchema => ({ +): ThresholdRuleCreateProps => ({ ...getRuleForSignalTesting(index, ruleId, enabled), type: 'threshold', language: 'kuery', diff --git a/x-pack/test/detection_engine_api_integration/utils/install_prepackaged_rules.ts b/x-pack/test/detection_engine_api_integration/utils/install_prepackaged_rules.ts index c75e8203bf6cd..53fb592e84d13 100644 --- a/x-pack/test/detection_engine_api_integration/utils/install_prepackaged_rules.ts +++ b/x-pack/test/detection_engine_api_integration/utils/install_prepackaged_rules.ts @@ -8,7 +8,7 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; -import { DETECTION_ENGINE_PREPACKAGED_URL } from '@kbn/security-solution-plugin/common/constants'; +import { PREBUILT_RULES_URL } from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; import { countDownTest } from './count_down_test'; export const installPrePackagedRules = async ( @@ -18,7 +18,7 @@ export const installPrePackagedRules = async ( await countDownTest( async () => { const { status, body } = await supertest - .put(DETECTION_ENGINE_PREPACKAGED_URL) + .put(PREBUILT_RULES_URL) .set('kbn-xsrf', 'true') .send(); if (status !== 200) { diff --git a/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties.ts b/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties.ts index 8d8a34bba8b79..b5c0bd1864ca8 100644 --- a/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties.ts +++ b/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties.ts @@ -5,23 +5,20 @@ * 2.0. */ -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { omit, pickBy } from 'lodash'; const serverGeneratedProperties = ['id', 'created_at', 'updated_at', 'execution_summary'] as const; type ServerGeneratedProperties = typeof serverGeneratedProperties[number]; -export type RuleWithoutServerGeneratedProperties = Omit< - FullResponseSchema, - ServerGeneratedProperties ->; +export type RuleWithoutServerGeneratedProperties = Omit; /** * This will remove server generated properties such as date times, etc... * @param rule Rule to pass in to remove typical server generated properties */ export const removeServerGeneratedProperties = ( - rule: FullResponseSchema + rule: RuleResponse ): RuleWithoutServerGeneratedProperties => { const removedProperties = omit(rule, serverGeneratedProperties); diff --git a/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties_including_rule_id.ts b/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties_including_rule_id.ts index e8e7e1900afb7..2a37c1b659093 100644 --- a/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties_including_rule_id.ts +++ b/x-pack/test/detection_engine_api_integration/utils/remove_server_generated_properties_including_rule_id.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { FullResponseSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { removeServerGeneratedProperties } from './remove_server_generated_properties'; @@ -14,8 +14,8 @@ import { removeServerGeneratedProperties } from './remove_server_generated_prope * @param rule Rule to pass in to remove typical server generated properties */ export const removeServerGeneratedPropertiesIncludingRuleId = ( - rule: FullResponseSchema -): Partial => { + rule: RuleResponse +): Partial => { const ruleWithRemovedProperties = removeServerGeneratedProperties(rule); // eslint-disable-next-line @typescript-eslint/naming-convention const { rule_id, ...additionalRuledIdRemoved } = ruleWithRemovedProperties; diff --git a/x-pack/test/detection_engine_api_integration/utils/rule_to_ndjson.ts b/x-pack/test/detection_engine_api_integration/utils/rule_to_ndjson.ts index 1082212432c01..03e6d266a3deb 100644 --- a/x-pack/test/detection_engine_api_integration/utils/rule_to_ndjson.ts +++ b/x-pack/test/detection_engine_api_integration/utils/rule_to_ndjson.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { CreateRulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import type { RuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * Given a rule this will convert it to an ndjson buffer which is useful for * testing upload features. * @param rule The rule to convert to ndjson */ -export const ruleToNdjson = (rule: CreateRulesSchema): Buffer => { +export const ruleToNdjson = (rule: RuleCreateProps): Buffer => { const stringified = JSON.stringify(rule); return Buffer.from(`${stringified}\n`); }; diff --git a/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts b/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts index 32766c88978cd..7c10c98c105d6 100644 --- a/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts +++ b/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts @@ -6,9 +6,9 @@ */ import type { - FullResponseSchema, - UpdateRulesSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleResponse, + RuleUpdateProps, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { omit, pickBy } from 'lodash'; const propertiesToRemove = [ @@ -25,12 +25,12 @@ const propertiesToRemove = [ ]; /** - * transforms FullResponseSchema rule to UpdateRulesSchema + * transforms RuleResponse rule to RuleUpdateProps * returned result can be used in rule update API calls */ -export const ruleToUpdateSchema = (rule: FullResponseSchema): UpdateRulesSchema => { +export const ruleToUpdateSchema = (rule: RuleResponse): RuleUpdateProps => { const removedProperties = omit(rule, propertiesToRemove); // We're only removing undefined values, so this cast correctly narrows the type - return pickBy(removedProperties, (value) => value !== undefined) as UpdateRulesSchema; + return pickBy(removedProperties, (value) => value !== undefined) as RuleUpdateProps; }; diff --git a/x-pack/test/detection_engine_api_integration/utils/update_rule.ts b/x-pack/test/detection_engine_api_integration/utils/update_rule.ts index c66d86c5594d0..cee09bc80a6c0 100644 --- a/x-pack/test/detection_engine_api_integration/utils/update_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/update_rule.ts @@ -10,9 +10,9 @@ import type SuperTest from 'supertest'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { - UpdateRulesSchema, - FullResponseSchema, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; + RuleUpdateProps, + RuleResponse, +} from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; /** * Helper to cut down on the noise in some of the tests. This checks for @@ -23,8 +23,8 @@ import { export const updateRule = async ( supertest: SuperTest.SuperTest, log: ToolingLog, - updatedRule: UpdateRulesSchema -): Promise => { + updatedRule: RuleUpdateProps +): Promise => { const response = await supertest .put(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') 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 ba670ad78aa32..9a9d5e0d450f2 100644 --- a/x-pack/test/functional/apps/discover/async_scripted_fields.js +++ b/x-pack/test/functional/apps/discover/async_scripted_fields.js @@ -77,7 +77,7 @@ export default function ({ getService, getPageObjects }) { it('query return results with valid scripted field', async function () { if (false) { - /* the commented-out steps below were used to create the scripted fields in the logstash-* index pattern + /* the skipped steps below were used to create the scripted fields in the logstash-* index pattern which are now saved in the esArchive. */ @@ -118,6 +118,7 @@ export default function ({ getService, getPageObjects }) { }); } + await PageObjects.common.navigateToApp('discover'); await PageObjects.discover.selectIndexPattern('logstash-*'); await queryBar.setQuery('php* OR *jpg OR *css*'); await testSubjects.click('querySubmitButton'); diff --git a/x-pack/test/functional/apps/lens/group1/smokescreen.ts b/x-pack/test/functional/apps/lens/group1/smokescreen.ts index 83e385d0dee00..c01fd3a848aaf 100644 --- a/x-pack/test/functional/apps/lens/group1/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/group1/smokescreen.ts @@ -263,7 +263,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // check for value labels data = await PageObjects.lens.getCurrentChartDebugState('xyVisChart'); - expect(data?.bars?.[0].labels.length).to.eql(0); + expect(data?.bars?.[0].labels).not.to.eql(0); }); it('should override axis title', async () => { diff --git a/x-pack/test/functional/apps/lens/group3/index.ts b/x-pack/test/functional/apps/lens/group3/index.ts index 627e9d560ca21..30c8624d876b5 100644 --- a/x-pack/test/functional/apps/lens/group3/index.ts +++ b/x-pack/test/functional/apps/lens/group3/index.ts @@ -86,7 +86,6 @@ export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext loadTestFile(require.resolve('./error_handling')); loadTestFile(require.resolve('./lens_tagging')); loadTestFile(require.resolve('./lens_reporting')); - loadTestFile(require.resolve('./open_in_lens')); // keep these two last in the group in this order because they are messing with the default saved objects loadTestFile(require.resolve('./rollup')); loadTestFile(require.resolve('./no_data')); diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/index.ts b/x-pack/test/functional/apps/lens/group3/open_in_lens/index.ts deleted file mode 100644 index b1d5a1cbb3c52..0000000000000 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/index.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 { FtrProviderContext } from '../../../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - describe('Open in Lens', function () { - loadTestFile(require.resolve('./tsvb')); - loadTestFile(require.resolve('./agg_based')); - }); -} diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/gauge.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/gauge.ts similarity index 98% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/gauge.ts rename to x-pack/test/functional/apps/lens/open_in_lens/agg_based/gauge.ts index 0d85d363d8b85..35838915ede31 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/gauge.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/gauge.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, lens, timePicker, visEditor, visChart } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/goal.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts similarity index 98% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/goal.ts rename to x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts index 547d15856b7f1..d5b793b267131 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/goal.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, lens, visChart, timePicker, visEditor } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/index.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/index.ts similarity index 89% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/index.ts rename to x-pack/test/functional/apps/lens/open_in_lens/agg_based/index.ts index 0737c7ffeeb50..87c9d025893a1 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/index.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Agg based Vis to Lens', function () { diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/metric.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts similarity index 99% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/metric.ts rename to x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts index eef46d2c0cdb7..4958704801c8c 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/metric.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visEditor, visualize, lens, timePicker, visChart } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/pie.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/pie.ts similarity index 98% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/pie.ts rename to x-pack/test/functional/apps/lens/open_in_lens/agg_based/pie.ts index ed08f1ea5ae09..346aada45cea8 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/pie.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/pie.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visEditor, lens, timePicker, header } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/table.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/table.ts similarity index 99% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/table.ts rename to x-pack/test/functional/apps/lens/open_in_lens/agg_based/table.ts index c03773e3276b1..1497eea84c851 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/table.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/table.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visEditor, lens, timePicker, header } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/xy.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/xy.ts similarity index 99% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/xy.ts rename to x-pack/test/functional/apps/lens/open_in_lens/agg_based/xy.ts index 9fd425984e3c5..4c966536001a3 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/agg_based/xy.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/xy.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visEditor, lens, timePicker, header, visChart } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/open_in_lens/config.ts b/x-pack/test/functional/apps/lens/open_in_lens/config.ts new file mode 100644 index 0000000000000..d927f93adeffd --- /dev/null +++ b/x-pack/test/functional/apps/lens/open_in_lens/config.ts @@ -0,0 +1,17 @@ +/* + * 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test/functional/apps/lens/open_in_lens/index.ts b/x-pack/test/functional/apps/lens/open_in_lens/index.ts new file mode 100644 index 0000000000000..5d81bfcb9a927 --- /dev/null +++ b/x-pack/test/functional/apps/lens/open_in_lens/index.ts @@ -0,0 +1,75 @@ +/* + * 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 { EsArchiver } from '@kbn/es-archiver'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext) => { + const browser = getService('browser'); + const log = getService('log'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['timePicker']); + const config = getService('config'); + let remoteEsArchiver; + + describe('lens app - Open in Lens', () => { + const esArchive = 'x-pack/test/functional/es_archives/logstash_functional'; + const localIndexPatternString = 'logstash-*'; + const remoteIndexPatternString = 'ftr-remote:logstash-*'; + const localFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/default', + }; + + const remoteFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/default', + }; + let esNode: EsArchiver; + let fixtureDirs: { + lensBasic: string; + lensDefault: string; + }; + let indexPatternString: string; + before(async () => { + log.debug('Starting lens before method'); + await browser.setWindowSize(1280, 1200); + try { + config.get('esTestCluster.ccs'); + remoteEsArchiver = getService('remoteEsArchiver' as 'esArchiver'); + esNode = remoteEsArchiver; + fixtureDirs = remoteFixtures; + indexPatternString = remoteIndexPatternString; + } catch (error) { + esNode = esArchiver; + fixtureDirs = localFixtures; + indexPatternString = localIndexPatternString; + } + + await esNode.load(esArchive); + // changing the timepicker default here saves us from having to set it in Discover (~8s) + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update({ + defaultIndex: indexPatternString, + 'dateFormat:tz': 'UTC', + }); + await kibanaServer.importExport.load(fixtureDirs.lensBasic); + await kibanaServer.importExport.load(fixtureDirs.lensDefault); + }); + + after(async () => { + await esArchiver.unload(esArchive); + await PageObjects.timePicker.resetDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.importExport.unload(fixtureDirs.lensBasic); + await kibanaServer.importExport.unload(fixtureDirs.lensDefault); + }); + + loadTestFile(require.resolve('./tsvb')); + loadTestFile(require.resolve('./agg_based')); + }); +}; diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/dashboard.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts similarity index 98% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/dashboard.ts rename to x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts index 292aaa3a36f05..72daa5ff5486b 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/dashboard.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visualBuilder, lens, timeToVisualize, dashboard, canvas } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/gauge.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/gauge.ts similarity index 98% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/gauge.ts rename to x-pack/test/functional/apps/lens/open_in_lens/tsvb/gauge.ts index 872ce7a58a22c..4655fd34accfa 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/gauge.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/gauge.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visualBuilder, lens, header } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/index.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/index.ts similarity index 89% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/index.ts rename to x-pack/test/functional/apps/lens/open_in_lens/tsvb/index.ts index ea859195e6346..c0b5197983aa4 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/index.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('TSVB to Lens', function () { diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/metric.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/metric.ts similarity index 98% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/metric.ts rename to x-pack/test/functional/apps/lens/open_in_lens/tsvb/metric.ts index 794a2be110a32..081b3787e39a7 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/metric.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/metric.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visualBuilder, lens, header } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/timeseries.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/timeseries.ts similarity index 99% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/timeseries.ts rename to x-pack/test/functional/apps/lens/open_in_lens/tsvb/timeseries.ts index 4c0c7e66b1ba3..dc77e9fcedb9a 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/timeseries.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/timeseries.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visualBuilder, lens, header } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/top_n.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/top_n.ts similarity index 99% rename from x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/top_n.ts rename to x-pack/test/functional/apps/lens/open_in_lens/tsvb/top_n.ts index 0631872fc9bd4..1192b38b03c69 100644 --- a/x-pack/test/functional/apps/lens/group3/open_in_lens/tsvb/top_n.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/top_n.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { visualize, visualBuilder, lens, header } = getPageObjects([ diff --git a/x-pack/test/functional/config.base.js b/x-pack/test/functional/config.base.js index e92ec8be1916c..11ba4d6ebd447 100644 --- a/x-pack/test/functional/config.base.js +++ b/x-pack/test/functional/config.base.js @@ -52,7 +52,6 @@ export default async function ({ readConfigFile }) { '--xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled=true', '--savedObjects.maxImportPayloadBytes=10485760', // for OSS test management/_import_objects, '--uiSettings.overrides.observability:enableNewSyntheticsView=true', // for OSS test management/_import_objects, - '--guidedOnboarding.ui=true', // Enable guided onboarding for infra/tour.ts tests ], }, uiSettings: { diff --git a/x-pack/test/observability_functional/apps/observability/exploratory_view.ts b/x-pack/test/observability_functional/apps/observability/exploratory_view.ts index b3adaa556dac3..9aa33a8e9f652 100644 --- a/x-pack/test/observability_functional/apps/observability/exploratory_view.ts +++ b/x-pack/test/observability_functional/apps/observability/exploratory_view.ts @@ -85,8 +85,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); - expect(await find.existsByCssSelector('[title="Chrome Mobile iOS"]')).to.eql(true); - expect(await find.existsByCssSelector('[title="Mobile Safari"]')).to.eql(true); + expect( + await find.existsByCssSelector( + '[aria-label="Chrome Mobile iOS; Activate to hide series in graph"]' + ) + ).to.eql(true); + expect( + await find.existsByCssSelector( + '[aria-label="Mobile Safari; Activate to hide series in graph"]' + ) + ).to.eql(true); }); }); } diff --git a/x-pack/test/observability_functional/apps/observability/pages/alerts/index.ts b/x-pack/test/observability_functional/apps/observability/pages/alerts/index.ts index cdb0ea37a6417..7052dcba7ff23 100644 --- a/x-pack/test/observability_functional/apps/observability/pages/alerts/index.ts +++ b/x-pack/test/observability_functional/apps/observability/pages/alerts/index.ts @@ -231,15 +231,6 @@ export default ({ getService }: FtrProviderContext) => { }); }); - /* - * ATTENTION FUTURE DEVELOPER - * - * These tests should only be valid for 7.17.x - * You can run this test if you go to this file: - * x-pack/plugins/observability/public/pages/alerts/containers/alerts_table_t_grid/alerts_table_t_grid.tsx - * and at line 397 and change showCheckboxes to true - * - */ describe.skip('Bulk Actions', () => { before(async () => { await security.testUser.setRoles(['global_alerts_logs_all_else_read']); diff --git a/x-pack/test/plugin_functional/config.ts b/x-pack/test/plugin_functional/config.ts index 361318c0992a3..19846669f48ba 100644 --- a/x-pack/test/plugin_functional/config.ts +++ b/x-pack/test/plugin_functional/config.ts @@ -31,7 +31,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ resolve(__dirname, './test_suites/resolver'), resolve(__dirname, './test_suites/global_search'), - resolve(__dirname, './test_suites/timelines'), ], services, @@ -62,9 +61,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { resolverTest: { pathname: '/app/resolverTest', }, - timelineTest: { - pathname: '/app/timelinesTest', - }, }, // choose where screenshots should be saved diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json b/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json deleted file mode 100644 index 1960c49839566..0000000000000 --- a/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "timelinesTest", - "owner": { "name": "Security solution", "githubTeam": "security-solution" }, - "version": "1.0.0", - "kibanaVersion": "kibana", - "configPath": ["xpack", "timelinesTest"], - "requiredPlugins": ["timelines", "data"], - "requiredBundles": ["kibanaReact"], - "server": false, - "ui": true -} diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/public/applications/timelines_test/index.tsx b/x-pack/test/plugin_functional/plugins/timelines_test/public/applications/timelines_test/index.tsx deleted file mode 100644 index 6b576012afb81..0000000000000 --- a/x-pack/test/plugin_functional/plugins/timelines_test/public/applications/timelines_test/index.tsx +++ /dev/null @@ -1,100 +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 { Router } from 'react-router-dom'; -import React, { useCallback, useRef } from 'react'; -import ReactDOM from 'react-dom'; -import { AppMountParameters, CoreStart } from '@kbn/core/public'; -import { I18nProvider } from '@kbn/i18n-react'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; -import { TimelinesUIStart } from '@kbn/timelines-plugin/public'; -import { DataPublicPluginStart } from '@kbn/data-plugin/public'; - -type CoreStartTimelines = CoreStart & { data: DataPublicPluginStart }; - -/** - * Render the Timeline Test app. Returns a cleanup function. - */ -export function renderApp( - coreStart: CoreStartTimelines, - parameters: AppMountParameters, - timelinesPluginSetup: TimelinesUIStart | null -) { - ReactDOM.render( - , - parameters.element - ); - - return () => { - ReactDOM.unmountComponentAtNode(parameters.element); - }; -} - -const AppRoot = React.memo( - ({ - coreStart, - parameters, - timelinesPluginSetup, - }: { - coreStart: CoreStartTimelines; - parameters: AppMountParameters; - timelinesPluginSetup: TimelinesUIStart | null; - }) => { - const refetch = useRef(); - - const setRefetch = useCallback((_refetch) => { - refetch.current = _refetch; - }, []); - - const hasAlertsCrudPermissions = useCallback(() => true, []); - - return ( - - - - - {(timelinesPluginSetup && - timelinesPluginSetup.getTGrid && - timelinesPluginSetup.getTGrid<'standalone'>({ - type: 'standalone', - columns: [], - indexNames: [], - deletedEventIds: [], - disabledCellActions: [], - end: '', - filters: [], - hasAlertsCrudPermissions, - itemsPerPageOptions: [1, 2, 3], - loadingText: 'Loading events', - renderCellValue: () =>

    test
    , - sort: [], - leadingControlColumns: [], - trailingControlColumns: [], - query: { - query: '', - language: 'kuery', - }, - setRefetch, - start: '', - rowRenderers: [], - runtimeMappings: {}, - filterStatus: 'open', - unit: (n: number) => `${n}`, - })) ?? - null} - - - - - ); - } -); diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/public/index.ts b/x-pack/test/plugin_functional/plugins/timelines_test/public/index.ts deleted file mode 100644 index 540e23622b2b3..0000000000000 --- a/x-pack/test/plugin_functional/plugins/timelines_test/public/index.ts +++ /dev/null @@ -1,20 +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 { PluginInitializer } from '@kbn/core/public'; -import { - TimelinesTestPlugin, - TimelinesTestPluginSetupDependencies, - TimelinesTestPluginStartDependencies, -} from './plugin'; - -export const plugin: PluginInitializer< - void, - void, - TimelinesTestPluginSetupDependencies, - TimelinesTestPluginStartDependencies -> = () => new TimelinesTestPlugin(); diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/public/plugin.ts b/x-pack/test/plugin_functional/plugins/timelines_test/public/plugin.ts deleted file mode 100644 index 13758e02603a3..0000000000000 --- a/x-pack/test/plugin_functional/plugins/timelines_test/public/plugin.ts +++ /dev/null @@ -1,54 +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 { Plugin, CoreStart, CoreSetup, AppMountParameters } from '@kbn/core/public'; -import { i18n } from '@kbn/i18n'; -import { TimelinesUIStart } from '@kbn/timelines-plugin/public'; -import { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import { renderApp } from './applications/timelines_test'; - -export type TimelinesTestPluginSetup = void; -export type TimelinesTestPluginStart = void; -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface TimelinesTestPluginSetupDependencies {} - -export interface TimelinesTestPluginStartDependencies { - timelines: TimelinesUIStart; - data: DataPublicPluginStart; -} - -export class TimelinesTestPlugin - implements - Plugin< - TimelinesTestPluginSetup, - void, - TimelinesTestPluginSetupDependencies, - TimelinesTestPluginStartDependencies - > -{ - private timelinesPlugin: TimelinesUIStart | null = null; - public setup( - core: CoreSetup, - setupDependencies: TimelinesTestPluginSetupDependencies - ) { - core.application.register({ - id: 'timelinesTest', - title: i18n.translate('xpack.timelinesTest.pluginTitle', { - defaultMessage: 'Timelines Test', - }), - mount: async (params: AppMountParameters) => { - const startServices = await core.getStartServices(); - const [coreStart, { data }] = startServices; - return renderApp({ ...coreStart, data }, params, this.timelinesPlugin); - }, - }); - } - - public start(core: CoreStart, { timelines }: TimelinesTestPluginStartDependencies) { - this.timelinesPlugin = timelines; - } -} diff --git a/x-pack/test/plugin_functional/test_suites/timelines/index.ts b/x-pack/test/plugin_functional/test_suites/timelines/index.ts deleted file mode 100644 index 955966eab12c0..0000000000000 --- a/x-pack/test/plugin_functional/test_suites/timelines/index.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 { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getPageObjects, getService }: FtrProviderContext) { - describe('Timelines plugin API', function () { - const pageObjects = getPageObjects(['common']); - const testSubjects = getService('testSubjects'); - - describe('timelines plugin rendering', function () { - before(async () => { - await pageObjects.common.navigateToApp('timelineTest'); - }); - it('shows the timeline component on navigation', async () => { - await testSubjects.existOrFail('events-viewer-panel'); - }); - }); - }); -} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts b/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts index dfd75d2e65248..aafd24b7a08e2 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts @@ -27,7 +27,8 @@ export default function ({ getService }: FtrProviderContext) { } }; - describe('Job parameter validation', () => { + // Failing: See https://github.com/elastic/kibana/issues/143717 + describe.skip('Job parameter validation', () => { before(async () => { await reportingAPI.initEcommerce(); }); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts index 11982a8b51425..2785fece6d90a 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { RuleRegistrySearchResponse } from '@kbn/rule-registry-plugin/common/search_strategy'; -import { QueryCreateSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/request'; +import { QueryRuleCreateProps } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { deleteSignalsIndex, @@ -118,7 +118,7 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); - const rule: QueryCreateSchema = { + const rule: QueryRuleCreateProps = { ...getRuleForSignalTesting(['auditbeat-*']), query: `_id:${ID}`, }; diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/legacy_url_aliases.json b/x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/legacy_url_aliases.json new file mode 100644 index 0000000000000..3b3f99cad1e51 --- /dev/null +++ b/x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/legacy_url_aliases.json @@ -0,0 +1,6 @@ +{ + "sourceId": "alias-match", + "targetNamespace": "default", + "targetType": "resolvetype", + "targetId": "alias-match-newid" +} diff --git a/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts b/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts index 9d88842f2b0fd..38a4a8d8db8c7 100644 --- a/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts +++ b/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts @@ -89,6 +89,7 @@ const createRequest = ({ type, id, initialNamespaces }: BulkCreateTestCase) => ( export function bulkCreateTestSuiteFactory(context: FtrProviderContext) { const testDataLoader = getTestDataLoader(context); const supertest = context.getService('supertestWithoutAuth'); + const log = context.getService('log'); const expectSavedObjectForbidden = expectResponses.forbiddenTypes('bulk_create'); const expectResponseBody = @@ -113,6 +114,9 @@ export function bulkCreateTestSuiteFactory(context: FtrProviderContext) { const { type, id } = testCase; expect(object.type).to.eql(type); expect(object.id).to.eql(id); + log.info( + `object type: ${object.type}, id: ${object.id}, namespaces: ${object.namespaces}` + ); let expectedMetadata; if (testCase.fail409Param === 'unresolvableConflict') { expectedMetadata = { isNotOverwritable: true }; @@ -216,6 +220,29 @@ export function bulkCreateTestSuiteFactory(context: FtrProviderContext) { 'x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/space_2.json', }, ]); + await testDataLoader.createLegacyUrlAliases([ + { + spaceName: null, + dataUrl: + 'x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/legacy_url_aliases.json', + }, + { + spaceName: SPACE_1.id, + dataUrl: + 'x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/legacy_url_aliases.json', + }, + { + spaceName: 'space_x', + dataUrl: + 'x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/legacy_url_aliases.json', + }, + { + spaceName: 'space_y', + dataUrl: + 'x-pack/test/saved_object_api_integration/common/fixtures/kbn_archiver/legacy_url_aliases.json', + disabled: true, + }, + ]); }); after(async () => { diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts index 4176b6707b124..bc75501d76b81 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/bulk_create.ts @@ -164,7 +164,7 @@ export default function (context: FtrProviderContext) { }; // Failing: See https://github.com/elastic/kibana/issues/122827 - describe.skip('_bulk_create', () => { + describe('_bulk_create', () => { getTestScenarios([false, true]).securityAndSpaces.forEach( ({ spaceId, users, modifier: overwrite }) => { const suffix = ` within the ${spaceId} space${overwrite ? ' with overwrite enabled' : ''}`; diff --git a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts index bccc55403ba79..befb34127c1c5 100644 --- a/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts +++ b/x-pack/test/saved_object_api_integration/spaces_only/apis/bulk_create.ts @@ -114,7 +114,7 @@ export default function (context: FtrProviderContext) { }; // Failing: See https://github.com/elastic/kibana/issues/141782 - describe.skip('_bulk_create', () => { + describe('_bulk_create', () => { getTestScenarios([false, true]).spaces.forEach(({ spaceId, modifier: overwrite }) => { const suffix = overwrite ? ' with overwrite enabled' : ''; const tests = createTests(overwrite!, spaceId); diff --git a/x-pack/test/saved_object_tagging/api_integration/security_and_spaces/apis/_get_assignable_types.ts b/x-pack/test/saved_object_tagging/api_integration/security_and_spaces/apis/_get_assignable_types.ts index 673ae6f73fac2..479fbe681d895 100644 --- a/x-pack/test/saved_object_tagging/api_integration/security_and_spaces/apis/_get_assignable_types.ts +++ b/x-pack/test/saved_object_tagging/api_integration/security_and_spaces/apis/_get_assignable_types.ts @@ -32,7 +32,16 @@ export default function (ftrContext: FtrProviderContext) { }); const assignablePerUser = { - [USERS.SUPERUSER.username]: ['dashboard', 'visualization', 'map', 'lens', 'search'], + [USERS.SUPERUSER.username]: [ + 'dashboard', + 'visualization', + 'map', + 'lens', + 'search', + 'osquery-pack', + 'osquery-pack-asset', + 'osquery-saved-query', + ], [USERS.DEFAULT_SPACE_SO_TAGGING_READ_USER.username]: [], [USERS.DEFAULT_SPACE_READ_USER.username]: [], [USERS.DEFAULT_SPACE_ADVANCED_SETTINGS_READ_USER.username]: [], diff --git a/x-pack/test/security_api_integration/fixtures/user_profiles/user_profiles_consumer/server/init_routes.ts b/x-pack/test/security_api_integration/fixtures/user_profiles/user_profiles_consumer/server/init_routes.ts index aa45cb7e3bb4f..091e50ff17350 100644 --- a/x-pack/test/security_api_integration/fixtures/user_profiles/user_profiles_consumer/server/init_routes.ts +++ b/x-pack/test/security_api_integration/fixtures/user_profiles/user_profiles_consumer/server/init_routes.ts @@ -16,8 +16,13 @@ export function initRoutes(core: CoreSetup) { path: '/internal/user_profiles_consumer/_suggest', validate: { body: schema.object({ - name: schema.string(), + name: schema.maybe(schema.string()), dataPath: schema.maybe(schema.string()), + hint: schema.maybe( + schema.object({ + uids: schema.arrayOf(schema.string()), + }) + ), size: schema.maybe(schema.number()), requiredAppPrivileges: schema.maybe(schema.arrayOf(schema.string())), }), @@ -28,6 +33,7 @@ export function initRoutes(core: CoreSetup) { const profiles = await pluginDeps.security.userProfiles.suggest({ name: request.body.name, dataPath: request.body.dataPath, + hint: request.body.hint, size: request.body.size, requiredPrivileges: request.body.requiredAppPrivileges ? { diff --git a/x-pack/test/security_api_integration/tests/user_profiles/suggest.ts b/x-pack/test/security_api_integration/tests/user_profiles/suggest.ts index 1e45f0edacf37..cf58f1b35d3b5 100644 --- a/x-pack/test/security_api_integration/tests/user_profiles/suggest.ts +++ b/x-pack/test/security_api_integration/tests/user_profiles/suggest.ts @@ -305,7 +305,7 @@ export default function ({ getService }: FtrProviderContext) { .post('/internal/security/user_profile/_data') .set('kbn-xsrf', 'xxx') .set('Cookie', usersSessions.get('user_one')!.cookie.cookieString()) - .send({ some: 'data', some_nested: { data: 'nested_data' } }) + .send({ some: 'data', some_more: 'data', some_nested: { data: 'nested_data' } }) .expect(200); // 2. Data is not returned by default @@ -334,7 +334,7 @@ export default function ({ getService }: FtrProviderContext) { suggestions = await supertest .post('/internal/user_profiles_consumer/_suggest') .set('kbn-xsrf', 'xxx') - .send({ name: 'one', requiredAppPrivileges: ['discover'], dataPath: 'some' }) + .send({ name: 'one', requiredAppPrivileges: ['discover'], dataPath: 'some,some_more' }) .expect(200); expect(suggestions.body).to.have.length(1); expectSnapshot( @@ -344,6 +344,7 @@ export default function ({ getService }: FtrProviderContext) { Object { "data": Object { "some": "data", + "some_more": "data", }, "user": Object { "email": "one@elastic.co", @@ -368,6 +369,7 @@ export default function ({ getService }: FtrProviderContext) { Object { "data": Object { "some": "data", + "some_more": "data", "some_nested": Object { "data": "nested_data", }, @@ -381,5 +383,31 @@ export default function ({ getService }: FtrProviderContext) { ] `); }); + + it('can get suggestions with hints', async () => { + const profile = await supertestWithoutAuth + .get('/internal/security/user_profile') + .set('kbn-xsrf', 'xxx') + .set('Cookie', usersSessions.get('user_three')!.cookie.cookieString()) + .expect(200); + + expect(profile.body.uid).not.to.be.empty(); + + const suggestions = await supertest + .post('/internal/user_profiles_consumer/_suggest') + .set('kbn-xsrf', 'xxx') + .send({ hint: { uids: [profile.body.uid] } }) + .expect(200); + + // `user_three` should be first in list + expect(suggestions.body.length).to.be.above(0); + expectSnapshot(suggestions.body[0].user).toMatchInline(` + Object { + "email": "three@elastic.co", + "full_name": "THREE", + "username": "user_three", + } + `); + }); }); } diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts index ddcbbc6251fdf..56cbfb782a8cc 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts @@ -76,7 +76,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); }; - describe('Response Actions Responder', function () { + // Failing: See https://github.com/elastic/kibana/issues/142148 + describe.skip('Response Actions Responder', function () { let indexedData: IndexedHostsAndAlertsResponse; let endpointAgentId: string; diff --git a/x-pack/test/security_solution_ftr/services/detections/index.ts b/x-pack/test/security_solution_ftr/services/detections/index.ts index 1d3e18f1ab43d..024dede892be5 100644 --- a/x-pack/test/security_solution_ftr/services/detections/index.ts +++ b/x-pack/test/security_solution_ftr/services/detections/index.ts @@ -13,8 +13,8 @@ import { DETECTION_ENGINE_RULES_URL, } from '@kbn/security-solution-plugin/common/constants'; import { estypes } from '@elastic/elasticsearch'; -import endpointPrePackagedRule from '@kbn/security-solution-plugin/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json'; -import { Rule } from '@kbn/security-solution-plugin/public/detections/containers/detection_engine/rules'; +import endpointPrePackagedRule from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/content/prepackaged_rules/elastic_endpoint_security.json'; +import { Rule } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types'; import { FtrService } from '../../../functional/ftr_provider_context'; export class DetectionsTestService extends FtrService { diff --git a/yarn.lock b/yarn.lock index a7a1440720c61..00d479810e668 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3493,6 +3493,10 @@ version "0.0.0" uid "" +"@kbn/guided-onboarding@link:bazel-bin/packages/kbn-guided-onboarding": + version "0.0.0" + uid "" + "@kbn/handlebars@link:bazel-bin/packages/kbn-handlebars": version "0.0.0" uid "" @@ -7665,6 +7669,10 @@ version "0.0.0" uid "" +"@types/kbn__guided-onboarding@link:bazel-bin/packages/kbn-guided-onboarding/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__handlebars@link:bazel-bin/packages/kbn-handlebars/npm_module_types": version "0.0.0" uid "" @@ -12381,6 +12389,13 @@ cross-env@^6.0.3: dependencies: cross-spawn "^7.0.0" +cross-fetch@3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -13242,13 +13257,6 @@ debug@4.1.1: dependencies: ms "^2.1.1" -debug@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -13594,10 +13602,10 @@ detective@^5.0.2: defined "^1.0.0" minimist "^1.1.1" -devtools-protocol@0.0.901419: - version "0.0.901419" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.901419.tgz#79b5459c48fe7e1c5563c02bd72f8fec3e0cebcd" - integrity sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ== +devtools-protocol@0.0.1045489: + version "0.0.1045489" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1045489.tgz#f959ad560b05acd72d55644bc3fb8168a83abf28" + integrity sha512-D+PTmWulkuQW4D1NTiCRCFxF7pQPn0hgp4YyX4wAQ6xYXKOadSWPR3ENGDQ47MW/Ewc9v2rpC/UEEGahgBYpSQ== dezalgo@^1.0.0: version "1.0.3" @@ -17060,7 +17068,7 @@ https-proxy-agent@5.0.0: agent-base "6" debug "4" -https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: +https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -21027,7 +21035,7 @@ node-emoji@^1.10.0: dependencies: lodash.toarray "^4.4.0" -node-fetch@2.6.1, node-fetch@^1.0.1, node-fetch@^2.3.0, node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@^1.0.1, node-fetch@^2.3.0, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -22281,13 +22289,6 @@ pixelmatch@^5.3.0: dependencies: pngjs "^6.0.0" -pkg-dir@4.2.0, pkg-dir@^4.1.0, pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" @@ -22302,6 +22303,13 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" +pkg-dir@^4.1.0, pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + pkg-dir@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" @@ -22926,21 +22934,16 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -progress@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.1.tgz#c9242169342b1c29d275889c95734621b1952e31" - integrity sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg== +progress@2.0.3, progress@^2.0.0, progress@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= -progress@^2.0.0, progress@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - proj4@2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/proj4/-/proj4-2.6.2.tgz#4665d7cbc30fd356375007c2fed53b07dbda1d67" @@ -23190,23 +23193,22 @@ pupa@^2.1.1: dependencies: escape-goat "^2.0.0" -puppeteer@^10.2.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-10.4.0.tgz#a6465ff97fda0576c4ac29601406f67e6fea3dc7" - integrity sha512-2cP8mBoqnu5gzAVpbZ0fRaobBWZM8GEUF4I1F6WbgHrKV/rz7SX8PG2wMymZgD0wo0UBlg2FBPNxlF/xlqW6+w== +puppeteer@18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-18.1.0.tgz#7fa53b29f87dfb3192d415f38a46e35b107ec907" + integrity sha512-2RCVWIF+pZOSfksWlQU0Hh6CeUT5NYt66CDDgRyuReu6EvBAk1y+/Q7DuzYNvGChSecGMb7QPN0hkxAa3guAog== dependencies: - debug "4.3.1" - devtools-protocol "0.0.901419" + cross-fetch "3.1.5" + debug "4.3.4" + devtools-protocol "0.0.1045489" extract-zip "2.0.1" - https-proxy-agent "5.0.0" - node-fetch "2.6.1" - pkg-dir "4.2.0" - progress "2.0.1" + https-proxy-agent "5.0.1" + progress "2.0.3" proxy-from-env "1.1.0" rimraf "3.0.2" - tar-fs "2.0.0" - unbzip2-stream "1.3.3" - ws "7.4.6" + tar-fs "2.1.1" + unbzip2-stream "1.4.3" + ws "8.9.0" q@^1.5.1: version "1.5.1" @@ -26638,17 +26640,7 @@ tape@^5.0.1: string.prototype.trim "^1.2.1" through "^2.3.8" -tar-fs@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad" - integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA== - dependencies: - chownr "^1.1.1" - mkdirp "^0.5.1" - pump "^3.0.0" - tar-stream "^2.0.0" - -tar-fs@^2.0.0, tar-fs@^2.1.1: +tar-fs@2.1.1, tar-fs@^2.0.0, tar-fs@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -26658,7 +26650,7 @@ tar-fs@^2.0.0, tar-fs@^2.1.1: pump "^3.0.0" tar-stream "^2.1.4" -tar-stream@^2.0.0, tar-stream@^2.1.4, tar-stream@^2.2.0: +tar-stream@^2.1.4, tar-stream@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -27448,10 +27440,10 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" -unbzip2-stream@1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a" - integrity sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg== +unbzip2-stream@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== dependencies: buffer "^5.2.1" through "^2.3.8" @@ -29112,10 +29104,10 @@ write-file-atomic@^4.0.1: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.9.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e" + integrity sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg== ws@>=8.7.0, ws@^8.2.3, ws@^8.4.2: version "8.8.0"