diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 50bd3144b1ccb..04cd0d29b76d1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -143,7 +143,6 @@ x-pack/examples/files_example @elastic/kibana-app-services /src/core/types/elasticsearch @elastic/apm-ui /packages/kbn-utility-types/src/dot.ts @dgieselaar /packages/kbn-utility-types/src/dot_test.ts @dgieselaar -/packages/kbn-adhoc-profiler @elastic/apm-ui #CC# /src/plugins/apm_oss/ @elastic/apm-ui #CC# /x-pack/plugins/observability/ @elastic/apm-ui @@ -478,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 @@ -508,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 @@ -528,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 @@ -596,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 @@ -856,7 +860,6 @@ packages/home/sample_data_card @elastic/shared-ux packages/home/sample_data_tab @elastic/shared-ux packages/home/sample_data_types @elastic/shared-ux packages/kbn-ace @elastic/platform-deployment-management -packages/kbn-adhoc-profiler @elastic/apm-ui packages/kbn-alerts @elastic/security-solution packages/kbn-ambient-storybook-types @elastic/kibana-operations packages/kbn-ambient-ui-types @elastic/kibana-operations diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 2ba7542f0c07b..fd854701b7dae 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-20 +date: 2022-10-24 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 d3c4a3465e0f2..7fe0d5d40235d 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-20 +date: 2022-10-24 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 7b8d4fb88c3b9..dc79f19c864aa 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-20 +date: 2022-10-24 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 e42b5ce906ba7..c4320e2c91121 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-20 +date: 2022-10-24 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 aa224ba811cd4..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", @@ -3031,9 +3031,9 @@ }, ", { 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", @@ -3091,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", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index f20727d06136f..dc40e7853ce2f 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index c2d744dd827a1..6b019f3a59567 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-20 +date: 2022-10-24 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 d36bbdf86ecf8..987ca5ff11074 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-20 +date: 2022-10-24 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 5437c10f4d717..fc205f73fabe6 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-20 +date: 2022-10-24 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 1de3ab4a521c3..8119cb3966c0d 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-20 +date: 2022-10-24 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 a48c8fe6661d1..4d9ddf5e4dde6 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-20 +date: 2022-10-24 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 7dc42f6387741..38641d23ed388 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-20 +date: 2022-10-24 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 f965713b58874..426269cb31393 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-20 +date: 2022-10-24 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 4dc125f728eca..1e421a3f35ea1 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-20 +date: 2022-10-24 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 9bd0886195c83..a22d44919bd88 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-20 +date: 2022-10-24 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 e1e057275a72c..abb27f5b269f5 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 7eb5069f01084..1fd8dba3211e0 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/core.devdocs.json b/api_docs/core.devdocs.json index 61651256d45da..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", @@ -40262,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", @@ -40870,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", @@ -46341,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", diff --git a/api_docs/core.mdx b/api_docs/core.mdx index cef8140fc8f77..8f9cee2a6279f 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-20 +date: 2022-10-24 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 | |-------------------|-----------|------------------------|-----------------| -| 2693 | 0 | 23 | 0 | +| 2697 | 0 | 23 | 0 | ## Client diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index c4f6a7138fb07..203d145d5ec50 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-20 +date: 2022-10-24 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 ec1e651a84cce..e7433c21e9280 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-20 +date: 2022-10-24 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 a39f0a5630e2b..bb048786661f7 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-20 +date: 2022-10-24 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 56d5bed9224e6..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,10 +11501,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "unifiedSearch", - "path": "src/plugins/unified_search/public/query_string_input/query_string_input.tsx" - }, { "plugin": "maps", "path": "x-pack/plugins/maps/public/kibana_services.ts" @@ -11776,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, @@ -12199,18 +12211,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "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" @@ -12557,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", @@ -19683,18 +19683,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "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" @@ -20041,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", @@ -25662,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 53b9fae5b68de..4c69b81b57a2f 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-20 +date: 2022-10-24 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 f8134455e6755..3a2f06a82a309 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-20 +date: 2022-10-24 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 8747220113c14..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", @@ -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 de74ebd14d8fd..81ed7ca0a25f8 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-20 +date: 2022-10-24 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 e7526b2d366cc..66cdf95555923 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-20 +date: 2022-10-24 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 30aaae06c143e..0a19c0b9a13dd 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-20 +date: 2022-10-24 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 d889d65cf65ea..30c65e7cb62dc 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-20 +date: 2022-10-24 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 cedcb41cb3040..38860d23cee6a 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -209,18 +209,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "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" @@ -567,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", @@ -8136,18 +8124,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "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" @@ -8494,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", @@ -15210,18 +15186,6 @@ "plugin": "unifiedFieldList", "path": "src/plugins/unified_field_list/common/utils/field_existing_utils.ts" }, - { - "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" @@ -15568,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", @@ -23213,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 25afb00311744..858ae42727905 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-20 +date: 2022-10-24 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 de8f8c678f99b..a2a80c5154d4d 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-20 +date: 2022-10-24 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 aa80017cd3fe9..5b11da9cc8894 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -33,15 +33,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | data, discover, embeddable | - | | | advancedSettings, discover | - | | | advancedSettings, discover | - | -| | unifiedSearch, maps, infra, graph, securitySolution, stackAlerts, inputControlVis, savedObjects | - | +| | 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 fc37544ad5717..8855f9150836b 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-20 +date: 2022-10-24 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) | - | @@ -739,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), [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/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) | - | | | [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), [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)+ 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 | +| | [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) | - | @@ -870,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 320e23c36d6e1..7b6cb06508524 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-20 +date: 2022-10-24 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 d6d54b0e4ab25..0feec691d406c 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-20 +date: 2022-10-24 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 61701f6178751..60bf441d66068 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-20 +date: 2022-10-24 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 5e55cad79b38a..4a5b349acb9dd 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 0dd00809e2877..0b6dd63154f5b 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-20 +date: 2022-10-24 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 cc93dd117ccb1..d4f1f4a57a6e1 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-20 +date: 2022-10-24 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 c1d7bf09b9d1f..247f65e1f0d4b 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-20 +date: 2022-10-24 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 918925909b18c..c4da56246b68e 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-20 +date: 2022-10-24 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 483d97ab9c62e..c5f2230103aab 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-20 +date: 2022-10-24 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 e7b47eb46b459..498491b480150 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-20 +date: 2022-10-24 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 8a4cb8d6f21ff..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; uuid?: 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; 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)[]" + "(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; uuid?: 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; 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" + "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; uuid?: 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; 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" + "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 3fdd39f12e552..1d2706ea1b2c1 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-20 +date: 2022-10-24 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 f441cb64c6c2e..f6253ab5570b5 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-20 +date: 2022-10-24 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 7f6a45e660c15..a3ab9a63ff6a1 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-20 +date: 2022-10-24 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 76181e4621e3c..8335b1da72019 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-20 +date: 2022-10-24 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 8f162e409b123..0e91bb98190a2 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-20 +date: 2022-10-24 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 58da6f6098120..ca60b919dfa38 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-20 +date: 2022-10-24 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 abc85bd558222..4b63148d14da6 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-20 +date: 2022-10-24 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 02213c68db14c..9a8b4d9653ec7 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-20 +date: 2022-10-24 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 6032cfe7da671..28f8759733ebb 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-20 +date: 2022-10-24 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 0db7950f1d91d..4b1814f785cbf 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-20 +date: 2022-10-24 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 ea00ede6222e9..43bc92d505368 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-20 +date: 2022-10-24 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 d45fe1df7e3be..51ee5e5e74128 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-20 +date: 2022-10-24 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 c27c5c079bc40..82f4f9235ebae 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-20 +date: 2022-10-24 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 e445e325a6fde..999b6f4b44f74 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-20 +date: 2022-10-24 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 f3777ecfaf65b..e6e78ade43e99 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-20 +date: 2022-10-24 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 b57ca485dacbe..6a521bc986a2f 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-20 +date: 2022-10-24 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 cef8fba31f3aa..d5714fc7d1036 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-20 +date: 2022-10-24 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 c6e65acd0c2e1..74d0df107707d 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 6e771a1243552..b3e811531cb49 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-20 +date: 2022-10-24 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 c2a258d682244..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, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 087cf7a080abc..9411e94690d6d 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-20 +date: 2022-10-24 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 f3d93c0b96f28..bd17be79cdc7b 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-20 +date: 2022-10-24 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 726b6f3c654f4..881a886f2610a 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-20 +date: 2022-10-24 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 2e08125dbf0df..9b0f2944cb20b 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-20 +date: 2022-10-24 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 ee2c2b3c76c61..879adf658036e 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-20 +date: 2022-10-24 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 ccf82eecd640c..252f8ed81b6bf 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-20 +date: 2022-10-24 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 2a13ce12dafe2..11f572a0541d3 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-20 +date: 2022-10-24 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 3d47e4cc70f9a..aba491b93a8e1 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-20 +date: 2022-10-24 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 9746756f8ab42..5dfc6d364accb 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-20 +date: 2022-10-24 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 c26bdc0a8083d..a9d4f451049e0 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-20 +date: 2022-10-24 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 9e282340ca79b..e856824cd465b 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-20 +date: 2022-10-24 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 7799cbb0da0da..25a5a279932cf 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-20 +date: 2022-10-24 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 6a0fe5ecba9c1..394760e1e2507 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-20 +date: 2022-10-24 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 ec29231f78d09..64e297d8c02a4 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index b971dd4478fc0..ee740710cc89c 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-20 +date: 2022-10-24 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 6f0d1df3c1bbb..8f0d89b32f870 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-20 +date: 2022-10-24 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 4418c2cf4afea..a13ae9f793bd3 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-20 +date: 2022-10-24 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 4ef5ce2ef87d8..ab9e813825ec0 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-20 +date: 2022-10-24 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 84685fd08bd10..c8e99aaa70fa9 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index d5aa154b832f8..15a9175703af1 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2022-10-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index c52448ed80232..0e2b948836ae9 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-20 +date: 2022-10-24 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 50629462e2b39..b4cf8d19dc2ed 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-20 +date: 2022-10-24 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 e65246d87557b..0a8b85a80ac71 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-20 +date: 2022-10-24 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 f8e125f5b780f..774a0ee0330c0 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-20 +date: 2022-10-24 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 00943cc13ceb5..56a10f629d6b4 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-20 +date: 2022-10-24 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 459755e68f057..b96d4163b65c4 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-20 +date: 2022-10-24 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 01138f069b066..34a85abda98bc 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-20 +date: 2022-10-24 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 e356290cd47e1..b6799e71abd08 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-20 +date: 2022-10-24 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 13abde8e6ce1c..f8887d91bcdc3 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-20 +date: 2022-10-24 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 6531f9a9c4a1e..d8543e906772e 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-20 +date: 2022-10-24 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 98e8b32d6927b..4ec2f8f515d3d 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-20 +date: 2022-10-24 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 cd44d6dbd6bcd..c8013cb00173b 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-20 +date: 2022-10-24 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 029f9987bb411..3785f9ac2944d 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-20 +date: 2022-10-24 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 8266a971c454a..70f3d9c4d3b5b 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-20 +date: 2022-10-24 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 62f6515643884..2f7d72fe038b9 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-20 +date: 2022-10-24 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 39f44bcf5c4db..f63116031e19c 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-20 +date: 2022-10-24 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 bcb243ba3411b..68d907d76e677 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-20 +date: 2022-10-24 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 58502ae32a939..4a3621f85a0ff 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-20 +date: 2022-10-24 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 05b908cc151c2..ca8068039751c 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-20 +date: 2022-10-24 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 9dc30e9abfb98..6785dd1c24cf0 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-20 +date: 2022-10-24 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 7a081daf64743..3af523b673b03 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-20 +date: 2022-10-24 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 47a8b2bbe3197..f7be87db8d166 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-20 +date: 2022-10-24 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 c30b1ccd5b390..dec5910b5372e 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-20 +date: 2022-10-24 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 d142c7c8838d6..45f826f3b3bc0 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-20 +date: 2022-10-24 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 d61802c3b00af..ed6ce1bada64c 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-20 +date: 2022-10-24 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 e35b13e80d01b..7301f169abebc 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-20 +date: 2022-10-24 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 411a78189f813..da1a1129beb6d 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-20 +date: 2022-10-24 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 4369bd9e3ea0c..65ca57d22c847 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-20 +date: 2022-10-24 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 f355006efea46..3cd12a8468154 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-20 +date: 2022-10-24 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 94cdf4ef4d11d..fa31c5c961afc 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-20 +date: 2022-10-24 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 1161eda5a59fe..8eaa7503a4f71 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-20 +date: 2022-10-24 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 265cd3fc774ab..90127fcda829f 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-20 +date: 2022-10-24 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 fede42e9d0dd3..450ece2351577 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-20 +date: 2022-10-24 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 e8d75ce033da9..48d443e3b00b1 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-20 +date: 2022-10-24 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 4e5e050a5c0e7..c022306576030 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-20 +date: 2022-10-24 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 fe100b0920608..f4a49ab875779 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-20 +date: 2022-10-24 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 7ae7bba520fb9..92d82d26e605c 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-20 +date: 2022-10-24 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 bbd49dea4979b..d75d3570bae13 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-20 +date: 2022-10-24 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 4cf11b93369e3..1ef10f67a6ce7 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-20 +date: 2022-10-24 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 aeb4e0ae4ecee..7a76cfe89994c 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-20 +date: 2022-10-24 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 1cf8420a6b97a..1b048e3c47dad 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-20 +date: 2022-10-24 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 fcb2097c28cb9..0de0c7f12fe59 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-20 +date: 2022-10-24 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 dd981a61e355e..a3a5411e49c9d 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-20 +date: 2022-10-24 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 ade2be4bebe74..5bad8b2ae00d1 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-20 +date: 2022-10-24 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 e6666ab809257..e774ea2f7b74c 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-20 +date: 2022-10-24 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 f3ccd9d1366e4..1796e47ccb045 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-20 +date: 2022-10-24 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 738a3b277d8e0..120f5cad04abc 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-20 +date: 2022-10-24 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 b308c2adcab7b..d556c7dc38d45 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-20 +date: 2022-10-24 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 eb72c0bc4dfe9..92f40659a5997 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-20 +date: 2022-10-24 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 02441d501dfbf..89bdb5f8dd359 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 591759a1c7d69..be7c56c041911 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 2739e7d96b49e..3619c8e0bca43 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 0b1c2b9ad1654..22faa7a16af25 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-20 +date: 2022-10-24 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 2df63c669ea89..790152efe2351 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-20 +date: 2022-10-24 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 756ec32503839..4d38008e4a031 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-20 +date: 2022-10-24 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 6264f03019292..55895197efb86 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-20 +date: 2022-10-24 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 f5aa12e30b02a..661c35b0e186a 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-20 +date: 2022-10-24 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 97a8f7840a8dc..b921a2fafac42 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-20 +date: 2022-10-24 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 1d0cd0c1bc692..2ce6736b1765d 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-20 +date: 2022-10-24 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 8cdea0c7f0c1b..c95b7c4ae721b 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-20 +date: 2022-10-24 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 15dbe3b1d82f8..35900d2f66567 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-20 +date: 2022-10-24 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 6217c28a7f041..cc4ff29d79a44 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-20 +date: 2022-10-24 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 5d61440d74bf1..eeb3cea35a301 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-20 +date: 2022-10-24 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 f3938fb47b989..475b11e99f695 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-20 +date: 2022-10-24 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 0aa76ef83048d..9c1936ddd77b7 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-20 +date: 2022-10-24 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 e06d2aee4c7c3..81d63fc9b6f39 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-20 +date: 2022-10-24 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 7c0035c2d3eb7..85473fb712d0c 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-20 +date: 2022-10-24 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 80bc22c6eb865..0cac187128314 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-20 +date: 2022-10-24 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 744fde2fb9c04..6f900446a59a5 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-20 +date: 2022-10-24 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 ec23789bb2a92..6bddc86756fe5 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-20 +date: 2022-10-24 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 4478bd912b23b..e28e61ffb0376 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 61da8e383b619..2aeb4b9454952 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index ee5068b3ff7ef..d5f8e50c2da73 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index 67207dd25cbdb..02e122b5473b0 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-20 +date: 2022-10-24 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 a5f2b456a30ae..75997bef4e255 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-20 +date: 2022-10-24 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 1e347c3470883..f062b763f0b69 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-20 +date: 2022-10-24 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 6c5e8c178a052..940ed5d080979 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index a01bae8661e79..75178ea85da02 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-20 +date: 2022-10-24 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 2efc3f42097d9..ef3250a681d44 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-20 +date: 2022-10-24 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 3a87234600ca4..3eb1a9e3a5d6e 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-20 +date: 2022-10-24 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 df1dfc488ecf8..c4053d98527ac 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-20 +date: 2022-10-24 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 c95b92361b0fc..2698e1485a139 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-20 +date: 2022-10-24 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 e994fb4cf6099..6530943459ef4 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-20 +date: 2022-10-24 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 c57fce245fc88..7e03c6d47515a 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-20 +date: 2022-10-24 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 4d1e468a6fdf1..746ba812a2037 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-20 +date: 2022-10-24 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 b63a9403138ce..532b5fe35e48f 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-20 +date: 2022-10-24 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 e564870c497f4..232be2470ac4e 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-20 +date: 2022-10-24 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 0e478b532f36b..dac8713e351e3 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-20 +date: 2022-10-24 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 42379bba304d0..037d552fe9452 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-20 +date: 2022-10-24 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 bb96d7fdc5a63..1a824bbba6194 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-20 +date: 2022-10-24 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 4d32b8d26576e..b96bcc4f4927e 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-20 +date: 2022-10-24 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 ef3e44515d46a..e54e0effb3fda 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-20 +date: 2022-10-24 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 f45b8f3fe9991..a87b0e0bb3cd5 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-20 +date: 2022-10-24 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 4c6ee9a54a3f4..251470bc5dd68 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-20 +date: 2022-10-24 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 7596c452104c8..9836655a7a7c6 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-20 +date: 2022-10-24 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 33bffcdebd5b1..cfbabf60a4989 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-20 +date: 2022-10-24 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 1c67f82360251..91e6d190572cb 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-20 +date: 2022-10-24 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 6c7d84c244062..13e4430c8cce1 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-20 +date: 2022-10-24 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 ef6d579dbbc6a..2bb083295fa1f 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-20 +date: 2022-10-24 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 32ac9adb4d7fa..9384c8bf3cdf5 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-20 +date: 2022-10-24 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 31d44b6368d02..9da489b8443e2 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-20 +date: 2022-10-24 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 eb0b48f3258c9..faae84d73a4d2 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-20 +date: 2022-10-24 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 078ae3c322887..d33a2160531f8 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-20 +date: 2022-10-24 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 a62973a308372..51a5b6b1e5c05 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-20 +date: 2022-10-24 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 615d80e3f3d1d..094ecbc105bcd 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-20 +date: 2022-10-24 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 ac228aa11d27f..dab96b323695c 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-20 +date: 2022-10-24 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 245a8de84e0a8..1844875b57afd 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-20 +date: 2022-10-24 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 9fd437ea3d524..0bdbac43e793f 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-20 +date: 2022-10-24 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 adf7e2dff2462..78cd7f446eb68 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-20 +date: 2022-10-24 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 8a301dc079228..885b7856c5401 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-20 +date: 2022-10-24 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 4b05cd683fff0..5279be0e19fd8 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-20 +date: 2022-10-24 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 77b9ab16de808..9b4c4e881a10b 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-20 +date: 2022-10-24 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 9f7454efe9463..3ff2058158833 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-20 +date: 2022-10-24 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 4b8b277d3f188..a4b770408653f 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-20 +date: 2022-10-24 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 722724733b9fb..465f2c9612032 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-20 +date: 2022-10-24 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 c77ca067ccf79..7aabde923ad02 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-20 +date: 2022-10-24 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 ebbc378e704b5..ec7ef7497ef93 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-20 +date: 2022-10-24 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 997e4865963cd..1b389e8e63b18 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-20 +date: 2022-10-24 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 fdad2201eb1d6..9f1ea7478cbb4 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-20 +date: 2022-10-24 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 0abea07df3d82..151e7283d103c 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-20 +date: 2022-10-24 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 c47baa097dee1..5d82251619d8d 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-20 +date: 2022-10-24 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 34301e6c36c42..7fca357b09c2f 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-20 +date: 2022-10-24 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 fa0c5b3358ef0..83ece93b25df6 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-20 +date: 2022-10-24 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 b5f134fd1f25b..f7926112a4ff6 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-20 +date: 2022-10-24 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 fd555d015d896..39308f1c9ad22 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-20 +date: 2022-10-24 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 756bea18eecce..1d42426f0239b 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-20 +date: 2022-10-24 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 aa038f44c60fc..3d77891f2eb05 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index 35a0ccf314ac5..855f6ebe09734 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-20 +date: 2022-10-24 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 542316d98f76c..cfd08eb218eb5 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-20 +date: 2022-10-24 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 5bede64640645..b95526b573da0 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-20 +date: 2022-10-24 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 7151d4e301670..2d823860b5374 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-20 +date: 2022-10-24 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 9bad53c1d90f8..b0ac4a8706efa 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-20 +date: 2022-10-24 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 4486bb7a77ff7..079d4e771d0bc 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-20 +date: 2022-10-24 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 499573c017481..2e3f37a017eb1 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-20 +date: 2022-10-24 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 d4d8e4b2f3935..1b5d38f2d81dc 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-20 +date: 2022-10-24 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 fd36bed8802a8..189c26df3ad4a 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-20 +date: 2022-10-24 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 98a84b8888f48..9c46d9bd3ef4e 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-20 +date: 2022-10-24 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 b1ba5573c1275..f565c90572970 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-20 +date: 2022-10-24 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 0a908c13b90c9..9a1831ce59c4e 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-20 +date: 2022-10-24 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 c8f38f90961c8..9d39a35943acc 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-20 +date: 2022-10-24 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 aa136ebc4314b..824203afa7ef3 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-20 +date: 2022-10-24 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 222e433adcc57..384301230d651 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-20 +date: 2022-10-24 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 525c3d33a19e2..79c08444a084f 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-20 +date: 2022-10-24 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 8c0b9308f3fe2..625e5cd02b2cf 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-20 +date: 2022-10-24 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 e49eb21b72d26..c7a22a15e2ba2 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-20 +date: 2022-10-24 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 bb3dbc049e157..9b429cfd565f1 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-20 +date: 2022-10-24 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 775384f6e429a..1036b49b1b40b 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-20 +date: 2022-10-24 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 114cbc96fd128..ed14e3fab33a3 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-20 +date: 2022-10-24 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 7c52db31d9215..e8ff590475623 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-20 +date: 2022-10-24 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 384a98dc0e815..12c596c904e57 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-20 +date: 2022-10-24 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 4977e9d3bd1d8..0f37f30eff626 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-20 +date: 2022-10-24 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 f2a3cfad2cfd7..c1f5d84abe52a 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-20 +date: 2022-10-24 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 392f8b70696e8..1a8c00b643ac1 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-20 +date: 2022-10-24 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 1ce520759eda5..cf99719d58e03 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-20 +date: 2022-10-24 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 64d65497cfa2e..350c317c25736 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-20 +date: 2022-10-24 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 c0cbc0603ed6c..6a179a27e52ea 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-20 +date: 2022-10-24 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 078ff04fd52d0..320ce22f0f30d 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-20 +date: 2022-10-24 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 ecbd50655ac80..535d2b531b671 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-20 +date: 2022-10-24 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 171f762efd8aa..396d5dda411f1 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-20 +date: 2022-10-24 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 db58fbd4b64f0..571b864d4a46d 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-20 +date: 2022-10-24 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 74b0500f0da36..b03ef33093967 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-20 +date: 2022-10-24 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 8a033fd3cce5a..20182c161c8b4 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 3cb3447738cf8..f85e958b203d1 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-20 +date: 2022-10-24 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 7d49ef654a7fb..b01179afc26a8 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-20 +date: 2022-10-24 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 a3825c1b98894..d7c245297163b 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-20 +date: 2022-10-24 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 da654357a439d..2630a960da878 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-20 +date: 2022-10-24 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 9913165ebf9c9..fcd4f38bb91ec 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-20 +date: 2022-10-24 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 bfda31d414f0d..e36366844132a 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 7aa8e89065f97..142f3d50fb1d5 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-20 +date: 2022-10-24 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 5767e3df777d6..5b5bddf7a8c33 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-20 +date: 2022-10-24 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 70890717529c6..204a52445c079 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-20 +date: 2022-10-24 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 e1c7c9b64148c..e9f40628e3237 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-20 +date: 2022-10-24 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 aaae772f0474d..e5fec11c32dc4 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-20 +date: 2022-10-24 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 03c3adae55946..54b58587b993d 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-20 +date: 2022-10-24 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 c75d1541b415c..149848d28f56c 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-20 +date: 2022-10-24 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..529074de483d2 --- /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-24 +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 c74dfa715656f..b6c9d40630f2b 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-20 +date: 2022-10-24 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 5cd93024fd21a..062826d731640 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-20 +date: 2022-10-24 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 66717f174d7ca..736fc7a3bb769 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-20 +date: 2022-10-24 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 059bde302b82d..25dfc11c439f0 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-20 +date: 2022-10-24 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 fd0e2de299df9..180a8a8d4a047 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-20 +date: 2022-10-24 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 11485cdadb8b9..9c12bd37c24f8 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-20 +date: 2022-10-24 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 7a77370726a76..bf377fe03d22a 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-20 +date: 2022-10-24 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 365496e0818e4..0560059991350 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-20 +date: 2022-10-24 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 ab7866d328889..e36ad3bbccf33 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-20 +date: 2022-10-24 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 05168e70d9fec..d582dadda4a7f 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-20 +date: 2022-10-24 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 ff51909df5133..4d3beb4de75cb 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-20 +date: 2022-10-24 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 index c0faf383d25f6..efc5a267ed84c 100644 --- a/api_docs/kbn_language_documentation_popover.devdocs.json +++ b/api_docs/kbn_language_documentation_popover.devdocs.json @@ -50,6 +50,38 @@ } ], "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": [ diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index 8b6f96e1ff6db..dd1a7f8d2c9f1 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2022-10-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 5 | 0 | 4 | 0 | +| 7 | 0 | 5 | 0 | ## Common diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index ed9dec2418b85..6eb885da91b2a 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-20 +date: 2022-10-24 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 ccee0631ef96e..7be99c0dcf7a1 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-20 +date: 2022-10-24 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 6efdcc34c59c2..f06980ca9960a 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-20 +date: 2022-10-24 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 d6d6fa081932a..a2b0c579d9fa1 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-20 +date: 2022-10-24 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 cca86fdea568f..a9e3088d3b4c5 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-20 +date: 2022-10-24 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 4583213488325..269ebc5101497 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-20 +date: 2022-10-24 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 d871b9f5f84c5..0e64277b4e113 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-20 +date: 2022-10-24 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 4a1ba8cb9d2bd..aa6506c9fc1c0 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-20 +date: 2022-10-24 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 c4b6c3fc990ad..76c6259d827a5 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-20 +date: 2022-10-24 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 f2b169e94fb49..69615c6146432 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-20 +date: 2022-10-24 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 c352eff4d2f00..1eef3bdde91f5 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-20 +date: 2022-10-24 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 51cb17a1a38e3..fea368c7794cb 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-20 +date: 2022-10-24 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 8d7793bca3e89..b824d0ddcb8f9 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-20 +date: 2022-10-24 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 0068b1ada744d..0f54b2a8e4429 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-20 +date: 2022-10-24 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 5ebe317a643d5..7474c397ec7ac 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-20 +date: 2022-10-24 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 8d2eb036e35ab..c6eb8444a6492 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-20 +date: 2022-10-24 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 033714495c220..ad075b918828d 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-20 +date: 2022-10-24 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.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 8dc48bb6441e6..1e164bccfc64a 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-20 +date: 2022-10-24 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.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 8c8a1150a65ac..e81efd72ba920 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-20 +date: 2022-10-24 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.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index 4b8a99506de5e..9dbbabc241d20 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 8e96142a2edf6..5280445670309 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-20 +date: 2022-10-24 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 2ff12c9112da2..9510bef560cc9 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-20 +date: 2022-10-24 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.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 20107e0bfebe3..18e34b6b3cb7b 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-20 +date: 2022-10-24 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 2a216d0b905ba..e235250c54f10 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-20 +date: 2022-10-24 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 7cca0d51bd71e..ea1ad269f3956 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index d2b9f3cd245a1..4656817f22674 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-20 +date: 2022-10-24 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 871f2b2db8c90..c7a0a3f208492 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 7f6630077abfb..7e55b4a50b8bc 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 7751c0035784d..7b035e960d034 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 9d46a6e8cad73..d98405a80a1f3 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-20 +date: 2022-10-24 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 4df40e4cbe930..abfae9f0b1448 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-20 +date: 2022-10-24 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 c3383e4c9411c..af5361b840a88 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-20 +date: 2022-10-24 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 ab57e8d242200..494f78c7ba1ec 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-20 +date: 2022-10-24 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 bf6152a48a54d..a412845fc364d 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-20 +date: 2022-10-24 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 56e03380cc56b..498efc5f0badb 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-20 +date: 2022-10-24 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 140e23a1266a2..8b2165ba52d51 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-20 +date: 2022-10-24 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 9716e8ba14c22..97177c2991ae6 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-20 +date: 2022-10-24 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 41337273a50cb..6cd919181f527 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-20 +date: 2022-10-24 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 80e87ef6dd32e..7f46959ddd8bd 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-20 +date: 2022-10-24 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 303ed560827a0..85d34487dfcf3 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-20 +date: 2022-10-24 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 4ac3160e4658d..609878f69f13e 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-20 +date: 2022-10-24 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 1d4b83c8060ce..b69b8e2f46adc 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-20 +date: 2022-10-24 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 1955749c7826b..2d5c809a76062 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-20 +date: 2022-10-24 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 22db67bddcaaf..22e90a866b8d6 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-20 +date: 2022-10-24 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 86d9ac7012e3f..7b33923cba1f4 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-20 +date: 2022-10-24 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 f52d68ffcc71b..a4bb29372dccf 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-20 +date: 2022-10-24 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 39cef6b5fc57c..67efdf573d730 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-20 +date: 2022-10-24 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 de815ae124749..7d3c32e43ea32 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-20 +date: 2022-10-24 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 282ec7408052e..00ea90576060f 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-20 +date: 2022-10-24 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 1474210b24c62..43cee35fc7313 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-20 +date: 2022-10-24 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 a62444bf18004..3246012749267 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-20 +date: 2022-10-24 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 179cee9710ef0..6991100e3b12f 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-20 +date: 2022-10-24 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 ee94a7b74aeeb..70a6c8cb661a2 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-20 +date: 2022-10-24 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 f5e7c916d598e..6ce6953b106c4 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-20 +date: 2022-10-24 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 1925b8b7a32e3..9f40e4d8642c2 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-20 +date: 2022-10-24 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 0ffd939d8e58c..6ee56c4ff243d 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-20 +date: 2022-10-24 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 6fa35ce2197fd..75b8a266c803d 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-20 +date: 2022-10-24 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 a6225ec43a674..3083ac4bc3226 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-20 +date: 2022-10-24 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 2d8c1e2886c83..13c66eb509d62 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-20 +date: 2022-10-24 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 16ccbcffa0c9f..28b2571ba23c5 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-20 +date: 2022-10-24 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 dbbc180ea9c08..5cbf90e820b10 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-20 +date: 2022-10-24 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 8d5b317a6c907..a8fade48b8415 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-20 +date: 2022-10-24 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 e82ba2edca4cf..0f52c22ab829b 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-20 +date: 2022-10-24 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 2f6004c4b1522..16bad577d4514 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-20 +date: 2022-10-24 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 675596c2bdc0f..357df78b62e96 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-20 +date: 2022-10-24 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 c57a38112b054..e7d63df0603b5 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-20 +date: 2022-10-24 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 897e00022340e..78d10c2515e80 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-20 +date: 2022-10-24 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 d11c349b2fb98..accfaf018d1c0 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-20 +date: 2022-10-24 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 c65cd7f816cd9..69313aba986c5 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-20 +date: 2022-10-24 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 e2fc560c16162..e71b065f059fb 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-20 +date: 2022-10-24 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 aada5cc7d17b7..ef0a436c7bf40 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-20 +date: 2022-10-24 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 925c8aa757080..ad50cb53ca5b7 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-20 +date: 2022-10-24 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 26fdfff440799..ff546645373a1 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-20 +date: 2022-10-24 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 d01b35439e310..9d53a2f0f678a 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-20 +date: 2022-10-24 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 cb12b4b4ec9f5..dfc13d67cd0d2 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-20 +date: 2022-10-24 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 816569aae53f0..b7efb422b19e6 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-20 +date: 2022-10-24 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 cafcc24b0d5ab..1fab2bde1e822 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-20 +date: 2022-10-24 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 85d65d1002f19..80d57bde057b7 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-20 +date: 2022-10-24 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 1b8aa0bc07226..a6d1ba795bd47 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-20 +date: 2022-10-24 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 6273e86b4f1b7..dc8f0ba906689 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-20 +date: 2022-10-24 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 498ada3897f18..6eb1a4a9dc5d4 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-20 +date: 2022-10-24 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 7c738714a4cc9..c8ab8b7f6be4f 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-20 +date: 2022-10-24 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 f3542cf74b5d3..47e25541320cf 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-20 +date: 2022-10-24 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 d2decc779ebe7..a8ecbdd425e55 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-20 +date: 2022-10-24 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 0740af861e6e2..2677b9e80acdf 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-20 +date: 2022-10-24 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 d8453576b74d8..11f663a022cb7 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-20 +date: 2022-10-24 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 b0c4620ca6010..e44638edb5126 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-20 +date: 2022-10-24 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 83e3b64a75521..6462cd09322aa 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 708db749853df..1eb5b5b3bf28c 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-20 +date: 2022-10-24 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 638ae8b0b503b..3adfdd91e151d 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-20 +date: 2022-10-24 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 afbf090e71206..2d39c4b7516e4 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-20 +date: 2022-10-24 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 8a47a6888f9df..20c83d460c62e 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index a8746ba91e913..ef16305a02e17 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-20 +date: 2022-10-24 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 20883bc3e1da9..a6fd852fdd874 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-20 +date: 2022-10-24 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 fcfa7e1b1d21b..c1da6184b64e2 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-20 +date: 2022-10-24 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 e5e3b97593b55..4a46bfd5f475f 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-20 +date: 2022-10-24 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 4b4cec9beebaa..b389d448179d2 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-20 +date: 2022-10-24 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 1358da9170942..2c64c1c5b973a 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -7780,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; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: \"occurrences\"; objective: { target: number; }; summary: { sli_value: number; error_budget: { initial: number; consumed: number; remaining: number; }; }; revision: number; created_at: string; updated_at: string; }, ", + ", { 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", @@ -7903,12 +7903,26 @@ "<{ 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", @@ -7916,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; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: \"occurrences\"; objective: { target: number; }; created_at: string; updated_at: string; }, ", + ", { 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", @@ -8035,12 +8049,26 @@ "<{ 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", @@ -8158,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; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: \"occurrences\"; objective: { target: number; }; summary: { sli_value: number; error_budget: { initial: number; consumed: number; remaining: number; }; }; revision: number; created_at: string; updated_at: string; }, ", + ", { 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", @@ -8281,12 +8309,26 @@ "<{ 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", @@ -8294,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; } | { duration: string; calendar: { start_time: string; }; }; budgeting_method: \"occurrences\"; objective: { target: number; }; created_at: string; updated_at: string; }, ", + ", { 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", @@ -8413,12 +8455,26 @@ "<{ 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", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 01ffb938b6418..a8d5cf35b064f 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 609be776bb796..69bd76b53f831 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-20 +date: 2022-10-24 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 db802862e289f..b014b1dc15c74 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-20 +date: 2022-10-24 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 | |--------------|----------|------------------------| -| 496 | 411 | 38 | +| 497 | 412 | 38 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 32608 | 179 | 21917 | 1032 | +| 32648 | 179 | 21947 | 1032 | ## Plugin Directory @@ -46,16 +46,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [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 | 229 | 0 | 220 | 7 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2693 | 0 | 23 | 0 | +| | [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 | @@ -91,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 | @@ -313,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 | @@ -322,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 | @@ -373,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 | @@ -384,7 +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] | - | 5 | 0 | 4 | 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 | @@ -406,7 +407,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | security solution elastic search utilities to use across plugins such lists, security_solution, cases, etc... | 67 | 0 | 61 | 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 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 5b8b880834a50..ec403b1daecf6 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-20 +date: 2022-10-24 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 71bfc40d13c6d..17af4446a2e46 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-20 +date: 2022-10-24 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 091c3c5273a98..6e2b08c70c7f8 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-20 +date: 2022-10-24 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 201e3e126917d..8b7d2c692aded 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-20 +date: 2022-10-24 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 5b7d8209a2b21..8099d161fb9fc 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index d05ef1264b7cd..7285f5e3f37fb 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-20 +date: 2022-10-24 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 05185c5d28fff..e2b01e3ff98db 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-20 +date: 2022-10-24 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 9b737c4798aeb..ffbcd2429fee1 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-20 +date: 2022-10-24 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 41ca713edf881..cb95769f0c880 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-20 +date: 2022-10-24 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 2e072a64eabff..1523f5943e69f 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-20 +date: 2022-10-24 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 f28f79ea92de6..ca5ea5e6fe0f0 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-20 +date: 2022-10-24 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 c0359745698d3..e588e9d2a45fa 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-20 +date: 2022-10-24 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 0c004f91d99f2..25191348ad1f8 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-20 +date: 2022-10-24 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 15f2ee1360887..d45a93a68f93c 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-20 +date: 2022-10-24 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 6f067a7c98157..c939b836664f6 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-20 +date: 2022-10-24 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 6d6efd0ecc1a5..331e2d40aeb93 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -2584,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" @@ -2600,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 2e24aa109b279..a827163faefe5 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 57eb1dd7bd5b7..f5a333450aad9 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-20 +date: 2022-10-24 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 76bd26074e5da..ef0b19ab974bf 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-20 +date: 2022-10-24 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 bffe945bf2c57..5d1f53461f8e1 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-20 +date: 2022-10-24 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 8165049a46396..14a1a8765afe7 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-20 +date: 2022-10-24 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 aca9d5bd01a8a..71e5ef0c3a701 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-20 +date: 2022-10-24 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 da477d71d6fa1..91794b1053525 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-20 +date: 2022-10-24 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 b41b4f0efde63..8c77a979c5555 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-20 +date: 2022-10-24 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 c32aa226c432e..f7caa6c81573a 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-20 +date: 2022-10-24 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 85a430b935469..888496756b7e2 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index e78d7ab4bfa69..2919da0fd203d 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-20 +date: 2022-10-24 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 b6cf490064ce9..91d9a7f891af6 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-20 +date: 2022-10-24 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 9759255750d43..426f52ed290f5 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-20 +date: 2022-10-24 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 6f665ce6ee569..882f15401cf99 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-20 +date: 2022-10-24 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 23859b9ee23aa..5d590998cb26b 100644 --- a/api_docs/timelines.devdocs.json +++ b/api_docs/timelines.devdocs.json @@ -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", diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 6b447d178739e..32e922a0c81cd 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-20 +date: 2022-10-24 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 f794633f1997d..0bf13c135fd9d 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-20 +date: 2022-10-24 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 825ac42f72426..08ead4109c082 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-20 +date: 2022-10-24 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 d4ded7aed8b67..8f82f4e464e1f 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-20 +date: 2022-10-24 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 fd2a3664fc5d1..aed9c6a8e4a0e 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-20 +date: 2022-10-24 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 937c4b59659eb..e5a947d81959e 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-20 +date: 2022-10-24 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 0e09d95e86fd7..101fb511048e3 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 269e37770a6ca..c6e706fff43f3 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 7b7785b8c5498..37d3fcb4df7b5 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 1f61340ddd192..a7a3bdcce7cbc 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-20 +date: 2022-10-24 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 0d2bd5167d822..3bd37737fe77b 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-20 +date: 2022-10-24 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 e398f431a47b3..0717eea02ad33 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-20 +date: 2022-10-24 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 6900b279dcbd2..55278b5401d83 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-20 +date: 2022-10-24 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 9d8cb0d2fa124..c2c6d6d601fc1 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-20 +date: 2022-10-24 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 7783f96a0b550..afba3a7c2c0aa 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-20 +date: 2022-10-24 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 6afbff496daa5..ad0cff7deeace 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-20 +date: 2022-10-24 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 96cd26d718932..0e56fe19cc73a 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-20 +date: 2022-10-24 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 9bc4580049e58..4677afb2acd27 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-20 +date: 2022-10-24 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 656d5801c4051..596c74e5f39d2 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-20 +date: 2022-10-24 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 e638fae2c0efd..dcc99abbcba4c 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-20 +date: 2022-10-24 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 72bb6b5272221..a4a18274d6b06 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-20 +date: 2022-10-24 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 1ad8363497f3e..c15d6fe4437d6 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-20 +date: 2022-10-24 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 82b067ad5ea8a..1a3a83aa5a71b 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-20 +date: 2022-10-24 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/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 69316af1593a1..c32d305b22d9a 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -386,6 +386,11 @@ Specifies an array of trusted hostnames, such as the {kib} host, or a reverse proxy sitting in front of it. This determines whether HTTP compression may be used for responses, based on the request `Referer` header. This setting may not be used when <> is set to `false`. *Default: `none`* +`server.compression.brotli.enabled`:: +Set to `true` to enable brotli (br) compression format. +Note: browsers not supporting brotli compression will fallback to using gzip instead. +This setting may not be used when <> is set to `false`. *Default: `false`* + [[server-securityResponseHeaders-strictTransportSecurity]] `server.securityResponseHeaders.strictTransportSecurity`:: Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security[`Strict-Transport-Security`] header is used in all responses to the client from the {kib} server, and specifies what value is used. Allowed values are any text value or diff --git a/package.json b/package.json index fbab0181a7f8e..8a71f04064b8a 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,6 @@ "@hapi/inert": "^6.0.4", "@hapi/wreck": "^17.1.0", "@kbn/ace": "link:bazel-bin/packages/kbn-ace", - "@kbn/adhoc-profiler": "link:bazel-bin/packages/kbn-adhoc-profiler", "@kbn/aiops-components": "link:bazel-bin/x-pack/packages/ml/aiops_components", "@kbn/aiops-utils": "link:bazel-bin/x-pack/packages/ml/aiops_utils", "@kbn/alerts": "link:bazel-bin/packages/kbn-alerts", @@ -456,6 +455,7 @@ "bitmap-sdf": "^1.0.3", "blurhash": "^2.0.1", "brace": "0.11.1", + "brok": "^5.0.2", "byte-size": "^8.1.0", "canvg": "^3.0.9", "cbor-x": "^1.3.3", @@ -575,7 +575,6 @@ "peggy": "^1.2.0", "pluralize": "3.1.0", "polished": "^3.7.2", - "pprof": "^3.2.0", "pretty-ms": "6.0.0", "prop-types": "^15.8.1", "proxy-from-env": "1.0.0", @@ -860,7 +859,6 @@ "@types/json5": "^0.0.30", "@types/jsonwebtoken": "^8.5.6", "@types/kbn__ace": "link:bazel-bin/packages/kbn-ace/npm_module_types", - "@types/kbn__adhoc-profiler": "link:bazel-bin/packages/kbn-adhoc-profiler/npm_module_types", "@types/kbn__aiops-components": "link:bazel-bin/x-pack/packages/ml/aiops_components/npm_module_types", "@types/kbn__aiops-utils": "link:bazel-bin/x-pack/packages/ml/aiops_utils/npm_module_types", "@types/kbn__alerts": "link:bazel-bin/packages/kbn-alerts/npm_module_types", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index 95c72f1cd9b9f..b68c27b27f3dd 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -181,7 +181,6 @@ filegroup( "//packages/home/sample_data_tab:build", "//packages/home/sample_data_types:build", "//packages/kbn-ace:build", - "//packages/kbn-adhoc-profiler:build", "//packages/kbn-alerts:build", "//packages/kbn-ambient-storybook-types:build", "//packages/kbn-ambient-ui-types:build", @@ -530,7 +529,6 @@ filegroup( "//packages/home/sample_data_card:build_types", "//packages/home/sample_data_tab:build_types", "//packages/kbn-ace:build_types", - "//packages/kbn-adhoc-profiler:build_types", "//packages/kbn-alerts:build_types", "//packages/kbn-analytics:build_types", "//packages/kbn-apm-config-loader:build_types", diff --git a/packages/analytics/shippers/README.md b/packages/analytics/shippers/README.md index 5ab85d08ff2ca..109bdd64700ab 100644 --- a/packages/analytics/shippers/README.md +++ b/packages/analytics/shippers/README.md @@ -3,5 +3,6 @@ This directory holds the implementation of the _built-in_ shippers provided by the Analytics client. At the moment, the shippers are: * [FullStory](./fullstory/README.md) +* [Gainsight](./gainsight/README.md) * [Elastic V3 (Browser shipper)](./elastic_v3/browser/README.md) * [Elastic V3 (Server-side shipper)](./elastic_v3/server/README.md) diff --git a/packages/analytics/shippers/gainsight/README.md b/packages/analytics/shippers/gainsight/README.md index 64899c52b554f..3baed8dcdf479 100644 --- a/packages/analytics/shippers/gainsight/README.md +++ b/packages/analytics/shippers/gainsight/README.md @@ -1,6 +1,6 @@ # @kbn/analytics-shippers-gainsight -gainsight implementation as a shipper for the `@kbn/analytics-client`. +Gainsight implementation as a shipper for the `@kbn/analytics-client`. ## How to use it diff --git a/packages/core/http/core-http-server-internal/BUILD.bazel b/packages/core/http/core-http-server-internal/BUILD.bazel index ab10546a3ddcc..214bb5833b7a9 100644 --- a/packages/core/http/core-http-server-internal/BUILD.bazel +++ b/packages/core/http/core-http-server-internal/BUILD.bazel @@ -44,6 +44,7 @@ RUNTIME_DEPS = [ "@npm//@hapi/cookie", "@npm//@hapi/inert", "@npm//elastic-apm-node", + "@npm//brok", "//packages/kbn-utils", "//packages/kbn-std", "//packages/kbn-config-schema", @@ -68,6 +69,7 @@ TYPES_DEPS = [ "@npm//moment", "@npm//@elastic/numeral", "@npm//lodash", + "@npm//brok", "@npm//@hapi/hapi", "@npm//@hapi/boom", "@npm//@hapi/cookie", diff --git a/packages/core/http/core-http-server-internal/src/__snapshots__/http_config.test.ts.snap b/packages/core/http/core-http-server-internal/src/__snapshots__/http_config.test.ts.snap index 65ac08f6ce5f7..bb81f7b3bc924 100644 --- a/packages/core/http/core-http-server-internal/src/__snapshots__/http_config.test.ts.snap +++ b/packages/core/http/core-http-server-internal/src/__snapshots__/http_config.test.ts.snap @@ -42,6 +42,10 @@ exports[`has defaults for config 1`] = ` Object { "autoListen": true, "compression": Object { + "brotli": Object { + "enabled": false, + "quality": 3, + }, "enabled": true, }, "cors": Object { diff --git a/packages/core/http/core-http-server-internal/src/http_config.test.ts b/packages/core/http/core-http-server-internal/src/http_config.test.ts index 26a42f27a794b..ec9fc41ed02fd 100644 --- a/packages/core/http/core-http-server-internal/src/http_config.test.ts +++ b/packages/core/http/core-http-server-internal/src/http_config.test.ts @@ -390,6 +390,33 @@ describe('with compression', () => { }); }); +describe('compression.brotli', () => { + describe('enabled', () => { + it('defaults to `false`', () => { + expect(config.schema.validate({}).compression.brotli.enabled).toEqual(false); + }); + }); + describe('quality', () => { + it('defaults to `3`', () => { + expect(config.schema.validate({}).compression.brotli.quality).toEqual(3); + }); + it('does not accepts value superior to `11`', () => { + expect(() => + config.schema.validate({ compression: { brotli: { quality: 12 } } }) + ).toThrowErrorMatchingInlineSnapshot( + `"[compression.brotli.quality]: Value must be equal to or lower than [11]."` + ); + }); + it('does not accepts value inferior to `0`', () => { + expect(() => + config.schema.validate({ compression: { brotli: { quality: -1 } } }) + ).toThrowErrorMatchingInlineSnapshot( + `"[compression.brotli.quality]: Value must be equal to or greater than [0]."` + ); + }); + }); +}); + describe('cors', () => { describe('allowOrigin', () => { it('list cannot be empty', () => { diff --git a/packages/core/http/core-http-server-internal/src/http_config.ts b/packages/core/http/core-http-server-internal/src/http_config.ts index 9cb636156c5e8..1fae2568edffd 100644 --- a/packages/core/http/core-http-server-internal/src/http_config.ts +++ b/packages/core/http/core-http-server-internal/src/http_config.ts @@ -112,6 +112,10 @@ const configSchema = schema.object( }), compression: schema.object({ enabled: schema.boolean({ defaultValue: true }), + brotli: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + quality: schema.number({ defaultValue: 3, min: 0, max: 11 }), + }), referrerWhitelist: schema.maybe( schema.arrayOf( schema.string({ @@ -209,7 +213,11 @@ export class HttpConfig implements IHttpConfig { public publicBaseUrl?: string; public rewriteBasePath: boolean; public ssl: SslConfig; - public compression: { enabled: boolean; referrerWhitelist?: string[] }; + public compression: { + enabled: boolean; + referrerWhitelist?: string[]; + brotli: { enabled: boolean; quality: number }; + }; public csp: ICspConfig; public externalUrl: IExternalUrlConfig; public xsrf: { disableProtection: boolean; allowlist: string[] }; diff --git a/packages/core/http/core-http-server-internal/src/http_server.test.ts b/packages/core/http/core-http-server-internal/src/http_server.test.ts index 82debfa44c2cb..92fa63c502558 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.test.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.test.ts @@ -60,7 +60,7 @@ beforeEach(() => { maxPayload: new ByteSizeValue(1024), port: 10002, ssl: { enabled: false }, - compression: { enabled: true }, + compression: { enabled: true, brotli: { enabled: false, quality: 3 } }, requestId: { allowFromAnyIp: true, ipAllowlist: [], @@ -865,7 +865,7 @@ describe('conditional compression', () => { test('with `compression.enabled: false`', async () => { const listener = await setupServer({ ...config, - compression: { enabled: false }, + compression: { enabled: false, brotli: { enabled: false, quality: 3 } }, }); const response = await supertest(listener).get('/').set('accept-encoding', 'gzip'); @@ -873,12 +873,38 @@ describe('conditional compression', () => { expect(response.header).not.toHaveProperty('content-encoding'); }); + test('with `compression.brotli.enabled: false`', async () => { + const listener = await setupServer({ + ...config, + compression: { enabled: true, brotli: { enabled: false, quality: 3 } }, + }); + + const response = await supertest(listener).get('/').set('accept-encoding', 'br'); + + expect(response.header).not.toHaveProperty('content-encoding', 'br'); + }); + + test('with `compression.brotli.enabled: true`', async () => { + const listener = await setupServer({ + ...config, + compression: { enabled: true, brotli: { enabled: true, quality: 3 } }, + }); + + const response = await supertest(listener).get('/').set('accept-encoding', 'br'); + + expect(response.header).toHaveProperty('content-encoding', 'br'); + }); + describe('with defined `compression.referrerWhitelist`', () => { let listener: Server; beforeEach(async () => { listener = await setupServer({ ...config, - compression: { enabled: true, referrerWhitelist: ['foo'] }, + compression: { + enabled: true, + referrerWhitelist: ['foo'], + brotli: { enabled: false, quality: 3 }, + }, }); }); diff --git a/packages/core/http/core-http-server-internal/src/http_server.ts b/packages/core/http/core-http-server-internal/src/http_server.ts index 766fa131349e1..4e4bf17d7a17a 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.ts @@ -21,6 +21,8 @@ import type { Duration } from 'moment'; import { firstValueFrom, Observable } from 'rxjs'; import { take } from 'rxjs/operators'; import apm from 'elastic-apm-node'; +// @ts-expect-error no type definition +import Brok from 'brok'; import type { Logger, LoggerFactory } from '@kbn/logging'; import type { InternalExecutionContextSetup } from '@kbn/core-execution-context-server-internal'; import { isSafeMethod } from '@kbn/core-http-router-server-internal'; @@ -147,9 +149,17 @@ export class HttpServer { ): Promise { const serverOptions = getServerOptions(config); const listenerOptions = getListenerOptions(config); + this.config = config; this.server = createServer(serverOptions, listenerOptions); await this.server.register([HapiStaticFiles]); - this.config = config; + if (config.compression.brotli.enabled) { + await this.server.register({ + plugin: Brok, + options: { + compress: { quality: config.compression.brotli.quality }, + }, + }); + } // It's important to have setupRequestStateAssignment call the very first, otherwise context passing will be broken. // That's the only reason why context initialization exists in this method. diff --git a/packages/core/http/core-http-server-mocks/src/test_utils.ts b/packages/core/http/core-http-server-mocks/src/test_utils.ts index 2b9658693dce7..bb260ae23c908 100644 --- a/packages/core/http/core-http-server-mocks/src/test_utils.ts +++ b/packages/core/http/core-http-server-mocks/src/test_utils.ts @@ -35,7 +35,7 @@ const createConfigService = () => { cors: { enabled: false, }, - compression: { enabled: true }, + compression: { enabled: true, brotli: { enabled: false } }, xsrf: { disableProtection: true, allowlist: [], diff --git a/packages/kbn-adhoc-profiler/BUILD.bazel b/packages/kbn-adhoc-profiler/BUILD.bazel deleted file mode 100644 index d3ecbb56e657f..0000000000000 --- a/packages/kbn-adhoc-profiler/BUILD.bazel +++ /dev/null @@ -1,128 +0,0 @@ -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-adhoc-profiler" -PKG_REQUIRE_NAME = "@kbn/adhoc-profiler" - -SOURCE_FILES = glob( - [ - "**/*.ts", - ], - 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//pprof", - "@npm//execa" -] - -# 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//pprof", - "@npm//execa" -] - -jsts_transpiler( - name = "target_node", - srcs = SRCS, - build_pkg_name = package_name(), -) - -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"], - 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-adhoc-profiler/README.md b/packages/kbn-adhoc-profiler/README.md deleted file mode 100644 index 688102937385c..0000000000000 --- a/packages/kbn-adhoc-profiler/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @kbn/adhoc-profiler - -This package offers tools for ad hoc profiling. Currently it only exports one method: `inspectCpuProfile`, which will start a CPU profile before executing the callback it is given, and opens the collected profile in a web browser. It assumes that you have `go` and [`pprof`](https://github.com/google/pprof) installed. - -Profiles are stored in the user's temporary directory (returned from `os.tmpdir()`). diff --git a/packages/kbn-adhoc-profiler/index.ts b/packages/kbn-adhoc-profiler/index.ts deleted file mode 100644 index 5aa7c8e9526e4..0000000000000 --- a/packages/kbn-adhoc-profiler/index.ts +++ /dev/null @@ -1,9 +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. - */ - -export { inspectCpuProfile } from './inspect_cpu_profile'; diff --git a/packages/kbn-adhoc-profiler/inspect_cpu_profile.ts b/packages/kbn-adhoc-profiler/inspect_cpu_profile.ts deleted file mode 100644 index e48c6989d0d00..0000000000000 --- a/packages/kbn-adhoc-profiler/inspect_cpu_profile.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 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 Fs from 'fs'; -import Os from 'os'; -import Path from 'path'; - -import execa from 'execa'; - -import { pprof } from './require_pprof'; -import { withCpuProfile } from './with_cpu_profile'; - -export function inspectCpuProfile(callback: () => T): T; - -export function inspectCpuProfile(callback: () => any) { - return withCpuProfile(callback, (profile) => { - pprof.encode(profile).then((buffer) => { - const filename = Path.join(Os.tmpdir(), Date.now() + '.pb.gz'); - Fs.writeFile(filename, buffer, (err) => { - execa('pprof', ['-web', filename]); - }); - }); - }); -} diff --git a/packages/kbn-adhoc-profiler/jest.config.js b/packages/kbn-adhoc-profiler/jest.config.js deleted file mode 100644 index ec035df5193fd..0000000000000 --- a/packages/kbn-adhoc-profiler/jest.config.js +++ /dev/null @@ -1,13 +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. - */ - -module.exports = { - preset: '@kbn/test/jest_node', - rootDir: '../..', - roots: ['/packages/kbn-adhoc-profiler'], -}; diff --git a/packages/kbn-adhoc-profiler/kibana.jsonc b/packages/kbn-adhoc-profiler/kibana.jsonc deleted file mode 100644 index bae020a4b1e8d..0000000000000 --- a/packages/kbn-adhoc-profiler/kibana.jsonc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/adhoc-profiler", - "owner": "@elastic/apm-ui", - "runtimeDeps": [], - "typeDeps": [], -} diff --git a/packages/kbn-adhoc-profiler/package.json b/packages/kbn-adhoc-profiler/package.json deleted file mode 100644 index aeee4a9d1d37b..0000000000000 --- a/packages/kbn-adhoc-profiler/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/adhoc-profiler", - "private": true, - "version": "1.0.0", - "main": "./target_node/index.js", - "license": "SSPL-1.0 OR Elastic License 2.0" -} diff --git a/packages/kbn-adhoc-profiler/tsconfig.json b/packages/kbn-adhoc-profiler/tsconfig.json deleted file mode 100644 index bf5ec76a5e1fb..0000000000000 --- a/packages/kbn-adhoc-profiler/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "../../tsconfig.bazel.json", - "compilerOptions": { - "declaration": true, - "declarationMap": true, - "emitDeclarationOnly": true, - "outDir": "target_types", - "stripInternal": false, - "types": [ - "jest", - "node", - "long" - ] - }, - "include": [ - "**/*.ts", - ] -} diff --git a/packages/kbn-adhoc-profiler/types.ts b/packages/kbn-adhoc-profiler/types.ts deleted file mode 100644 index 76ef307b75de4..0000000000000 --- a/packages/kbn-adhoc-profiler/types.ts +++ /dev/null @@ -1,13 +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 type pprofRuntime from 'pprof'; - -type PProf = typeof pprofRuntime; -type Profile = ReturnType>; - -export type { PProf, Profile }; diff --git a/packages/kbn-adhoc-profiler/with_cpu_profile.ts b/packages/kbn-adhoc-profiler/with_cpu_profile.ts deleted file mode 100644 index 25833f8cb4805..0000000000000 --- a/packages/kbn-adhoc-profiler/with_cpu_profile.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 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 { isPromise } from 'util/types'; -import { pprof } from './require_pprof'; -import { Profile } from './types'; - -export function withCpuProfile(callback: () => T, onProfileDone: (profile: Profile) => void): T; - -export function withCpuProfile(callback: () => any, onProfileDone: (profile: Profile) => void) { - const stop = pprof.time.start(); - - const result = callback(); - - function collectProfile() { - const profile = stop(); - onProfileDone(profile); - } - - if (isPromise(result)) { - result.finally(() => { - collectProfile(); - }); - } else { - collectProfile(); - } - return result; -} 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-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/src/core/server/integration_tests/http/cookie_session_storage.test.ts b/src/core/server/integration_tests/http/cookie_session_storage.test.ts index 713ed2dc9edfd..1041ed66872dd 100644 --- a/src/core/server/integration_tests/http/cookie_session_storage.test.ts +++ b/src/core/server/integration_tests/http/cookie_session_storage.test.ts @@ -53,7 +53,7 @@ configService.atPath.mockImplementation((path) => { ssl: { verificationMode: 'none', }, - compression: { enabled: true }, + compression: { enabled: true, brotli: { enabled: false } }, xsrf: { disableProtection: true, allowlist: [], diff --git a/src/core/server/integration_tests/http/http_server.test.ts b/src/core/server/integration_tests/http/http_server.test.ts index 1b9da1f0fddde..313421fa05eca 100644 --- a/src/core/server/integration_tests/http/http_server.test.ts +++ b/src/core/server/integration_tests/http/http_server.test.ts @@ -31,7 +31,7 @@ describe('Http server', () => { maxPayload: new ByteSizeValue(1024), port: 10002, ssl: { enabled: false }, - compression: { enabled: true }, + compression: { enabled: true, brotli: { enabled: false } }, requestId: { allowFromAnyIp: true, ipAllowlist: [], diff --git a/src/core/server/integration_tests/http/lifecycle_handlers.test.ts b/src/core/server/integration_tests/http/lifecycle_handlers.test.ts index 6e72afd4f4e58..26c17a17b41bb 100644 --- a/src/core/server/integration_tests/http/lifecycle_handlers.test.ts +++ b/src/core/server/integration_tests/http/lifecycle_handlers.test.ts @@ -52,7 +52,7 @@ describe('core lifecycle handlers', () => { cors: { enabled: false, }, - compression: { enabled: true }, + compression: { enabled: true, brotli: { enabled: false } }, name: kibanaName, securityResponseHeaders: { // reflects default config 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/component/control_frame_component.tsx b/src/plugins/controls/public/control_group/component/control_frame_component.tsx index 196b2cfe28be3..8f53e2e29c63e 100644 --- a/src/plugins/controls/public/control_group/component/control_frame_component.tsx +++ b/src/plugins/controls/public/control_group/component/control_frame_component.tsx @@ -13,12 +13,17 @@ import { EuiFormControlLayout, EuiFormLabel, EuiFormRow, + EuiIcon, + EuiLink, EuiLoadingChart, + EuiPopover, + EuiText, EuiToolTip, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { Markdown } from '@kbn/kibana-react-plugin/public'; import { useReduxContainerContext } from '@kbn/presentation-util-plugin/public'; -import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import { ControlGroupReduxState } from '../types'; import { pluginServices } from '../../services'; import { EditControlButton } from '../editor/edit_control'; @@ -26,6 +31,44 @@ import { ControlGroupStrings } from '../control_group_strings'; import { useChildEmbeddable } from '../../hooks/use_child_embeddable'; import { TIME_SLIDER_CONTROL } from '../../../common'; +interface ControlFrameErrorProps { + error: Error; +} + +const ControlFrameError = ({ error }: ControlFrameErrorProps) => { + const [isPopoverOpen, setPopoverOpen] = useState(false); + const popoverButton = ( + + setPopoverOpen((open) => !open)} + > + + + + + ); + + return ( + setPopoverOpen(false)} + > + + + ); +}; + export interface ControlFrameProps { customPrepend?: JSX.Element; enableActions?: boolean; @@ -40,7 +83,7 @@ export const ControlFrame = ({ embeddableType, }: ControlFrameProps) => { const embeddableRoot: React.RefObject = useMemo(() => React.createRef(), []); - const [hasFatalError, setHasFatalError] = useState(false); + const [fatalError, setFatalError] = useState(); const { useEmbeddableSelector: select, @@ -61,19 +104,14 @@ export const ControlFrame = ({ const usingTwoLineLayout = controlStyle === 'twoLine'; useEffect(() => { - if (embeddableRoot.current && embeddable) { - embeddable.render(embeddableRoot.current); + if (embeddableRoot.current) { + embeddable?.render(embeddableRoot.current); } const inputSubscription = embeddable ?.getInput$() .subscribe((newInput) => setTitle(newInput.title)); const errorSubscription = embeddable?.getOutput$().subscribe({ - error: (error: Error) => { - if (!embeddableRoot.current) return; - const errorEmbeddable = new ErrorEmbeddable(error, { id: embeddable.id }, undefined, true); - errorEmbeddable.render(embeddableRoot.current); - setHasFatalError(true); - }, + error: setFatalError, }); return () => { inputSubscription?.unsubscribe(); @@ -88,7 +126,7 @@ export const ControlFrame = ({ 'controlFrameFloatingActions--oneLine': !usingTwoLineLayout, })} > - {!hasFatalError && embeddableType !== TIME_SLIDER_CONTROL && ( + {!fatalError && embeddableType !== TIME_SLIDER_CONTROL && ( @@ -119,7 +157,7 @@ export const ControlFrame = ({ const embeddableParentClassNames = classNames('controlFrame__control', { 'controlFrame--twoLine': controlStyle === 'twoLine', 'controlFrame--oneLine': controlStyle === 'oneLine', - 'controlFrame--fatalError': hasFatalError, + 'controlFrame--fatalError': !!fatalError, }); function renderEmbeddablePrepend() { @@ -149,12 +187,19 @@ export const ControlFrame = ({ } > - {embeddable && ( + {embeddable && !fatalError && (
    + > + {fatalError && } +
    + )} + {fatalError && ( +
    + {} +
    )} {!embeddable && (
    diff --git a/src/plugins/embeddable/README.md b/src/plugins/embeddable/README.md index 14fab2f8412f3..eae9ef04cfb9b 100644 --- a/src/plugins/embeddable/README.md +++ b/src/plugins/embeddable/README.md @@ -90,7 +90,6 @@ export class HelloWorldEmbeddableFactoryDefinition implements EmbeddableFactoryD The embeddable should implement the `IEmbeddable` interface, and usually, that just extends the base class `Embeddable`. ```tsx import React from 'react'; -import { render } from 'react-dom'; import { Embeddable } from '@kbn/embeddable-plugin/public'; export const HELLO_WORLD = 'HELLO_WORLD'; @@ -98,8 +97,8 @@ export const HELLO_WORLD = 'HELLO_WORLD'; export class HelloWorld extends Embeddable { readonly type = HELLO_WORLD; - render(node: HTMLElement) { - render(
    {this.getTitle()}
    , node); + render() { + return
    {this.getTitle()}
    ; } reload() {} @@ -126,6 +125,21 @@ export class HelloWorld extends Embeddable { } ``` +There is also an option to return a [React node](https://reactjs.org/docs/react-component.html#render) directly. +In that case, the returned node will be automatically mounted and unmounted. +```tsx +import React from 'react'; +import { Embeddable } from '@kbn/embeddable-plugin/public'; + +export class HelloWorld extends Embeddable { + // ... + + render() { + return
    {this.getTitle()}
    ; + } +} +``` + #### `reload` This hook is called after every input update to perform some UI changes. ```typescript @@ -150,13 +164,13 @@ export class HelloWorld extends Embeddable { } ``` -#### `renderError` +#### `catchError` This is an optional error handler to provide a custom UI for the error state. The embeddable may change its state in the future so that the error should be able to disappear. In that case, the method should return a callback performing cleanup actions for the error UI. -If there is no implementation provided for the `renderError` hook, the embeddable will render a fallback error UI. +If there is no implementation provided for the `catchError` hook, the embeddable will render a fallback error UI. In case of an error, the embeddable UI will not be destroyed or unmounted. The default behavior is to hide that visually and show the error message on top of that. @@ -169,7 +183,7 @@ import { Embeddable } from '@kbn/embeddable-plugin/public'; export class HelloWorld extends Embeddable { // ... - renderError(node: HTMLElement, error: Error) { + catchError(error: Error, node: HTMLElement) { render(
    Something went wrong: {error.message}
    , node); return () => unmountComponentAtNode(node); @@ -177,6 +191,21 @@ export class HelloWorld extends Embeddable { } ``` +There is also an option to return a [React node](https://reactjs.org/docs/react-component.html#render) directly. +In that case, the returned node will be automatically mounted and unmounted. +```typescript +import React from 'react'; +import { Embeddable } from '@kbn/embeddable-plugin/public'; + +export class HelloWorld extends Embeddable { + // ... + + catchError(error: Error) { + return
    Something went wrong: {error.message}
    ; + } +} +``` + #### `destroy` This hook is invoked when the embeddable is destroyed and should perform cleanup actions. ```typescript @@ -366,7 +395,6 @@ To perform state mutations, the plugin also exposes a pre-defined state of the a Here is an example of initializing a Redux store: ```tsx import React from 'react'; -import { render } from 'react-dom'; import { connect, Provider } from 'react-redux'; import { Embeddable, IEmbeddable } from '@kbn/embeddable-plugin/public'; import { createStore, State } from '@kbn/embeddable-plugin/public/store'; @@ -381,16 +409,15 @@ export class HelloWorld extends Embeddable { reload() {} - render(node: HTMLElement) { + render() { const Component = connect((state: State) => ({ title: state.input.title }))( HelloWorldComponent ); - render( + return ( - , - node + ); } } @@ -434,7 +461,6 @@ That means there is no need to reimplement already existing actions. ```tsx import React from 'react'; -import { render } from 'react-dom'; import { createSlice } from '@reduxjs/toolkit'; import { Embeddable, @@ -523,7 +549,6 @@ This can be achieved by passing a custom reducer. ```tsx import React from 'react'; -import { render } from 'react-dom'; import { createSlice } from '@reduxjs/toolkit'; import { Embeddable, IEmbeddable } from '@kbn/embeddable-plugin/public'; import { createStore, State } from '@kbn/embeddable-plugin/public/store'; diff --git a/src/plugins/embeddable/public/__stories__/embeddable_panel.stories.tsx b/src/plugins/embeddable/public/__stories__/embeddable_panel.stories.tsx index 97e8b83b9f7b1..c7fba909068da 100644 --- a/src/plugins/embeddable/public/__stories__/embeddable_panel.stories.tsx +++ b/src/plugins/embeddable/public/__stories__/embeddable_panel.stories.tsx @@ -15,7 +15,6 @@ import React, { useMemo, useRef, } from 'react'; -import { render, unmountComponentAtNode } from 'react-dom'; import { ReplaySubject } from 'rxjs'; import { ThemeContext } from '@emotion/react'; import { DecoratorFn, Meta } from '@storybook/react'; @@ -251,15 +250,13 @@ DefaultWithError.argTypes = { export function DefaultWithCustomError({ message, ...props }: DefaultWithErrorProps) { const ref = useRef>(null); - useEffect( - () => - ref.current?.embeddable.setErrorRenderer((node, error) => { - render(, node); - - return () => unmountComponentAtNode(node); - }), - [] - ); + useEffect(() => { + if (ref.current) { + ref.current.embeddable.catchError = (error) => { + return ; + }; + } + }, []); useEffect( () => void ref.current?.embeddable.store.dispatch(actions.output.setError(new Error(message))), [message] diff --git a/src/plugins/embeddable/public/__stories__/embeddable_root.stories.tsx b/src/plugins/embeddable/public/__stories__/embeddable_root.stories.tsx index e8ccc0edd66a2..2539185022f3f 100644 --- a/src/plugins/embeddable/public/__stories__/embeddable_root.stories.tsx +++ b/src/plugins/embeddable/public/__stories__/embeddable_root.stories.tsx @@ -65,7 +65,7 @@ Default.args = { loading: false, }; -export const DefaultWithError = Default as Meta; +export const DefaultWithError = Default.bind({}) as Meta; DefaultWithError.args = { ...Default.args, diff --git a/src/plugins/embeddable/public/__stories__/error_embeddable.stories.tsx b/src/plugins/embeddable/public/__stories__/error_embeddable.stories.tsx index ad65b2412c4c4..2d83d9b8ed702 100644 --- a/src/plugins/embeddable/public/__stories__/error_embeddable.stories.tsx +++ b/src/plugins/embeddable/public/__stories__/error_embeddable.stories.tsx @@ -6,14 +6,10 @@ * Side Public License, v 1. */ -import React, { useContext, useEffect, useMemo, useRef } from 'react'; -import { filter, ReplaySubject } from 'rxjs'; -import { ThemeContext } from '@emotion/react'; +import { useEffect, useMemo } from 'react'; import { Meta } from '@storybook/react'; -import { CoreTheme } from '@kbn/core-theme-browser'; import { ErrorEmbeddable } from '..'; -import { setTheme } from '../services'; export default { title: 'components/ErrorEmbeddable', @@ -26,32 +22,17 @@ export default { } as Meta; interface ErrorEmbeddableWrapperProps { - compact?: boolean; message: string; } -function ErrorEmbeddableWrapper({ compact, message }: ErrorEmbeddableWrapperProps) { +function ErrorEmbeddableWrapper({ message }: ErrorEmbeddableWrapperProps) { const embeddable = useMemo( - () => new ErrorEmbeddable(message, { id: `${Math.random()}` }, undefined, compact), - [compact, message] + () => new ErrorEmbeddable(message, { id: `${Math.random()}` }, undefined), + [message] ); - const root = useRef(null); - const theme$ = useMemo(() => new ReplaySubject(1), []); - const theme = useContext(ThemeContext) as CoreTheme; + useEffect(() => () => embeddable.destroy(), [embeddable]); - useEffect(() => setTheme({ theme$: theme$.pipe(filter(Boolean)) }), [theme$]); - useEffect(() => theme$.next(theme), [theme$, theme]); - useEffect(() => { - if (!root.current) { - return; - } - - embeddable.render(root.current); - - return () => embeddable.destroy(); - }, [embeddable]); - - return
    ; + return embeddable.render(); } export const Default = ErrorEmbeddableWrapper as Meta; @@ -59,9 +40,3 @@ export const Default = ErrorEmbeddableWrapper as Meta ( - -)) as Meta; - -DefaultCompact.args = { ...Default.args }; diff --git a/src/plugins/embeddable/public/__stories__/hello_world_embeddable.tsx b/src/plugins/embeddable/public/__stories__/hello_world_embeddable.tsx index 5cf2c5fdc46e8..d343425bced3e 100644 --- a/src/plugins/embeddable/public/__stories__/hello_world_embeddable.tsx +++ b/src/plugins/embeddable/public/__stories__/hello_world_embeddable.tsx @@ -7,10 +7,9 @@ */ import React from 'react'; -import { render } from 'react-dom'; import { connect, Provider } from 'react-redux'; import { EuiEmptyPrompt } from '@elastic/eui'; -import { Embeddable, IEmbeddable } from '..'; +import { Embeddable } from '..'; import { createStore, State } from '../store'; export class HelloWorldEmbeddable extends Embeddable { @@ -19,22 +18,15 @@ export class HelloWorldEmbeddable extends Embeddable { readonly type = 'hello-world'; - renderError: IEmbeddable['renderError']; - reload() {} - render(node: HTMLElement) { - const App = connect((state: State) => ({ body: state.input.title }))(EuiEmptyPrompt); + render() { + const HelloWorld = connect((state: State) => ({ body: state.input.title }))(EuiEmptyPrompt); - render( + return ( - - , - node + + ); } - - setErrorRenderer(renderer: IEmbeddable['renderError']) { - this.renderError = renderer; - } } diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx index 94025320ec86d..d1871ce2ffc98 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx @@ -14,7 +14,7 @@ import { debounceTime, distinctUntilChanged, map, skip } from 'rxjs/operators'; import { RenderCompleteDispatcher } from '@kbn/kibana-utils-plugin/public'; import { Adapters } from '../types'; import { IContainer } from '../containers'; -import { EmbeddableOutput, IEmbeddable } from './i_embeddable'; +import { EmbeddableError, EmbeddableOutput, IEmbeddable } from './i_embeddable'; import { EmbeddableInput, ViewMode } from '../../../common/types'; import { genericEmbeddableInputIsEqual, omitGenericEmbeddableInput } from './diff_embeddable_input'; @@ -23,8 +23,9 @@ function getPanelTitle(input: EmbeddableInput, output: EmbeddableOutput) { } export abstract class Embeddable< TEmbeddableInput extends EmbeddableInput = EmbeddableInput, - TEmbeddableOutput extends EmbeddableOutput = EmbeddableOutput -> implements IEmbeddable + TEmbeddableOutput extends EmbeddableOutput = EmbeddableOutput, + TNode = any +> implements IEmbeddable { static runtimeId: number = 0; @@ -33,6 +34,7 @@ export abstract class Embeddable< public readonly parent?: IContainer; public readonly isContainer: boolean = false; public readonly deferEmbeddableLoad: boolean = false; + public catchError?(error: EmbeddableError, domNode: HTMLElement | Element): TNode | (() => void); public abstract readonly type: string; public readonly id: string; @@ -209,14 +211,13 @@ export abstract class Embeddable< } } - public render(el: HTMLElement): void { + public render(el: HTMLElement): TNode | void { this.renderComplete.setEl(el); this.renderComplete.setTitle(this.output.title || ''); if (this.destroyed) { throw new Error('Embeddable has been destroyed'); } - return; } /** diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx index c5912427893a6..056c652e104f0 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { HelloWorldEmbeddable } from '../../tests/fixtures'; +import { HelloWorldEmbeddable, HelloWorldEmbeddableReact } from '../../tests/fixtures'; import { EmbeddableRoot } from './embeddable_root'; import { mount } from 'enzyme'; import { findTestSubject } from '@elastic/eui/lib/test'; @@ -25,6 +25,13 @@ test('EmbeddableRoot renders an embeddable', async () => { expect(findTestSubject(component, 'embedError').length).toBe(0); }); +test('EmbeddableRoot renders a React-based embeddable', async () => { + const embeddable = new HelloWorldEmbeddableReact({ id: 'hello' }); + const component = mount(); + + expect(component.find('[data-test-subj="helloWorldEmbeddable"]')).toHaveLength(1); +}); + test('EmbeddableRoot updates input', async () => { const embeddable = new HelloWorldEmbeddable({ id: 'hello' }); const component = mount(); diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx index cab7fcbd54e1d..bfaefe09b5e6b 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx @@ -6,19 +6,25 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import { EuiLoadingSpinner } from '@elastic/eui'; import { EuiText } from '@elastic/eui'; -import { EmbeddableInput, IEmbeddable } from './i_embeddable'; +import { isPromise } from '@kbn/std'; +import { MaybePromise } from '@kbn/utility-types'; +import { EmbeddableInput, EmbeddableOutput, IEmbeddable } from './i_embeddable'; interface Props { - embeddable?: IEmbeddable; + embeddable?: IEmbeddable>; loading?: boolean; error?: string; input?: EmbeddableInput; } -export class EmbeddableRoot extends React.Component { +interface State { + node?: ReactNode; +} + +export class EmbeddableRoot extends React.Component { private root?: React.RefObject; private alreadyMounted: boolean = false; @@ -26,20 +32,33 @@ export class EmbeddableRoot extends React.Component { super(props); this.root = React.createRef(); + this.state = {}; } + private updateNode = (node: MaybePromise) => { + if (isPromise(node)) { + node.then(this.updateNode); + + return; + } + + this.setState({ node }); + }; + public componentDidMount() { - if (this.root && this.root.current && this.props.embeddable) { - this.alreadyMounted = true; - this.props.embeddable.render(this.root.current); + if (!this.root?.current || !this.props.embeddable) { + return; } + + this.alreadyMounted = true; + this.updateNode(this.props.embeddable.render(this.root.current) ?? undefined); } public componentDidUpdate(prevProps?: Props) { let justRendered = false; - if (this.root && this.root.current && this.props.embeddable && !this.alreadyMounted) { + if (this.root?.current && this.props.embeddable && !this.alreadyMounted) { this.alreadyMounted = true; - this.props.embeddable.render(this.root.current); + this.updateNode(this.props.embeddable.render(this.root.current) ?? undefined); justRendered = true; } @@ -56,20 +75,21 @@ export class EmbeddableRoot extends React.Component { } } - public shouldComponentUpdate(newProps: Props) { + public shouldComponentUpdate({ embeddable, error, input, loading }: Props, { node }: State) { return Boolean( - newProps.error !== this.props.error || - newProps.loading !== this.props.loading || - newProps.embeddable !== this.props.embeddable || - (this.root && this.root.current && newProps.embeddable && !this.alreadyMounted) || - newProps.input !== this.props.input + error !== this.props.error || + loading !== this.props.loading || + embeddable !== this.props.embeddable || + (this.root && this.root.current && embeddable && !this.alreadyMounted) || + input !== this.props.input || + node !== this.state.node ); } public render() { return ( -
    +
    {this.state.node}
    {this.props.loading && } {this.props.error && {this.props.error}} diff --git a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.test.tsx b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.test.tsx index 8f17a3bf84198..d932018c3f4fe 100644 --- a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.test.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.test.tsx @@ -20,47 +20,6 @@ test('ErrorEmbeddable renders an embeddable', async () => { expect(getByText(/some error occurred/i)).toBeVisible(); }); -test('ErrorEmbeddable renders in compact mode', async () => { - const embeddable = new ErrorEmbeddable( - 'some error occurred', - { id: '123', title: 'Error' }, - undefined, - true - ); - const component = render(); - - expect(component.baseElement).toMatchInlineSnapshot(` - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    - - `); -}); - test('ErrorEmbeddable renders an embeddable with markdown message', async () => { const error = '[some link](http://localhost:5601/takeMeThere)'; const embeddable = new ErrorEmbeddable(error, { id: '123', title: 'Error' }); diff --git a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx index 55946aad5da02..8dff4ecee8976 100644 --- a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx @@ -6,16 +6,12 @@ * Side Public License, v 1. */ -import { EuiText, EuiIcon, EuiPopover, EuiLink, EuiEmptyPrompt } from '@elastic/eui'; -import React, { useState } from 'react'; -import ReactDOM from 'react-dom'; -import { KibanaThemeProvider, Markdown } from '@kbn/kibana-react-plugin/public'; -import { i18n } from '@kbn/i18n'; +import { EuiEmptyPrompt } from '@elastic/eui'; +import React, { ReactNode } from 'react'; +import { Markdown } from '@kbn/kibana-react-plugin/public'; import { Embeddable } from './embeddable'; import { EmbeddableInput, EmbeddableOutput, IEmbeddable } from './i_embeddable'; import { IContainer } from '../containers'; -import { getTheme } from '../../services'; -import './error_embedabble.scss'; export const ERROR_EMBEDDABLE_TYPE = 'error'; @@ -25,91 +21,32 @@ export function isErrorEmbeddable( return Boolean(embeddable.fatalError || (embeddable as ErrorEmbeddable).error !== undefined); } -export class ErrorEmbeddable extends Embeddable { +export class ErrorEmbeddable extends Embeddable { public readonly type = ERROR_EMBEDDABLE_TYPE; public error: Error | string; - private dom?: HTMLElement; - constructor( - error: Error | string, - input: EmbeddableInput, - parent?: IContainer, - private compact: boolean = false - ) { + constructor(error: Error | string, input: EmbeddableInput, parent?: IContainer) { super(input, {}, parent); this.error = error; } public reload() {} - public render(dom: HTMLElement) { + public render() { const title = typeof this.error === 'string' ? this.error : this.error.message; - this.dom = dom; - let theme; - try { - theme = getTheme(); - } catch (err) { - theme = {}; - } - const errorMarkdown = ( + const body = ( ); - const node = this.compact ? ( - {errorMarkdown} - ) : ( + return (
    ); - const content = - theme && theme.theme$ ? ( - {node} - ) : ( - node - ); - - ReactDOM.render(content, dom); - } - - public destroy() { - if (this.dom) { - ReactDOM.unmountComponentAtNode(this.dom); - } } } - -const CompactEmbeddableError = ({ children }: { children?: React.ReactNode }) => { - const [isPopoverOpen, setPopoverOpen] = useState(false); - - const popoverButton = ( - - setPopoverOpen((open) => !open)} - > - - {i18n.translate('embeddableApi.panel.errorEmbeddable.message', { - defaultMessage: 'An error has occurred. Read more', - })} - - - ); - - return ( - setPopoverOpen(false)} - > - {children} - - ); -}; diff --git a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts index 1c9bdebcefc9b..1d3cc7980ad62 100644 --- a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts +++ b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts @@ -33,7 +33,8 @@ export interface EmbeddableOutput { export interface IEmbeddable< I extends EmbeddableInput = EmbeddableInput, - O extends EmbeddableOutput = EmbeddableOutput + O extends EmbeddableOutput = EmbeddableOutput, + N = any > { /** * Is this embeddable an instance of a Container class, can it contain @@ -172,15 +173,17 @@ export interface IEmbeddable< /** * Renders the embeddable at the given node. * @param domNode + * @returns A React node to mount or void in the case when rendering is done without React. */ - render(domNode: HTMLElement | Element): void; + render(domNode: HTMLElement | Element): N | void; /** * Renders a custom embeddable error at the given node. + * @param error * @param domNode - * @returns A callback that will be called on error destroy. + * @returns A React node or callback that will be called on error destroy. */ - renderError?(domNode: HTMLElement | Element, error: ErrorLike): () => void; + catchError?(error: EmbeddableError, domNode: HTMLElement | Element): N | (() => void); /** * Reload the embeddable so output and rendering is up to date. Especially relevant diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx index a79f19cb4225c..8f096020ae60e 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx @@ -17,17 +17,17 @@ import { Action, UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { Trigger, ViewMode } from '../types'; import { isErrorEmbeddable } from '../embeddables'; import { EmbeddablePanel } from './embeddable_panel'; -import { createEditModeAction } from '../test_samples/actions'; -import { - ContactCardEmbeddableFactory, - CONTACT_CARD_EMBEDDABLE, -} from '../test_samples/embeddables/contact_card/contact_card_embeddable_factory'; -import { HelloWorldContainer } from '../test_samples/embeddables/hello_world_container'; import { + createEditModeAction, ContactCardEmbeddable, ContactCardEmbeddableInput, ContactCardEmbeddableOutput, -} from '../test_samples/embeddables/contact_card/contact_card_embeddable'; + ContactCardEmbeddableFactory, + ContactCardEmbeddableReactFactory, + CONTACT_CARD_EMBEDDABLE, + CONTACT_CARD_EMBEDDABLE_REACT, + HelloWorldContainer, +} from '../test_samples'; import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; import { EuiBadge } from '@elastic/eui'; import { embeddablePluginMock } from '../../mocks'; @@ -43,12 +43,17 @@ const trigger: Trigger = { id: CONTEXT_MENU_TRIGGER, }; const embeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); +const embeddableReactFactory = new ContactCardEmbeddableReactFactory( + (() => null) as any, + {} as any +); const applicationMock = applicationServiceMock.createStartContract(); const theme = themeServiceMock.createStartContract(); actionRegistry.set(editModeAction.id, editModeAction); triggerRegistry.set(trigger.id, trigger); setup.registerEmbeddableFactory(embeddableFactory.type, embeddableFactory); +setup.registerEmbeddableFactory(embeddableReactFactory.type, embeddableReactFactory); const start = doStart(); const getEmbeddableFactory = start.getEmbeddableFactory; @@ -198,7 +203,7 @@ describe('HelloWorldContainer in error state', () => { ); - jest.spyOn(embeddable, 'renderError'); + jest.spyOn(embeddable, 'catchError'); }); test('renders a custom error', () => { @@ -207,9 +212,9 @@ describe('HelloWorldContainer in error state', () => { const embeddableError = findTestSubject(component, 'embeddableError'); - expect(embeddable.renderError).toHaveBeenCalledWith( - expect.any(HTMLElement), - new Error('something') + expect(embeddable.catchError).toHaveBeenCalledWith( + new Error('something'), + expect.any(HTMLElement) ); expect(embeddableError).toHaveProperty('length', 1); expect(embeddableError.text()).toBe('something'); @@ -222,21 +227,21 @@ describe('HelloWorldContainer in error state', () => { const embeddableError = findTestSubject(component, 'embeddableError'); - expect(embeddable.renderError).toHaveBeenCalledWith( - expect.any(HTMLElement), - new Error('something') + expect(embeddable.catchError).toHaveBeenCalledWith( + new Error('something'), + expect.any(HTMLElement) ); expect(embeddableError).toHaveProperty('length', 1); expect(embeddableError.text()).toBe('something'); }); test('destroys previous error', () => { - const { renderError } = embeddable as Required; - let destroyError: jest.MockedFunction>; + const { catchError } = embeddable as Required; + let destroyError: jest.MockedFunction>; - (embeddable.renderError as jest.MockedFunction).mockImplementationOnce( + (embeddable.catchError as jest.MockedFunction).mockImplementationOnce( (...args) => { - destroyError = jest.fn(renderError(...args)); + destroyError = jest.fn(catchError(...args)); return destroyError; } @@ -254,7 +259,7 @@ describe('HelloWorldContainer in error state', () => { }); test('renders a default error', async () => { - embeddable.renderError = undefined; + embeddable.catchError = undefined; embeddable.triggerError(new Error('something')); component.update(); @@ -263,6 +268,17 @@ describe('HelloWorldContainer in error state', () => { expect(embeddableError).toHaveProperty('length', 1); expect(embeddableError.children.length).toBeGreaterThan(0); }); + + test('renders a React node', () => { + (embeddable.catchError as jest.Mock).mockReturnValueOnce(
    Something
    ); + embeddable.triggerError(new Error('something')); + component.update(); + + const embeddableError = findTestSubject(component, 'embeddableError'); + + expect(embeddableError).toHaveProperty('length', 1); + expect(embeddableError.text()).toBe('Something'); + }); }); const renderInEditModeAndOpenContextMenu = async ( @@ -735,3 +751,37 @@ test('Should work in minimal way rendering only the inspector action', async () const action = findTestSubject(component, `embeddablePanelAction-ACTION_CUSTOMIZE_PANEL`); expect(action.length).toBe(0); }); + +test('Renders an embeddable returning a React node', async () => { + const container = new HelloWorldContainer( + { id: '123', panels: {}, viewMode: ViewMode.VIEW, hidePanelTitles: false }, + { getEmbeddableFactory } as any + ); + + const embeddable = await container.addNewEmbeddable< + ContactCardEmbeddableInput, + ContactCardEmbeddableOutput, + ContactCardEmbeddable + >(CONTACT_CARD_EMBEDDABLE_REACT, { + firstName: 'Bran', + lastName: 'Stark', + }); + + const component = mount( + + Promise.resolve([])} + getAllEmbeddableFactories={start.getEmbeddableFactories} + getEmbeddableFactory={start.getEmbeddableFactory} + notifications={{} as any} + overlays={{} as any} + application={applicationMock} + SavedObjectFinder={() => null} + theme={theme} + /> + + ); + + expect(component.find('.embPanel__titleText').text()).toBe('Hello Bran Stark'); +}); diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx index 52b70f3b53406..f5b072a591225 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx @@ -8,12 +8,14 @@ import { EuiContextMenuPanelDescriptor, EuiPanel, htmlIdGenerator } from '@elastic/eui'; import classNames from 'classnames'; -import React from 'react'; +import React, { ReactNode } from 'react'; import { Subscription } from 'rxjs'; import deepEqual from 'fast-deep-equal'; import { CoreStart, OverlayStart, ThemeServiceStart } from '@kbn/core/public'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { isPromise } from '@kbn/std'; import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import { MaybePromise } from '@kbn/utility-types'; import { buildContextMenuForActions, UiActionsService, Action } from '../ui_actions'; import { Start as InspectorStartContract } from '../inspector'; @@ -66,7 +68,7 @@ export interface EmbeddableContainerContext { } interface Props { - embeddable: IEmbeddable; + embeddable: IEmbeddable>; /** * Ordinal number of the embeddable in the container, used as a @@ -105,6 +107,7 @@ interface State { loading?: boolean; error?: EmbeddableError; destroyError?(): void; + node?: ReactNode; } interface InspectorPanelAction { @@ -304,27 +307,37 @@ export class EmbeddablePanel extends React.Component { error={this.state.error} /> )} -
    +
    + {this.state.node} +
    ); } public componentDidMount() { - if (this.embeddableRoot.current) { - this.subscription.add( - this.props.embeddable.getOutput$().subscribe( - (output: EmbeddableOutput) => { - this.setState({ - error: output.error, - loading: output.loading, - }); - }, - (error) => { - this.setState({ error }); - } - ) - ); - this.props.embeddable.render(this.embeddableRoot.current); + if (!this.embeddableRoot.current) { + return; + } + + this.subscription.add( + this.props.embeddable.getOutput$().subscribe( + (output: EmbeddableOutput) => { + this.setState({ + error: output.error, + loading: output.loading, + }); + }, + (error) => { + this.setState({ error }); + } + ) + ); + + const node = this.props.embeddable.render(this.embeddableRoot.current) ?? undefined; + if (isPromise(node)) { + node.then((resolved) => this.setState({ node: resolved })); + } else { + this.setState({ node }); } } diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel_error.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel_error.tsx index 46e26fd1448bb..69af8e7220e62 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel_error.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel_error.tsx @@ -6,17 +6,20 @@ * Side Public License, v 1. */ -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { isFunction } from 'lodash'; +import React, { ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import { EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { isPromise } from '@kbn/std'; +import type { MaybePromise } from '@kbn/utility-types'; import { ErrorLike } from '@kbn/expressions-plugin/common'; import { distinctUntilChanged, merge, of, switchMap } from 'rxjs'; import { EditPanelAction } from '../actions'; -import { ErrorEmbeddable, IEmbeddable } from '../embeddables'; +import { EmbeddableInput, EmbeddableOutput, ErrorEmbeddable, IEmbeddable } from '../embeddables'; interface EmbeddablePanelErrorProps { editPanelAction?: EditPanelAction; - embeddable: IEmbeddable; + embeddable: IEmbeddable>; error: ErrorLike; } @@ -26,6 +29,7 @@ export function EmbeddablePanelError({ error, }: EmbeddablePanelErrorProps) { const [isEditable, setEditable] = useState(false); + const [node, setNode] = useState(); const ref = useRef(null); const handleErrorClick = useMemo( () => (isEditable ? () => editPanelAction?.execute({ embeddable }) : undefined), @@ -63,14 +67,22 @@ export function EmbeddablePanelError({ return; } - if (embeddable.renderError) { - return embeddable.renderError(ref.current, error); - } + if (!embeddable.catchError) { + const errorEmbeddable = new ErrorEmbeddable(error, { id: embeddable.id }); + setNode(errorEmbeddable.render()); - const errorEmbeddable = new ErrorEmbeddable(error, { id: embeddable.id }); - errorEmbeddable.render(ref.current); + return () => errorEmbeddable.destroy(); + } - return () => errorEmbeddable.destroy(); + const renderedNode = embeddable.catchError(error, ref.current); + if (isFunction(renderedNode)) { + return renderedNode; + } + if (isPromise(renderedNode)) { + renderedNode.then(setNode); + } else { + setNode(renderedNode); + } }, [embeddable, error]); return ( @@ -84,6 +96,8 @@ export function EmbeddablePanelError({ role={isEditable ? 'button' : undefined} aria-label={isEditable ? ariaLabel : undefined} onClick={handleErrorClick} - /> + > + {node} + ); } diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx index 7d9a929299f35..0287b9d115827 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable.tsx @@ -47,7 +47,7 @@ export class ContactCardEmbeddable extends Embeddable< constructor( initialInput: ContactCardEmbeddableInput, - private readonly options: ContactCardEmbeddableOptions, + protected readonly options: ContactCardEmbeddableOptions, parent?: Container ) { super( @@ -77,7 +77,7 @@ export class ContactCardEmbeddable extends Embeddable< ); } - public renderError?(node: HTMLElement, error: ErrorLike) { + public catchError?(error: ErrorLike, node: HTMLElement) { ReactDom.render(
    {error.message}
    , node); return () => ReactDom.unmountComponentAtNode(node); diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx index 282f6a8c627c2..317e0d5e741c8 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx @@ -25,7 +25,7 @@ export class ContactCardEmbeddableFactory public readonly type = CONTACT_CARD_EMBEDDABLE; constructor( - private readonly execTrigger: UiActionsStart['executeTriggerActions'], + protected readonly execTrigger: UiActionsStart['executeTriggerActions'], private readonly overlays: CoreStart['overlays'] ) {} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react.tsx new file mode 100644 index 0000000000000..d42ba42a0cfb3 --- /dev/null +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react.tsx @@ -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 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 { ContactCardEmbeddableComponent } from './contact_card'; +import { ContactCardEmbeddable } from './contact_card_embeddable'; + +export class ContactCardEmbeddableReact extends ContactCardEmbeddable { + public render() { + return ( + + ); + } +} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react_factory.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react_factory.ts new file mode 100644 index 0000000000000..7378dc24ea5f8 --- /dev/null +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_react_factory.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 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 { Container } from '../../../containers'; +import { ContactCardEmbeddableInput } from './contact_card_embeddable'; +import { ContactCardEmbeddableFactory } from './contact_card_embeddable_factory'; +import { ContactCardEmbeddableReact } from './contact_card_embeddable_react'; + +export const CONTACT_CARD_EMBEDDABLE_REACT = 'CONTACT_CARD_EMBEDDABLE_REACT'; + +export class ContactCardEmbeddableReactFactory extends ContactCardEmbeddableFactory { + public readonly type = CONTACT_CARD_EMBEDDABLE_REACT as ContactCardEmbeddableFactory['type']; + + public create = async (initialInput: ContactCardEmbeddableInput, parent?: Container) => { + return new ContactCardEmbeddableReact( + initialInput, + { + execAction: this.execTrigger, + }, + parent + ); + }; +} diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.ts b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.ts index 526256d375963..fc63fcacbab79 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.ts +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/index.ts @@ -11,5 +11,7 @@ export * from './contact_card_embeddable'; export * from './contact_card_embeddable_factory'; export * from './contact_card_exportable_embeddable'; export * from './contact_card_exportable_embeddable_factory'; +export * from './contact_card_embeddable_react'; +export * from './contact_card_embeddable_react_factory'; export * from './contact_card_initializer'; export * from './slow_contact_card_embeddable_factory'; diff --git a/packages/kbn-adhoc-profiler/require_pprof.ts b/src/plugins/embeddable/public/tests/fixtures/hello_world_embeddable_react.tsx similarity index 57% rename from packages/kbn-adhoc-profiler/require_pprof.ts rename to src/plugins/embeddable/public/tests/fixtures/hello_world_embeddable_react.tsx index beba96c2a4793..aa9ac3175fd5e 100644 --- a/packages/kbn-adhoc-profiler/require_pprof.ts +++ b/src/plugins/embeddable/public/tests/fixtures/hello_world_embeddable_react.tsx @@ -6,9 +6,11 @@ * Side Public License, v 1. */ -import { PProf } from './types'; +import React from 'react'; +import { HelloWorldEmbeddable } from './hello_world_embeddable'; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const pprof = require('pprof') as PProf; - -export { pprof }; +export class HelloWorldEmbeddableReact extends HelloWorldEmbeddable { + public render() { + return
    HELLO WORLD!
    ; + } +} diff --git a/src/plugins/embeddable/public/tests/fixtures/index.ts b/src/plugins/embeddable/public/tests/fixtures/index.ts index a155f65d47858..ea9533a359ca7 100644 --- a/src/plugins/embeddable/public/tests/fixtures/index.ts +++ b/src/plugins/embeddable/public/tests/fixtures/index.ts @@ -8,3 +8,4 @@ export * from './hello_world_embeddable'; export * from './hello_world_embeddable_factory'; +export * from './hello_world_embeddable_react'; 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_panel.test.tsx b/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx index 0ef85523d01fe..5c2861a1543ca 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx @@ -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); @@ -225,28 +226,53 @@ describe('Guided setup', () => { }); describe('Steps', () => { - test('should show "Start" button label if step has not been started', async () => { + const clickActiveStepButton = async () => { const { component, find } = testBed; + await act(async () => { + find('activeStepButton').simulate('click'); + }); + + component.update(); + }; + + test('can start a step if step has not been started', async () => { + const { component, find, exists } = testBed; + await updateComponentWithState(component, mockActiveSearchGuideState, true); - expect(find('activeStepButtonLabel').text()).toEqual('Start'); + expect(find('activeStepButton').text()).toEqual('Start'); + + await clickActiveStepButton(); + + expect(exists('guidePanel')).toBe(false); }); - test('should show "Continue" button label if step is in progress', async () => { - const { component, find } = testBed; + test('can continue a step if step is in progress', async () => { + const { component, find, exists } = testBed; await updateComponentWithState(component, mockInProgressSearchGuideState, true); - expect(find('activeStepButtonLabel').text()).toEqual('Continue'); + expect(find('activeStepButton').text()).toEqual('Continue'); + + await clickActiveStepButton(); + + expect(exists('guidePanel')).toBe(false); }); - test('shows "Mark done" button label if step is ready to complete', async () => { - const { component, find } = testBed; + test('can mark a step "done" if step is ready to complete', async () => { + const { component, find, exists } = testBed; await updateComponentWithState(component, mockReadyToCompleteSearchGuideState, true); - expect(find('activeStepButtonLabel').text()).toEqual('Mark done'); + expect(find('activeStepButton').text()).toEqual('Mark done'); + + await clickActiveStepButton(); + + // The guide panel should remain open after marking a step done + expect(exists('guidePanel')).toBe(true); + // Dependent on the Search guide config, which expects another step to start + expect(find('activeStepButton').text()).toEqual('Start'); }); }); @@ -280,9 +306,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 6bd33735ec94e..ed021bc39c0ec 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel.tsx @@ -74,18 +74,19 @@ export const GuidePanel = ({ api, application }: GuidePanelProps) => { const handleStepButtonClick = async (step: GuideStepStatus, stepConfig: StepConfig) => { if (guideState) { const { id, status } = step; + if (status === 'ready_to_complete') { return await api.completeGuideStep(guideState?.guideId, id); } - if (status === 'active') { - await api.startGuideStep(guideState!.guideId, id); - } if (status === 'active' || status === 'in_progress') { + await api.startGuideStep(guideState!.guideId, id); + if (stepConfig.location) { await application.navigateToApp(stepConfig.location.appID, { path: stepConfig.location.path, }); + if (stepConfig.manualCompletion?.readyToCompleteOnNavigation) { await api.completeGuideStep(guideState.guideId, id); } @@ -140,20 +141,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.tsx b/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx index f79a26778c1a3..fa72afff87dc9 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx @@ -109,7 +109,7 @@ export const GuideStep = ({ handleButtonClick()} fill - data-test-subj="activeStepButtonLabel" + data-test-subj="activeStepButton" > {getStepButtonLabel()} diff --git a/src/plugins/guided_onboarding/public/index.ts b/src/plugins/guided_onboarding/public/index.ts index f4b2e6d8ff2f8..c9ea467231981 100755 --- a/src/plugins/guided_onboarding/public/index.ts +++ b/src/plugins/guided_onboarding/public/index.ts @@ -6,11 +6,10 @@ * 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, 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/types.ts b/src/plugins/guided_onboarding/public/types.ts index 41a26c6c32de1..a6536e3caf114 100755 --- a/src/plugins/guided_onboarding/public/types.ts +++ b/src/plugins/guided_onboarding/public/types.ts @@ -17,10 +17,6 @@ export interface GuidedOnboardingPluginStart { guidedOnboardingApi?: GuidedOnboardingApi; } -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/unified_search/public/query_string_input/text_based_languages_editor/index.tsx b/src/plugins/unified_search/public/query_string_input/text_based_languages_editor/index.tsx index 7857704ba329d..88140ef3d46b3 100644 --- a/src/plugins/unified_search/public/query_string_input/text_based_languages_editor/index.tsx +++ b/src/plugins/unified_search/public/query_string_input/text_based_languages_editor/index.tsx @@ -438,7 +438,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ , - domNode + /> ); - } else { - render(, domNode); } - return () => unmountComponentAtNode(domNode); + return ; } public destroy() { diff --git a/test/api_integration/apis/core/compression.ts b/test/api_integration/apis/core/compression.ts index c175fe4b9862e..c4b119692f4bb 100644 --- a/test/api_integration/apis/core/compression.ts +++ b/test/api_integration/apis/core/compression.ts @@ -12,10 +12,10 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - describe('compression', () => { + const compressionSuite = (url: string) => { it(`uses compression when there isn't a referer`, async () => { await supertest - .get('/app/kibana') + .get(url) .set('accept-encoding', 'gzip') .then((response) => { expect(response.header).to.have.property('content-encoding', 'gzip'); @@ -24,7 +24,7 @@ export default function ({ getService }: FtrProviderContext) { it(`uses compression when there is a whitelisted referer`, async () => { await supertest - .get('/app/kibana') + .get(url) .set('accept-encoding', 'gzip') .set('referer', 'https://some-host.com') .then((response) => { @@ -34,12 +34,27 @@ export default function ({ getService }: FtrProviderContext) { it(`doesn't use compression when there is a non-whitelisted referer`, async () => { await supertest - .get('/app/kibana') + .get(url) .set('accept-encoding', 'gzip') .set('referer', 'https://other.some-host.com') .then((response) => { expect(response.header).not.to.have.property('content-encoding'); }); }); + + it(`supports brotli compression`, async () => { + await supertest + .get(url) + .set('accept-encoding', 'br') + .then((response) => { + expect(response.header).to.have.property('content-encoding', 'br'); + }); + }); + }; + + describe('compression', () => { + describe('against an application page', () => { + compressionSuite('/app/kibana'); + }); }); } diff --git a/test/api_integration/config.js b/test/api_integration/config.js index 7f3f4b45298d1..ce04be64bb36e 100644 --- a/test/api_integration/config.js +++ b/test/api_integration/config.js @@ -31,6 +31,7 @@ export default async function ({ readConfigFile }) { '--elasticsearch.healthCheck.delay=3600000', '--server.xsrf.disableProtection=true', '--server.compression.referrerWhitelist=["some-host.com"]', + '--server.compression.brotli.enabled=true', `--savedObjects.maxImportExportSize=10001`, '--savedObjects.maxImportPayloadBytes=30000000', // for testing set buffer duration to 0 to immediately flush counters into saved objects. diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 1c7e8a96bd1ec..c3106d19204f2 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -104,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/x-pack/examples/files_example/common/index.ts b/x-pack/examples/files_example/common/index.ts index 1586d92c4c05a..aeb807e30aadf 100644 --- a/x-pack/examples/files_example/common/index.ts +++ b/x-pack/examples/files_example/common/index.ts @@ -8,14 +8,14 @@ import type { FileKind, FileImageMetadata } from '@kbn/files-plugin/common'; export const PLUGIN_ID = 'filesExample'; -export const PLUGIN_NAME = 'filesExample'; +export const PLUGIN_NAME = 'Files example'; const httpTags = { tags: [`access:${PLUGIN_ID}`], }; export const exampleFileKind: FileKind = { - id: 'filesExample', + id: PLUGIN_ID, allowedMimeTypes: ['image/png'], http: { create: httpTags, diff --git a/x-pack/examples/files_example/kibana.json b/x-pack/examples/files_example/kibana.json index 5df1141929c41..b9cc4027a43f4 100644 --- a/x-pack/examples/files_example/kibana.json +++ b/x-pack/examples/files_example/kibana.json @@ -9,6 +9,6 @@ "description": "Example plugin integrating with files plugin", "server": true, "ui": true, - "requiredPlugins": ["files"], + "requiredPlugins": ["files", "developerExamples"], "optionalPlugins": [] } diff --git a/x-pack/examples/files_example/public/application.tsx b/x-pack/examples/files_example/public/application.tsx index 3bdbae462f6b3..0bad6975c6da0 100644 --- a/x-pack/examples/files_example/public/application.tsx +++ b/x-pack/examples/files_example/public/application.tsx @@ -22,7 +22,7 @@ export const renderApp = ( ) => { ReactDOM.render( - + , diff --git a/x-pack/examples/files_example/public/components/app.tsx b/x-pack/examples/files_example/public/components/app.tsx index cf0f4461b8b62..d3dfbdeb71874 100644 --- a/x-pack/examples/files_example/public/components/app.tsx +++ b/x-pack/examples/files_example/public/components/app.tsx @@ -21,6 +21,7 @@ import { } from '@elastic/eui'; import { CoreStart } from '@kbn/core/public'; +import { MyFilePicker } from './file_picker'; import type { MyImageMetadata } from '../../common'; import type { FileClients } from '../types'; import { DetailsFlyout } from './details_flyout'; @@ -39,11 +40,19 @@ export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) = files.example.list() ); const [showUploadModal, setShowUploadModal] = useState(false); + const [showFilePickerModal, setShowFilePickerModal] = useState(false); const [isDeletingFile, setIsDeletingFile] = useState(false); const [selectedItem, setSelectedItem] = useState>(); const renderToolsRight = () => { return [ + setShowFilePickerModal(true)} + isDisabled={isLoading || isDeletingFile} + iconType="eye" + > + Select a file + , setShowUploadModal(true)} isDisabled={isLoading || isDeletingFile} @@ -155,6 +164,18 @@ export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) = }} /> )} + {showFilePickerModal && ( + setShowFilePickerModal(false)} + onDone={(ids) => { + notifications.toasts.addSuccess({ + title: 'Selected files!', + text: 'IDS:' + JSON.stringify(ids, null, 2), + }); + setShowFilePickerModal(false); + }} + /> + )} ); }; diff --git a/x-pack/examples/files_example/public/components/file_picker.tsx b/x-pack/examples/files_example/public/components/file_picker.tsx new file mode 100644 index 0000000000000..2bf5530655ba3 --- /dev/null +++ b/x-pack/examples/files_example/public/components/file_picker.tsx @@ -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 React from 'react'; +import type { FunctionComponent } from 'react'; + +import { exampleFileKind } from '../../common'; + +import { FilePicker } from '../imports'; + +interface Props { + onClose: () => void; + onDone: (ids: string[]) => void; +} + +export const MyFilePicker: FunctionComponent = ({ onClose, onDone }) => { + return ; +}; diff --git a/x-pack/examples/files_example/public/components/modal.tsx b/x-pack/examples/files_example/public/components/modal.tsx index 9d323b240f416..d8289257617cf 100644 --- a/x-pack/examples/files_example/public/components/modal.tsx +++ b/x-pack/examples/files_example/public/components/modal.tsx @@ -27,8 +27,8 @@ export const Modal: FunctionComponent = ({ onDismiss, onUploaded, client diff --git a/x-pack/examples/files_example/public/imports.ts b/x-pack/examples/files_example/public/imports.ts index 7758883d0da83..a60d9cb4a6a36 100644 --- a/x-pack/examples/files_example/public/imports.ts +++ b/x-pack/examples/files_example/public/imports.ts @@ -12,5 +12,8 @@ export { UploadFile, FilesContext, ScopedFilesClient, + FilePicker, Image, } from '@kbn/files-plugin/public'; + +export type { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; diff --git a/x-pack/examples/files_example/public/plugin.ts b/x-pack/examples/files_example/public/plugin.ts index 98a6b6f6e4608..4906b59d4d6fc 100644 --- a/x-pack/examples/files_example/public/plugin.ts +++ b/x-pack/examples/files_example/public/plugin.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { AppNavLinkStatus } from '@kbn/core-application-browser'; import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { PLUGIN_ID, PLUGIN_NAME, exampleFileKind, MyImageMetadata } from '../common'; import { FilesExamplePluginsStart, FilesExamplePluginsSetup } from './types'; @@ -12,12 +13,22 @@ import { FilesExamplePluginsStart, FilesExamplePluginsSetup } from './types'; export class FilesExamplePlugin implements Plugin { - public setup(core: CoreSetup, { files }: FilesExamplePluginsSetup) { + public setup( + core: CoreSetup, + { files, developerExamples }: FilesExamplePluginsSetup + ) { files.registerFileKind(exampleFileKind); + developerExamples.register({ + appId: PLUGIN_ID, + title: PLUGIN_NAME, + description: 'Example plugin for the files plugin', + }); + core.application.register({ id: PLUGIN_ID, title: PLUGIN_NAME, + navLinkStatus: AppNavLinkStatus.hidden, async mount(params: AppMountParameters) { // Load application bundle const { renderApp } = await import('./application'); diff --git a/x-pack/examples/files_example/public/types.ts b/x-pack/examples/files_example/public/types.ts index fbc058d9aec30..0ac384055aaf3 100644 --- a/x-pack/examples/files_example/public/types.ts +++ b/x-pack/examples/files_example/public/types.ts @@ -6,10 +6,17 @@ */ import { MyImageMetadata } from '../common'; -import type { FilesSetup, FilesStart, ScopedFilesClient, FilesClient } from './imports'; +import type { + FilesSetup, + FilesStart, + ScopedFilesClient, + FilesClient, + DeveloperExamplesSetup, +} from './imports'; export interface FilesExamplePluginsSetup { files: FilesSetup; + developerExamples: DeveloperExamplesSetup; } export interface FilesExamplePluginsStart { diff --git a/x-pack/examples/files_example/tsconfig.json b/x-pack/examples/files_example/tsconfig.json index caeb25650a142..e75078a80019c 100644 --- a/x-pack/examples/files_example/tsconfig.json +++ b/x-pack/examples/files_example/tsconfig.json @@ -15,11 +15,8 @@ ], "exclude": [], "references": [ - { - "path": "../../../src/core/tsconfig.json" - }, - { - "path": "../../plugins/files/tsconfig.json" - } + { "path": "../../../src/core/tsconfig.json" }, + { "path": "../../plugins/files/tsconfig.json" }, + { "path": "../../../examples/developer_examples/tsconfig.json" } ] } 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 35791ffa01f23..849cd2ff44ba5 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -540,7 +540,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 26d0a55b07dc6..90603499cd4a7 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -242,7 +242,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 fa70e0dc71354..749fc7a21ebdf 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, @@ -351,6 +351,7 @@ export class ActionsPlugin implements Plugin ) => { ensureSufficientLicense(actionType); + actionType.maxAttempts = actionType.maxAttempts ?? MAX_ATTEMPTS; actionTypeRegistry.register(actionType); }, registerSubActionConnectorType: < diff --git a/x-pack/plugins/apm/common/rules/apm_rule_field_map.ts b/x-pack/plugins/apm/common/rules/apm_rule_field_map.ts deleted file mode 100644 index 9bbd9381c2319..0000000000000 --- a/x-pack/plugins/apm/common/rules/apm_rule_field_map.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. - */ - -export const apmRuleFieldMap = { - 'service.environment': { - type: 'keyword', - }, - 'transaction.type': { - type: 'keyword', - }, - 'processor.event': { - type: 'keyword', - }, -} as const; - -export type APMRuleFieldMap = typeof apmRuleFieldMap; 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/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index 33ae657747dfe..ff978bebe8fb9 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -28,7 +28,7 @@ import { ServiceAnomalyTimeseriesContextProvider } from '../../../../context/ser import { useApmParams } from '../../../../hooks/use_apm_params'; import { useApmRouter } from '../../../../hooks/use_apm_router'; import { useTimeRange } from '../../../../hooks/use_time_range'; -import { getAlertingCapabilities } from '../../../alerting/get_alerting_capabilities'; +import { getAlertingCapabilities } from '../../../alerting/utils/get_alerting_capabilities'; import { SearchBar } from '../../../shared/search_bar'; import { ServiceIcons } from '../../../shared/service_icons'; import { BetaBadge } from '../../../shared/beta_badge'; diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/alerting_popover_flyout.tsx b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/alerting_popover_flyout.tsx index cc5e6ac67d43e..115c7019be611 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/alerting_popover_flyout.tsx +++ b/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/alerting_popover_flyout.tsx @@ -14,8 +14,8 @@ import { import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; import { IBasePath } from '@kbn/core/public'; -import { AlertType } from '../../../../common/alert_types'; -import { AlertingFlyout } from '../../alerting/alerting_flyout'; +import { ApmRuleType } from '../../../../common/rules/apm_rule_types'; +import { AlertingFlyout } from '../../alerting/ui_components/alerting_flyout'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; const alertLabel = i18n.translate('xpack.apm.home.alertsMenu.alerts', { @@ -59,7 +59,7 @@ export function AlertingPopoverAndFlyout({ includeTransactionDuration, }: Props) { const [popoverOpen, setPopoverOpen] = useState(false); - const [alertType, setAlertType] = useState(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/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/lib/helpers/service_metrics/index.ts b/x-pack/plugins/apm/server/lib/helpers/service_metrics/index.ts index 48936b644c2af..1f68eaef98aae 100644 --- a/x-pack/plugins/apm/server/lib/helpers/service_metrics/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/service_metrics/index.ts @@ -54,7 +54,7 @@ export async function getHasServicesMetrics({ }, body: { track_total_hits: 1, - size: 1, + size: 0, query: { bool: { filter: [ diff --git a/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts b/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts index 757868425be32..0dbf3006a324d 100644 --- a/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts +++ b/x-pack/plugins/apm/server/lib/helpers/spans/get_is_using_service_destination_metrics.ts @@ -79,7 +79,7 @@ export async function getIsUsingServiceDestinationMetrics({ }, body: { track_total_hits: 1, - size: 1, + size: 0, terminate_after: 1, query: { bool: { diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap b/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap index bc4ade1230986..325ce29af118d 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap @@ -31,7 +31,7 @@ Object { ], }, }, - "size": 1, + "size": 0, "terminate_after": 1, "track_total_hits": 1, }, @@ -57,7 +57,7 @@ Object { ], }, }, - "size": 1, + "size": 0, "terminate_after": 1, "track_total_hits": 1, }, @@ -86,7 +86,7 @@ Array [ ], }, }, - "size": 1, + "size": 0, "terminate_after": 1, "track_total_hits": 1, }, diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts index b6f7dfa4083e1..3e54ee7fda79f 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts @@ -37,7 +37,7 @@ export async function getHasTransactionsEvents({ body: { track_total_hits: 1, terminate_after: 1, - size: 1, + size: 0, query: { bool: { filter: [ 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/apm_routes/register_apm_server_routes.ts b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts index f0e1f67ec2bec..6de9c99cdbcd3 100644 --- a/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts @@ -5,25 +5,23 @@ * 2.0. */ -import { errors } from '@elastic/elasticsearch'; import Boom from '@hapi/boom'; -import { RequestHandler } from '@kbn/core-http-server'; +import * as t from 'io-ts'; import { KibanaRequest, RouteRegistrar } from '@kbn/core/server'; -import { jsonRt, mergeRt } from '@kbn/io-ts-utils'; -import { InspectResponse } from '@kbn/observability-plugin/typings/common'; +import { errors } from '@elastic/elasticsearch'; +import agent from 'elastic-apm-node'; +import { ServerRouteRepository } from '@kbn/server-route-repository'; +import { merge } from 'lodash'; import { decodeRequestParams, parseEndpoint, routeValidationObject, - ServerRouteRepository, } from '@kbn/server-route-repository'; -import agent from 'elastic-apm-node'; -import * as t from 'io-ts'; -import { merge } from 'lodash'; -import { inspectCpuProfile } from '@kbn/adhoc-profiler'; +import { jsonRt, mergeRt } from '@kbn/io-ts-utils'; +import { InspectResponse } from '@kbn/observability-plugin/typings/common'; import { pickKeys } from '../../../common/utils/pick_keys'; -import type { ApmPluginRequestHandlerContext } from '../typings'; import { APMRouteHandlerResources, TelemetryUsageCounter } from '../typings'; +import type { ApmPluginRequestHandlerContext } from '../typings'; const inspectRt = t.exact( t.partial({ @@ -66,29 +64,6 @@ export function registerRoutes({ const router = core.setup.http.createRouter(); - function wrapRouteHandlerInProfiler( - handler: RequestHandler< - unknown, - unknown, - unknown, - ApmPluginRequestHandlerContext - > - ): RequestHandler< - unknown, - { _profile?: 'inspect' }, - unknown, - ApmPluginRequestHandlerContext - > { - return (context, request, response) => { - const { _profile } = request.query; - if (_profile === 'inspect') { - delete request.query._profile; - return inspectCpuProfile(() => handler(context, request, response)); - } - return handler(context, request, response); - }; - } - routes.forEach((route) => { const { params, endpoint, options, handler } = route; @@ -105,7 +80,7 @@ export function registerRoutes({ options, validate: routeValidationObject, }, - wrapRouteHandlerInProfiler(async (context, request, response) => { + async (context, request, response) => { if (agent.isStarted()) { agent.addLabels({ plugin: 'apm', @@ -211,7 +186,7 @@ export function registerRoutes({ // cleanup inspectableEsQueriesMap.delete(request); } - }) + } ); }); } diff --git a/x-pack/plugins/cases/common/constants.ts b/x-pack/plugins/cases/common/constants.ts index 89c7de48b257d..30c1d7d186de0 100644 --- a/x-pack/plugins/cases/common/constants.ts +++ b/x-pack/plugins/cases/common/constants.ts @@ -141,7 +141,7 @@ export const MAX_CONCURRENT_SEARCHES = 10 as const; * Validation */ -export const MAX_TITLE_LENGTH = 64 as const; +export const MAX_TITLE_LENGTH = 160 as const; /** * Cases features 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/all_cases/selector_modal/all_cases_selector_modal.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx index 217893b0923e0..89bd623307f1f 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx @@ -29,8 +29,8 @@ export interface AllCasesSelectorModalProps { const Modal = styled(EuiModal)` ${({ theme }) => ` - width: ${theme.eui.euiBreakpoints.l}; - max-width: ${theme.eui.euiBreakpoints.l}; + width: ${theme.eui.euiBreakpoints.xl}; + max-width: ${theme.eui.euiBreakpoints.xl}; `} `; diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx index 424ad669c5b34..8185b3be3df3e 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx @@ -52,6 +52,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "assignees", @@ -130,6 +131,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "assignees", @@ -199,6 +201,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "assignees", @@ -262,6 +265,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "tags", @@ -331,6 +335,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "tags", @@ -398,6 +403,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "tags", @@ -464,6 +470,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "tags", @@ -529,6 +536,7 @@ describe('useCasesColumns ', () => { Object { "name": "Name", "render": [Function], + "width": "20%", }, Object { "field": "tags", diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx index 965277abd2dd3..3f0009d42f591 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx @@ -160,6 +160,7 @@ export const useCasesColumns = ({ } return getEmptyTagValue(); }, + width: '20%', }, ]; diff --git a/x-pack/plugins/cases/public/components/header_page/editable_title.test.tsx b/x-pack/plugins/cases/public/components/header_page/editable_title.test.tsx index 51d42c3d1d3b0..f0ecca120ac10 100644 --- a/x-pack/plugins/cases/public/components/header_page/editable_title.test.tsx +++ b/x-pack/plugins/cases/public/components/header_page/editable_title.test.tsx @@ -190,9 +190,8 @@ describe('EditableTitle', () => { expect(wrapper.find('[data-test-subj="editable-title-edit-icon"]').first().exists()).toBe(true); }); - it('does not submit the title when the length is longer than 64 characters', () => { - const longTitle = - 'This is a title that should not be saved as it is longer than 64 characters.'; + it('does not submit the title when the length is longer than 160 characters', () => { + const longTitle = 'a'.repeat(161); const wrapper = mount( @@ -210,7 +209,7 @@ describe('EditableTitle', () => { wrapper.find('button[data-test-subj="editable-title-submit-btn"]').simulate('click'); wrapper.update(); expect(wrapper.find('.euiFormErrorText').text()).toBe( - 'The length of the title is too long. The maximum length is 64.' + 'The length of the title is too long. The maximum length is 160.' ); expect(submitTitle).not.toHaveBeenCalled(); @@ -220,8 +219,7 @@ describe('EditableTitle', () => { }); it('does not show an error after a previous edit error was displayed', () => { - const longTitle = - 'This is a title that should not be saved as it is longer than 64 characters.'; + const longTitle = 'a'.repeat(161); const shortTitle = 'My title'; const wrapper = mount( @@ -241,7 +239,7 @@ describe('EditableTitle', () => { wrapper.find('button[data-test-subj="editable-title-submit-btn"]').simulate('click'); wrapper.update(); expect(wrapper.find('.euiFormErrorText').text()).toBe( - 'The length of the title is too long. The maximum length is 64.' + 'The length of the title is too long. The maximum length is 160.' ); // write a shorter one diff --git a/x-pack/plugins/cases/public/components/property_actions/index.tsx b/x-pack/plugins/cases/public/components/property_actions/index.tsx index 9fa874344864b..8f67611097a80 100644 --- a/x-pack/plugins/cases/public/components/property_actions/index.tsx +++ b/x-pack/plugins/cases/public/components/property_actions/index.tsx @@ -45,8 +45,8 @@ export const PropertyActions = React.memo(({ propertyActio const [showActions, setShowActions] = useState(false); const onButtonClick = useCallback(() => { - setShowActions(!showActions); - }, [showActions]); + setShowActions((prevShowActions) => !prevShowActions); + }, []); const onClosePopover = useCallback((cb?: () => void) => { setShowActions(false); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/actions.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/actions.tsx index b82e10b8065a4..5b17b05a45f68 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/actions.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/actions.tsx @@ -5,11 +5,9 @@ * 2.0. */ -import React, { useContext } from 'react'; +import React from 'react'; import classNames from 'classnames'; -import { ThemeContext } from 'styled-components'; -import { EuiToken } from '@elastic/eui'; import type { CommentResponseActionsType } from '../../../../common/api'; import type { UserActionBuilder, UserActionBuilderArgs } from '../types'; import { UserActionTimestamp } from '../timestamp'; @@ -54,7 +52,7 @@ export const createActionAttachmentUserActionBuilder = ({ ), 'data-test-subj': 'endpoint-action', timestamp: , - timelineAvatar: , + timelineAvatar: comment.actions.type === 'isolate' ? 'lock' : 'lockOpen', actions: , children: comment.comment.trim().length > 0 && ( @@ -65,21 +63,3 @@ export const createActionAttachmentUserActionBuilder = ({ ]; }, }); - -const ActionIcon = React.memo<{ - actionType: string; -}>(({ actionType }) => { - const theme = useContext(ThemeContext); - return ( - - ); -}); - -ActionIcon.displayName = 'ActionIcon'; diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx index 20afa12a377bf..049862abaaf40 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { get, isEmpty } from 'lodash'; import type { EuiCommentProps } from '@elastic/eui'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexItem } from '@elastic/eui'; import { ALERT_RULE_NAME, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; import type { CommentResponseAlertsType } from '../../../../common/api'; @@ -16,10 +16,11 @@ import type { UserActionBuilder, UserActionBuilderArgs } from '../types'; import { UserActionTimestamp } from '../timestamp'; import type { SnakeToCamelCase } from '../../../../common/types'; import { MultipleAlertsCommentEvent, SingleAlertCommentEvent } from './alert_event'; -import { UserActionCopyLink } from '../copy_link'; import { UserActionShowAlert } from './show_alert'; import { ShowAlertTableLink } from './show_alert_table_link'; import { HoverableUserWithAvatarResolver } from '../../user_profiles/hoverable_user_with_avatar_resolver'; +import { UserActionContentToolbar } from '../content_toolbar'; +import { AlertPropertyActions } from '../property_actions/alert_property_actions'; type BuilderArgs = Pick< UserActionBuilderArgs, @@ -30,6 +31,8 @@ type BuilderArgs = Pick< | 'loadingAlertData' | 'onShowAlertDetails' | 'userProfiles' + | 'handleDeleteComment' + | 'loadingCommentIds' > & { comment: SnakeToCamelCase }; const getSingleAlertUserAction = ({ @@ -37,10 +40,12 @@ const getSingleAlertUserAction = ({ userProfiles, comment, alertData, - getRuleDetailsHref, loadingAlertData, + loadingCommentIds, + getRuleDetailsHref, onRuleDetailsClick, onShowAlertDetails, + handleDeleteComment, }: BuilderArgs): EuiCommentProps[] => { const alertId = getNonEmptyField(comment.alertId); const alertIndex = getNonEmptyField(comment.index); @@ -73,10 +78,7 @@ const getSingleAlertUserAction = ({ timestamp: , timelineAvatar: 'bell', actions: ( - - - - + - + handleDeleteComment(comment.id)} + isLoading={loadingCommentIds.includes(comment.id)} + totalAlerts={1} + /> + ), }, ]; @@ -96,9 +103,11 @@ const getMultipleAlertsUserAction = ({ userProfiles, comment, alertData, - getRuleDetailsHref, loadingAlertData, + loadingCommentIds, + getRuleDetailsHref, onRuleDetailsClick, + handleDeleteComment, }: BuilderArgs): EuiCommentProps[] => { if (!Array.isArray(comment.alertId)) { return []; @@ -128,14 +137,16 @@ const getMultipleAlertsUserAction = ({ timestamp: , timelineAvatar: 'bell', actions: ( - - - - + - + handleDeleteComment(comment.id)} + isLoading={loadingCommentIds.includes(comment.id)} + totalAlerts={totalAlerts} + /> + ), }, ]; diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx index 46562a028e536..3415355354ed9 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { EuiCommentList } from '@elastic/eui'; +import type { RenderResult } from '@testing-library/react'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; @@ -20,6 +21,7 @@ import { getExternalReferenceAttachment, getExternalReferenceUserAction, getHostIsolationUserAction, + getMultipleAlertsUserAction, getPersistableStateAttachment, getPersistableStateUserAction, getUserAction, @@ -30,7 +32,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer, TestProviders } from '../../../common/mock'; import { createCommentUserActionBuilder } from './comment'; import { getMockBuilderArgs } from '../mock'; -import { useCaseViewParams } from '../../../common/navigation'; +import { useCaseViewNavigation, useCaseViewParams } from '../../../common/navigation'; import { ExternalReferenceAttachmentTypeRegistry } from '../../../client/attachment_framework/external_reference_registry'; import { PersistableStateAttachmentTypeRegistry } from '../../../client/attachment_framework/persistable_state_registry'; import { userProfiles } from '../../../containers/user_profiles/api.mock'; @@ -39,66 +41,231 @@ jest.mock('../../../common/lib/kibana'); jest.mock('../../../common/navigation/hooks'); const useCaseViewParamsMock = useCaseViewParams as jest.Mock; +const useCaseViewNavigationMock = useCaseViewNavigation as jest.Mock; +const navigateToCaseView = jest.fn(); describe('createCommentUserActionBuilder', () => { const builderArgs = getMockBuilderArgs(); beforeEach(() => { jest.clearAllMocks(); + useCaseViewNavigationMock.mockReturnValue({ navigateToCaseView }); }); - it('renders correctly when editing a comment', async () => { - const userAction = getUserAction('comment', Actions.update); - const builder = createCommentUserActionBuilder({ - ...builderArgs, - userAction, - }); + describe('edits', () => { + it('renders correctly when editing a comment', async () => { + const userAction = getUserAction('comment', Actions.update); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); - const createdUserAction = builder.build(); - render( - - - - ); + const createdUserAction = builder.build(); + render( + + + + ); - expect(screen.getByText('edited comment')).toBeInTheDocument(); + expect(screen.getByText('edited comment')).toBeInTheDocument(); + }); }); - it('renders correctly when deleting a comment', async () => { - const userAction = getUserAction('comment', Actions.delete); - const builder = createCommentUserActionBuilder({ - ...builderArgs, - userAction, + describe('deletions', () => { + it('renders correctly when deleting a comment', async () => { + const userAction = getUserAction('comment', Actions.delete); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + render( + + + + ); + + expect(screen.getByText('removed comment')).toBeInTheDocument(); }); - const createdUserAction = builder.build(); - render( - - - - ); + it('renders correctly when deleting a single alert', async () => { + const userAction = getAlertUserAction({ action: Actions.delete }); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + render( + + + + ); + + expect(screen.getByText('removed one alert')).toBeInTheDocument(); + }); + + it('renders correctly when deleting multiple alerts', async () => { + const userAction = getMultipleAlertsUserAction({ action: Actions.delete }); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); - expect(screen.getByText('removed comment')).toBeInTheDocument(); + const createdUserAction = builder.build(); + render( + + + + ); + + expect(screen.getByText('removed 2 alerts')).toBeInTheDocument(); + }); + + it('renders correctly when deleting an external reference attachment', async () => { + const userAction = getExternalReferenceUserAction({ action: Actions.delete }); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + render( + + + + ); + + expect(screen.getByText('removed attachment')).toBeInTheDocument(); + }); + + it('renders correctly when deleting a persistable state attachment', async () => { + const userAction = getPersistableStateUserAction({ action: Actions.delete }); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + render( + + + + ); + + expect(screen.getByText('removed attachment')).toBeInTheDocument(); + }); }); - it('renders correctly a user comment', async () => { - const userAction = getUserAction('comment', Actions.create, { - commentId: basicCase.comments[0].id, + describe('user comments', () => { + it('renders correctly a user comment', async () => { + const userAction = getUserAction('comment', Actions.create, { + commentId: basicCase.comments[0].id, + }); + + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + render( + + + + ); + + expect(screen.getByText('Solve this fast!')).toBeInTheDocument(); }); - const builder = createCommentUserActionBuilder({ - ...builderArgs, - userAction, + it('deletes a user comment correctly', async () => { + const userAction = getUserAction('comment', Actions.create, { + commentId: basicCase.comments[0].id, + }); + + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + const result = render( + + + + ); + + expect(result.getByText('Solve this fast!')).toBeInTheDocument(); + + await deleteAttachment(result, 'trash', 'Delete'); + + await waitFor(() => { + expect(builderArgs.handleDeleteComment).toHaveBeenCalledWith('basic-comment-id'); + }); }); - const createdUserAction = builder.build(); - render( - - - - ); + it('edits a user comment correctly', async () => { + const userAction = getUserAction('comment', Actions.create, { + commentId: basicCase.comments[0].id, + }); - expect(screen.getByText('Solve this fast!')).toBeInTheDocument(); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + const result = render( + + + + ); + + expect(result.getByText('Solve this fast!')).toBeInTheDocument(); + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-pencil')).toBeInTheDocument(); + userEvent.click(result.getByTestId('property-actions-pencil')); + + await waitFor(() => { + expect(builderArgs.handleManageMarkdownEditId).toHaveBeenCalledWith('basic-comment-id'); + }); + }); + + it('quotes a user comment correctly', async () => { + const userAction = getUserAction('comment', Actions.create, { + commentId: basicCase.comments[0].id, + }); + + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + const result = render( + + + + ); + + expect(result.getByText('Solve this fast!')).toBeInTheDocument(); + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-quote')).toBeInTheDocument(); + userEvent.click(result.getByTestId('property-actions-quote')); + + await waitFor(() => { + expect(builderArgs.handleManageQuote).toHaveBeenCalledWith('basic-comment-id'); + }); + }); }); describe('Single alert', () => { @@ -125,9 +292,72 @@ describe('createCommentUserActionBuilder', () => { 'added an alert from Awesome rule' ); }); + + it('deletes a single alert correctly', async () => { + const userAction = getAlertUserAction(); + + const builder = createCommentUserActionBuilder({ + ...builderArgs, + caseData: { + ...builderArgs.caseData, + comments: [alertComment], + }, + userAction, + }); + + const createdUserAction = builder.build(); + const res = render( + + + + ); + + expect(res.getByTestId('single-alert-user-action-alert-action-id')).toHaveTextContent( + 'added an alert from Awesome rule' + ); + + await deleteAttachment(res, 'minusInCircle', 'Remove'); + + await waitFor(() => { + expect(builderArgs.handleDeleteComment).toHaveBeenCalledWith('alert-comment-id'); + }); + }); + + it('views an alert correctly', async () => { + const userAction = getAlertUserAction(); + + const builder = createCommentUserActionBuilder({ + ...builderArgs, + caseData: { + ...builderArgs.caseData, + comments: [alertComment], + }, + userAction, + }); + + const createdUserAction = builder.build(); + const result = render( + + + + ); + + expect(result.getByTestId('comment-action-show-alert-alert-action-id')).toBeInTheDocument(); + userEvent.click(result.getByTestId('comment-action-show-alert-alert-action-id')); + + await waitFor(() => { + expect(builderArgs.onShowAlertDetails).toHaveBeenCalledWith('alert-id-1', 'alert-index-1'); + }); + }); }); describe('Multiple alerts', () => { + let appMockRender: AppMockRenderer; + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + }); + it('renders correctly multiple alerts with a link to the alerts table', async () => { useCaseViewParamsMock.mockReturnValue({ detailName: '1234' }); const userAction = getAlertUserAction(); @@ -148,16 +378,74 @@ describe('createCommentUserActionBuilder', () => { }); const createdUserAction = builder.build(); - render( - - - + const res = appMockRender.render(); + + expect(res.getByTestId('multiple-alerts-user-action-alert-action-id')).toHaveTextContent( + 'added 2 alerts from Awesome rule' ); + expect(res.getByTestId('comment-action-show-alerts-1234')); + }); + + it('deletes multiple alerts correctly', async () => { + const userAction = getAlertUserAction(); + + const builder = createCommentUserActionBuilder({ + ...builderArgs, + caseData: { + ...builderArgs.caseData, + comments: [ + { + ...alertComment, + alertId: ['alert-id-1', 'alert-id-2'], + index: ['alert-index-1', 'alert-index-2'], + }, + ], + }, + userAction, + }); + + const createdUserAction = builder.build(); + const res = appMockRender.render(); expect(screen.getByTestId('multiple-alerts-user-action-alert-action-id')).toHaveTextContent( 'added 2 alerts from Awesome rule' ); - expect(screen.getByTestId('comment-action-show-alerts-1234')); + + await deleteAttachment(res, 'minusInCircle', 'Remove'); + + await waitFor(() => { + expect(builderArgs.handleDeleteComment).toHaveBeenCalledWith('alert-comment-id'); + }); + }); + + it('views multiple alerts correctly', async () => { + useCaseViewParamsMock.mockReturnValue({ detailName: '1234' }); + const userAction = getAlertUserAction(); + + const builder = createCommentUserActionBuilder({ + ...builderArgs, + caseData: { + ...builderArgs.caseData, + comments: [ + { + ...alertComment, + alertId: ['alert-id-1', 'alert-id-2'], + index: ['alert-index-1', 'alert-index-2'], + }, + ], + }, + userAction, + }); + + const createdUserAction = builder.build(); + const res = appMockRender.render(); + + expect(res.getByTestId('comment-action-show-alerts-1234')); + userEvent.click(res.getByTestId('comment-action-show-alerts-1234')); + + await waitFor(() => { + expect(navigateToCaseView).toHaveBeenCalledWith({ detailName: '1234', tabId: 'alerts' }); + }); }); }); @@ -297,20 +585,8 @@ describe('createCommentUserActionBuilder', () => { const result = appMockRender.render(); expect(result.getByTestId('comment-externalReference-.test')).toBeInTheDocument(); - expect(result.getByTestId('property-actions')).toBeInTheDocument(); - userEvent.click(result.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - - expect(result.queryByTestId('property-actions-trash')).toBeInTheDocument(); - - userEvent.click(result.getByTestId('property-actions-trash')); - - await waitFor(() => { - expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); - }); - - userEvent.click(result.getByText('Delete')); + await deleteAttachment(result, 'trash', 'Delete'); await waitFor(() => { expect(builderArgs.handleDeleteComment).toHaveBeenCalledWith( @@ -480,20 +756,8 @@ describe('createCommentUserActionBuilder', () => { const result = appMockRender.render(); expect(result.getByTestId('comment-persistableState-.test')).toBeInTheDocument(); - expect(result.getByTestId('property-actions')).toBeInTheDocument(); - - userEvent.click(result.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - - expect(result.queryByTestId('property-actions-trash')).toBeInTheDocument(); - userEvent.click(result.getByTestId('property-actions-trash')); - - await waitFor(() => { - expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); - }); - - userEvent.click(result.getByText('Delete')); + await deleteAttachment(result, 'trash', 'Delete'); await waitFor(() => { expect(builderArgs.handleDeleteComment).toHaveBeenCalledWith( @@ -503,3 +767,20 @@ describe('createCommentUserActionBuilder', () => { }); }); }); + +const deleteAttachment = async (result: RenderResult, deleteIcon: string, buttonLabel: string) => { + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId(`property-actions-${deleteIcon}`)).toBeInTheDocument(); + + userEvent.click(result.getByTestId(`property-actions-${deleteIcon}`)); + + await waitFor(() => { + expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + }); + + userEvent.click(result.getByText(buttonLabel)); +}; diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx index 4e2ecb85e22ba..0de6fcb91a5e8 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx @@ -12,7 +12,7 @@ import { Actions, CommentType } from '../../../../common/api'; import type { UserActionBuilder, UserActionBuilderArgs, UserActionResponse } from '../types'; import { createCommonUpdateUserActionBuilder } from '../common'; import type { Comment } from '../../../containers/types'; -import * as i18n from '../translations'; +import * as i18n from './translations'; import { createUserAttachmentUserActionBuilder } from './user'; import { createAlertAttachmentUserActionBuilder } from './alert'; import { createActionAttachmentUserActionBuilder } from './actions'; @@ -20,7 +20,25 @@ import { createExternalReferenceAttachmentUserActionBuilder } from './external_r import { createPersistableStateAttachmentUserActionBuilder } from './persistable_state'; const getUpdateLabelTitle = () => `${i18n.EDITED_FIELD} ${i18n.COMMENT.toLowerCase()}`; -const getDeleteLabelTitle = () => `${i18n.REMOVED_FIELD} ${i18n.COMMENT.toLowerCase()}`; +const getDeleteLabelTitle = (userAction: UserActionResponse) => { + const { comment } = userAction.payload; + + if (comment.type === CommentType.alert) { + const totalAlerts = Array.isArray(comment.alertId) ? comment.alertId.length : 1; + const alertLabel = i18n.MULTIPLE_ALERTS(totalAlerts); + + return `${i18n.REMOVED_FIELD} ${alertLabel}`; + } + + if ( + comment.type === CommentType.externalReference || + comment.type === CommentType.persistableState + ) { + return `${i18n.REMOVED_FIELD} ${i18n.ATTACHMENT.toLowerCase()}`; + } + + return `${i18n.REMOVED_FIELD} ${i18n.COMMENT.toLowerCase()}`; +}; const getDeleteCommentUserAction = ({ userAction, @@ -29,7 +47,7 @@ const getDeleteCommentUserAction = ({ }: { userAction: UserActionResponse; } & Pick): EuiCommentProps[] => { - const label = getDeleteLabelTitle(); + const label = getDeleteLabelTitle(userAction); const commonBuilder = createCommonUpdateUserActionBuilder({ userAction, userProfiles, @@ -96,6 +114,8 @@ const getCreateCommentUserAction = ({ loadingAlertData, onRuleDetailsClick, onShowAlertDetails, + handleDeleteComment, + loadingCommentIds, }); return alertBuilder.build(); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx index fc2c24f225898..da20f4c4cefc3 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.tsx @@ -23,8 +23,8 @@ import { UserActionTimestamp } from '../timestamp'; import type { SnakeToCamelCase } from '../../../../common/types'; import { ATTACHMENT_NOT_REGISTERED_ERROR, DEFAULT_EVENT_ATTACHMENT_TITLE } from './translations'; import { UserActionContentToolbar } from '../content_toolbar'; -import * as i18n from '../translations'; import { HoverableUserWithAvatarResolver } from '../../user_profiles/hoverable_user_with_avatar_resolver'; +import { RegisteredAttachmentsPropertyActions } from '../property_actions/registered_attachments_property_actions'; type BuilderArgs = Pick< UserActionBuilderArgs, @@ -123,17 +123,13 @@ export const createRegisteredAttachmentUserActionBuilder = < timestamp: , timelineAvatar: attachmentViewObject.timelineAvatar, actions: ( - <> - + {attachmentViewObject.actions} + handleDeleteComment(comment.id)} - extraActions={attachmentViewObject.actions} /> - + ), children: renderer(props), }, diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx index 5506cbd5d7d00..48a6bff3fd557 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx @@ -26,6 +26,7 @@ const UserActionShowAlertComponent = ({ () => onShowAlertDetails(alertId, index), [alertId, index, onShowAlertDetails] ); + return ( {i18n.SHOW_ALERT_TOOLTIP}

    }> + i18n.translate('xpack.cases.caseView.alerts.multipleAlerts', { + values: { totalAlerts }, + defaultMessage: + '{totalAlerts, plural, =1 {one} other {{totalAlerts}}} {totalAlerts, plural, =1 {alert} other {alerts}}', + }); + +export const ATTACHMENT = i18n.translate('xpack.cases.userActions.attachment', { + defaultMessage: 'Attachment', +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/user.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/user.tsx index 91df42cee7e4e..5331b215d1880 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/user.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/user.tsx @@ -13,10 +13,10 @@ import { UserActionTimestamp } from '../timestamp'; import type { SnakeToCamelCase } from '../../../../common/types'; import { UserActionMarkdown } from '../markdown_form'; import { UserActionContentToolbar } from '../content_toolbar'; -import * as i18n from '../translations'; import type { UserActionBuilderArgs, UserActionBuilder } from '../types'; import { HoverableUsernameResolver } from '../../user_profiles/hoverable_username_resolver'; import { HoverableAvatarResolver } from '../../user_profiles/hoverable_avatar_resolver'; +import { UserCommentPropertyActions } from '../property_actions/user_comment_property_actions'; type BuilderArgs = Pick< UserActionBuilderArgs, @@ -76,18 +76,15 @@ export const createUserAttachmentUserActionBuilder = ({ ), actions: ( - + + handleManageMarkdownEditId(comment.id)} + onDelete={() => handleDeleteComment(comment.id)} + onQuote={() => handleManageQuote(comment.id)} + /> + ), }, ], diff --git a/x-pack/plugins/cases/public/components/user_actions/content_toolbar.test.tsx b/x-pack/plugins/cases/public/components/user_actions/content_toolbar.test.tsx index bc8d79b25e4e6..79e3e256d3deb 100644 --- a/x-pack/plugins/cases/public/components/user_actions/content_toolbar.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/content_toolbar.test.tsx @@ -6,38 +6,26 @@ */ import React from 'react'; -import type { ReactWrapper } from 'enzyme'; -import { mount } from 'enzyme'; -import type { UserActionContentToolbarProps } from './content_toolbar'; import { UserActionContentToolbar } from './content_toolbar'; -import { TestProviders } from '../../common/mock'; +import type { AppMockRenderer } from '../../common/mock'; +import { createAppMockRenderer } from '../../common/mock'; jest.mock('../../common/navigation/hooks'); jest.mock('../../common/lib/kibana'); -const props: UserActionContentToolbarProps = { - commentMarkdown: '', - id: '1', - editLabel: 'edit', - quoteLabel: 'quote', - isLoading: false, - onEdit: jest.fn(), - onQuote: jest.fn(), -}; - describe('UserActionContentToolbar ', () => { - let wrapper: ReactWrapper; + let appMockRenderer: AppMockRenderer; - beforeAll(() => { - wrapper = mount( - - - - ); + beforeEach(() => { + appMockRenderer = createAppMockRenderer(); }); - it('it renders', async () => { - expect(wrapper.find(`[data-test-subj="copy-link-${props.id}"]`).first().exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="property-actions"]').first().exists()).toBeTruthy(); + it('renders', async () => { + const res = appMockRenderer.render( + {'My children'} + ); + + res.getByTestId('copy-link-1'); + res.getByText('My children'); }); }); diff --git a/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx b/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx index a37f2f894608b..e7d1dd7ba5eaa 100644 --- a/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx @@ -6,64 +6,31 @@ */ import React, { memo } from 'react'; -import type { EuiCommentProps } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { UserActionCopyLink } from './copy_link'; -import type { Actions } from './property_actions'; -import { UserActionPropertyActions } from './property_actions'; export interface UserActionContentToolbarProps { - commentMarkdown?: string; id: string; - actions?: Actions; - editLabel?: string; - deleteLabel?: string; - deleteConfirmTitle?: string; - quoteLabel?: string; - isLoading: boolean; - extraActions?: EuiCommentProps['actions']; - onEdit?: (id: string) => void; - onQuote?: (id: string) => void; - onDelete?: (id: string) => void; + children: React.ReactNode; + withCopyLinkAction?: boolean; } -const UserActionContentToolbarComponent = ({ - commentMarkdown, +const UserActionContentToolbarComponent: React.FC = ({ id, - actions, - editLabel, - deleteLabel, - deleteConfirmTitle, - quoteLabel, - isLoading, - extraActions, - onEdit, - onQuote, - onDelete, -}: UserActionContentToolbarProps) => ( + withCopyLinkAction = true, + children, +}) => ( - - - - - - - {extraActions != null ? {extraActions} : null} + {withCopyLinkAction ? ( + + + + ) : null} + {children} ); + UserActionContentToolbarComponent.displayName = 'UserActionContentToolbar'; export const UserActionContentToolbar = memo(UserActionContentToolbarComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/delete_attachment_confirmation_modal.test.tsx b/x-pack/plugins/cases/public/components/user_actions/delete_attachment_confirmation_modal.test.tsx new file mode 100644 index 0000000000000..b4e53e21a0df9 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/delete_attachment_confirmation_modal.test.tsx @@ -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 userEvent from '@testing-library/user-event'; +import React from 'react'; +import type { AppMockRenderer } from '../../common/mock'; +import { createAppMockRenderer } from '../../common/mock'; +import { DeleteAttachmentConfirmationModal } from './delete_attachment_confirmation_modal'; + +describe('DeleteAttachmentConfirmationModal', () => { + let appMock: AppMockRenderer; + const props = { + title: 'My title', + confirmButtonText: 'My button text', + onCancel: jest.fn(), + onConfirm: jest.fn(), + }; + + beforeEach(() => { + appMock = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + expect(result.getByText('My title')).toBeInTheDocument(); + expect(result.getByText('My button text')).toBeInTheDocument(); + expect(result.getByText('Cancel')).toBeInTheDocument(); + }); + + it('calls onConfirm', async () => { + const result = appMock.render(); + + expect(result.getByText('My button text')).toBeInTheDocument(); + userEvent.click(result.getByText('My button text')); + + expect(props.onConfirm).toHaveBeenCalled(); + }); + + it('calls onCancel', async () => { + const result = appMock.render(); + + expect(result.getByText('Cancel')).toBeInTheDocument(); + userEvent.click(result.getByText('Cancel')); + + expect(props.onCancel).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/delete_attachment_confirmation_modal.tsx b/x-pack/plugins/cases/public/components/user_actions/delete_attachment_confirmation_modal.tsx new file mode 100644 index 0000000000000..be97b65669287 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/delete_attachment_confirmation_modal.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { EuiConfirmModalProps } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; +import { CANCEL_BUTTON } from './property_actions/translations'; + +type Pros = Pick; + +const DeleteAttachmentConfirmationModalComponent: React.FC = ({ + title, + confirmButtonText, + onConfirm, + onCancel, +}) => { + return ( + + ); +}; + +DeleteAttachmentConfirmationModalComponent.displayName = 'DeleteAttachmentConfirmationModal'; + +export const DeleteAttachmentConfirmationModal = React.memo( + DeleteAttachmentConfirmationModalComponent +); diff --git a/x-pack/plugins/cases/public/components/user_actions/description.test.tsx b/x-pack/plugins/cases/public/components/user_actions/description.test.tsx index d76829add5a63..9fddcbb3cce6a 100644 --- a/x-pack/plugins/cases/public/components/user_actions/description.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/description.test.tsx @@ -7,24 +7,96 @@ import React from 'react'; import { EuiCommentList } from '@elastic/eui'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { Actions } from '../../../common/api'; import { getUserAction } from '../../containers/mock'; import { TestProviders } from '../../common/mock'; -import { createDescriptionUserActionBuilder } from './description'; +import { createDescriptionUserActionBuilder, getDescriptionUserAction } from './description'; import { getMockBuilderArgs } from './mock'; +import userEvent from '@testing-library/user-event'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; jest.mock('../../common/lib/kibana'); jest.mock('../../common/navigation/hooks'); describe('createDescriptionUserActionBuilder ', () => { + const onUpdateField = jest.fn(); const builderArgs = getMockBuilderArgs(); beforeEach(() => { jest.clearAllMocks(); }); + it('renders correctly description', async () => { + const descriptionUserAction = getDescriptionUserAction({ + ...builderArgs, + onUpdateField, + isLoadingDescription: false, + }); + + render( + + + + ); + + expect(screen.getByText('added description')).toBeInTheDocument(); + expect(screen.getByText('Security banana Issue')).toBeInTheDocument(); + }); + + it('edits the description correctly', async () => { + const descriptionUserAction = getDescriptionUserAction({ + ...builderArgs, + onUpdateField, + isLoadingDescription: false, + }); + + const res = render( + + + + ); + + expect(res.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(res.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(res.queryByTestId('property-actions-pencil')).toBeInTheDocument(); + userEvent.click(res.getByTestId('property-actions-pencil')); + + await waitFor(() => { + expect(builderArgs.handleManageMarkdownEditId).toHaveBeenCalledWith('description'); + }); + }); + + it('quotes the description correctly', async () => { + const descriptionUserAction = getDescriptionUserAction({ + ...builderArgs, + onUpdateField, + isLoadingDescription: false, + }); + + const res = render( + + + + ); + + expect(res.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(res.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(res.queryByTestId('property-actions-quote')).toBeInTheDocument(); + userEvent.click(res.getByTestId('property-actions-quote')); + + await waitFor(() => { + expect(builderArgs.handleManageQuote).toHaveBeenCalledWith('Security banana Issue'); + }); + }); + it('renders correctly when editing a description', async () => { const userAction = getUserAction('description', Actions.update); const builder = createDescriptionUserActionBuilder({ diff --git a/x-pack/plugins/cases/public/components/user_actions/description.tsx b/x-pack/plugins/cases/public/components/user_actions/description.tsx index d37992577aeb8..19874dc05f2d0 100644 --- a/x-pack/plugins/cases/public/components/user_actions/description.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/description.tsx @@ -17,6 +17,7 @@ import { UserActionMarkdown } from './markdown_form'; import * as i18n from './translations'; import { HoverableAvatarResolver } from '../user_profiles/hoverable_avatar_resolver'; import { HoverableUsernameResolver } from '../user_profiles/hoverable_username_resolver'; +import { DescriptionPropertyActions } from './property_actions/description_property_actions'; const DESCRIPTION_ID = 'description'; @@ -69,15 +70,13 @@ export const getDescriptionUserAction = ({ isEdit: manageMarkdownEditIds.includes(DESCRIPTION_ID), }), actions: ( - + + handleManageMarkdownEditId(DESCRIPTION_ID)} + onQuote={() => handleManageQuote(caseData.description)} + /> + ), }; }; diff --git a/x-pack/plugins/cases/public/components/user_actions/index.test.tsx b/x-pack/plugins/cases/public/components/user_actions/index.test.tsx index 3566de547d354..1a643234d3456 100644 --- a/x-pack/plugins/cases/public/components/user_actions/index.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/index.test.tsx @@ -18,7 +18,6 @@ import { getUserAction, getHostIsolationUserAction, hostIsolationComment, - hostReleaseComment, } from '../../containers/mock'; import { UserActions } from '.'; import type { AppMockRenderer } from '../../common/mock'; @@ -424,45 +423,5 @@ describe(`UserActions`, () => { expect(screen.getByText('DR')).toBeInTheDocument(); expect(screen.getByText('Damaged Raccoon')).toBeInTheDocument(); }); - - it('shows a lock icon if the action is isolate', async () => { - const isolateAction = [getHostIsolationUserAction()]; - const props = { - ...defaultProps, - caseUserActions: isolateAction, - data: { ...defaultProps.data, comments: [hostIsolationComment()] }, - }; - - const wrapper = mount( - - - - ); - await waitFor(() => { - expect( - wrapper.find(`[data-test-subj="endpoint-action-icon"]`).first().prop('iconType') - ).toBe('lock'); - }); - }); - - it('shows a lockOpen icon if the action is unisolate/release', async () => { - const isolateAction = [getHostIsolationUserAction()]; - const props = { - ...defaultProps, - caseUserActions: isolateAction, - data: { ...defaultProps.data, comments: [hostReleaseComment()] }, - }; - - const wrapper = mount( - - - - ); - await waitFor(() => { - expect( - wrapper.find(`[data-test-subj="endpoint-action-icon"]`).first().prop('iconType') - ).toBe('lockOpen'); - }); - }); }); }); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions.test.tsx deleted file mode 100644 index 75d2b3027f37b..0000000000000 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions.test.tsx +++ /dev/null @@ -1,251 +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 type { UserActionPropertyActionsProps } from './property_actions'; -import { UserActionPropertyActions } from './property_actions'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; -import { - noCreateCasesPermissions, - noDeleteCasesPermissions, - noUpdateCasesPermissions, - TestProviders, -} from '../../common/mock'; - -jest.mock('../../common/lib/kibana'); - -const onEdit = jest.fn(); -const onQuote = jest.fn(); -const props = { - commentMarkdown: '', - id: 'property-actions-id', - editLabel: 'edit', - quoteLabel: 'quote', - disabled: false, - isLoading: false, - onEdit, - onQuote, -}; - -describe('UserActionPropertyActions ', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('renders', async () => { - render( - - - - ); - - expect(screen.queryByTestId('user-action-title-loading')).not.toBeInTheDocument(); - expect(screen.getByTestId('property-actions')).toBeInTheDocument(); - }); - - it('shows the edit and quote buttons', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - expect(screen.getByTestId('property-actions-pencil')).toBeInTheDocument(); - expect(screen.getByTestId('property-actions-quote')).toBeInTheDocument(); - }); - - it('quote click calls onQuote', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - userEvent.click(renderResult.getByTestId('property-actions-quote')); - - expect(onQuote).toHaveBeenCalledWith(props.id); - }); - - it('pencil click calls onEdit', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - userEvent.click(renderResult.getByTestId('property-actions-pencil')); - expect(onEdit).toHaveBeenCalledWith(props.id); - }); - - it('shows the spinner when loading', async () => { - render( - - - - ); - expect(screen.getByTestId('user-action-title-loading')).toBeInTheDocument(); - expect(screen.queryByTestId('property-actions')).not.toBeInTheDocument(); - }); - - describe('deletion props', () => { - let onDelete: jest.Mock; - let deleteProps: UserActionPropertyActionsProps; - - beforeEach(() => { - jest.clearAllMocks(); - - onDelete = jest.fn(); - deleteProps = { - ...props, - onDelete, - deleteLabel: 'delete me', - deleteConfirmTitle: 'confirm delete me', - }; - }); - - it('does not show the delete icon when the user does not have delete permissions', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - expect(renderResult.queryByTestId('property-actions-trash')).not.toBeInTheDocument(); - expect(renderResult.queryByTestId('property-actions-pencil')).toBeInTheDocument(); - expect(renderResult.queryByTestId('property-actions-quote')).toBeInTheDocument(); - }); - - it('does not show the pencil icon when the user does not have update permissions', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - expect(renderResult.queryByTestId('property-actions-trash')).toBeInTheDocument(); - expect(renderResult.queryByTestId('property-actions-pencil')).not.toBeInTheDocument(); - expect(renderResult.queryByTestId('property-actions-quote')).toBeInTheDocument(); - }); - - it('does not show the quote icon when the user does not have create permissions', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - expect(renderResult.queryByTestId('property-actions-trash')).toBeInTheDocument(); - expect(renderResult.queryByTestId('property-actions-pencil')).toBeInTheDocument(); - expect(renderResult.queryByTestId('property-actions-quote')).not.toBeInTheDocument(); - }); - - it('shows the delete button', () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - expect(renderResult.getByTestId('property-actions-trash')).toBeTruthy(); - }); - - it('shows a confirm dialog when the delete button is clicked', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - userEvent.click(renderResult.getByTestId('property-actions-trash')); - - expect(renderResult.getByTestId('property-actions-confirm-modal')).toBeTruthy(); - }); - - it('closes the confirm dialog when the cancel button is clicked', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - userEvent.click(renderResult.getByTestId('property-actions-trash')); - expect(renderResult.getByTestId('property-actions-confirm-modal')).toBeTruthy(); - - userEvent.click(renderResult.getByTestId('confirmModalCancelButton')); - expect(renderResult.queryByTestId('property-actions-confirm-modal')).toBe(null); - }); - - it('calls onDelete when the confirm is pressed', async () => { - const renderResult = render( - - - - ); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - userEvent.click(renderResult.getByTestId('property-actions-trash')); - expect(renderResult.getByTestId('property-actions-confirm-modal')).toBeTruthy(); - - userEvent.click(renderResult.getByTestId('confirmModalConfirmButton')); - expect(onDelete).toHaveBeenCalledWith(deleteProps.id); - }); - }); - - describe('action filtering', () => { - const tests = [ - ['edit', 'pencil'], - ['delete', 'trash'], - ['quote', 'quote'], - ] as const; - - it.each(tests)('renders action %s', async (action, type) => { - const renderResult = render( - - {}} - deleteLabel={'test'} - actions={[action]} - /> - - ); - - expect(renderResult.queryByTestId('user-action-title-loading')).not.toBeInTheDocument(); - expect(renderResult.getByTestId('property-actions')).toBeInTheDocument(); - - userEvent.click(renderResult.getByTestId('property-actions-ellipses')); - await waitForEuiPopoverOpen(); - - expect(renderResult.queryByTestId(`property-actions-${type}`)).toBeInTheDocument(); - /** - * This check ensures that no other action is rendered. There is - * one button to open the popover and one button for the action - **/ - expect(await renderResult.findAllByRole('button')).toHaveLength(2); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions.tsx deleted file mode 100644 index 132b824109e51..0000000000000 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions.tsx +++ /dev/null @@ -1,164 +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'; -import React, { memo, useMemo, useCallback, useState } from 'react'; -import { EuiConfirmModal, EuiLoadingSpinner } from '@elastic/eui'; - -import { PropertyActions } from '../property_actions'; -import { useLensOpenVisualization } from '../markdown_editor/plugins/lens/use_lens_open_visualization'; -import { CANCEL_BUTTON, CONFIRM_BUTTON } from './translations'; -import { useCasesContext } from '../cases_context/use_cases_context'; - -const totalActions = { - edit: 'edit', - delete: 'delete', - quote: 'quote', - showLensEditor: 'showLensEditor', -} as const; - -const availableActions = Object.keys(totalActions) as Array; - -export type Actions = typeof availableActions; - -export interface UserActionPropertyActionsProps { - id: string; - actions?: Actions; - editLabel?: string; - deleteLabel?: string; - deleteConfirmTitle?: string; - quoteLabel?: string; - isLoading: boolean; - onEdit?: (id: string) => void; - onDelete?: (id: string) => void; - onQuote?: (id: string) => void; - commentMarkdown?: string; -} - -const UserActionPropertyActionsComponent = ({ - id, - actions = availableActions, - editLabel = '', - quoteLabel = '', - deleteLabel = '', - deleteConfirmTitle, - isLoading, - onEdit = noop, - onDelete, - onQuote = noop, - commentMarkdown, -}: UserActionPropertyActionsProps) => { - const { permissions } = useCasesContext(); - const { canUseEditor, actionConfig } = useLensOpenVisualization({ - comment: commentMarkdown ?? '', - }); - const onEditClick = useCallback(() => onEdit(id), [id, onEdit]); - const onQuoteClick = useCallback(() => onQuote(id), [id, onQuote]); - const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); - - const onDeleteClick = useCallback(() => { - setShowDeleteConfirm(true); - }, []); - - const onDeleteConfirmClick = useCallback(() => { - if (onDelete) { - onDelete(id); - } - setShowDeleteConfirm(false); - }, [id, onDelete]); - - const onDeleteCancelClick = useCallback(() => { - setShowDeleteConfirm(false); - }, []); - - const propertyActions = useMemo(() => { - const showEditPencilIcon = permissions.update && actions.includes(totalActions.edit); - - const showTrashIcon = Boolean( - permissions.delete && deleteLabel && onDelete && actions.includes(totalActions.delete) - ); - - const showQuoteIcon = permissions.create && actions.includes(totalActions.quote); - - const showLensEditor = - permissions.update && - canUseEditor && - actionConfig && - actions.includes(totalActions.showLensEditor); - - return [ - ...(showEditPencilIcon - ? [ - { - iconType: 'pencil', - label: editLabel, - onClick: onEditClick, - }, - ] - : []), - ...(showTrashIcon - ? [ - { - iconType: 'trash', - label: deleteLabel, - onClick: onDeleteClick, - }, - ] - : []), - ...(showQuoteIcon - ? [ - { - iconType: 'quote', - label: quoteLabel, - onClick: onQuoteClick, - }, - ] - : []), - ...(showLensEditor ? [actionConfig] : []), - ]; - }, [ - permissions.update, - permissions.delete, - permissions.create, - actions, - deleteLabel, - onDelete, - canUseEditor, - actionConfig, - editLabel, - onEditClick, - onDeleteClick, - quoteLabel, - onQuoteClick, - ]); - - if (!propertyActions.length) { - return null; - } - - return ( - <> - {isLoading && } - {!isLoading && } - {showDeleteConfirm ? ( - - ) : null} - - ); -}; -UserActionPropertyActionsComponent.displayName = 'UserActionPropertyActions'; - -export const UserActionPropertyActions = memo(UserActionPropertyActionsComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.test.tsx new file mode 100644 index 0000000000000..dc8a57b8477f6 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.test.tsx @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import { waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import type { AppMockRenderer } from '../../../common/mock'; +import { + noCasesPermissions, + onlyDeleteCasesPermission, + createAppMockRenderer, +} from '../../../common/mock'; +import { AlertPropertyActions } from './alert_property_actions'; + +describe('AlertPropertyActions', () => { + let appMock: AppMockRenderer; + + const props = { + isLoading: false, + totalAlerts: 1, + onDelete: jest.fn(), + }; + + beforeEach(() => { + appMock = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders the correct number of actions', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.getByTestId('property-actions-group').children.length).toBe(1); + expect(result.queryByTestId('property-actions-minusInCircle')).toBeInTheDocument(); + }); + + it('renders the modal info correctly for one alert', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-minusInCircle')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-minusInCircle')); + + await waitFor(() => { + expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + }); + + expect(result.getByTestId('confirmModalTitleText')).toHaveTextContent('Remove alert'); + expect(result.getByText('Remove')).toBeInTheDocument(); + }); + + it('renders the modal info correctly for multiple alert', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-minusInCircle')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-minusInCircle')); + + await waitFor(() => { + expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + }); + + expect(result.getByTestId('confirmModalTitleText')).toHaveTextContent('Remove alerts'); + expect(result.getByText('Remove')).toBeInTheDocument(); + }); + + it('remove alerts correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-minusInCircle')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-minusInCircle')); + + await waitFor(() => { + expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + }); + + userEvent.click(result.getByText('Remove')); + expect(props.onDelete).toHaveBeenCalled(); + }); + + it('does not show the property actions without delete permissions', async () => { + appMock = createAppMockRenderer({ permissions: noCasesPermissions() }); + const result = appMock.render(); + + expect(result.queryByTestId('property-actions')).not.toBeInTheDocument(); + }); + + it('does show the property actions with only delete permissions', async () => { + appMock = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.tsx new file mode 100644 index 0000000000000..0acafdcfa8d60 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { useCasesContext } from '../../cases_context/use_cases_context'; +import { DeleteAttachmentConfirmationModal } from '../delete_attachment_confirmation_modal'; +import { UserActionPropertyActions } from './property_actions'; +import * as i18n from './translations'; +import { useDeletePropertyAction } from './use_delete_property_action'; + +interface Props { + isLoading: boolean; + totalAlerts: number; + onDelete: () => void; +} + +const AlertPropertyActionsComponent: React.FC = ({ isLoading, totalAlerts, onDelete }) => { + const { permissions } = useCasesContext(); + const { showDeletionModal, onModalOpen, onConfirm, onCancel } = useDeletePropertyAction({ + onDelete, + }); + + const propertyActions = useMemo(() => { + const showRemoveAlertIcon = permissions.delete; + + return [ + ...(showRemoveAlertIcon + ? [ + { + iconType: 'minusInCircle', + label: i18n.REMOVE_ALERTS(totalAlerts), + onClick: onModalOpen, + }, + ] + : []), + ]; + }, [permissions.delete, totalAlerts, onModalOpen]); + + return ( + <> + + {showDeletionModal ? ( + + ) : null} + + ); +}; + +AlertPropertyActionsComponent.displayName = 'AlertPropertyActions'; + +export const AlertPropertyActions = React.memo(AlertPropertyActionsComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/description_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/description_property_actions.test.tsx new file mode 100644 index 0000000000000..bfaa349caf46f --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/description_property_actions.test.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 React from 'react'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import userEvent from '@testing-library/user-event'; +import type { AppMockRenderer } from '../../../common/mock'; +import { createAppMockRenderer, noCasesPermissions } from '../../../common/mock'; +import { DescriptionPropertyActions } from './description_property_actions'; + +describe('DescriptionPropertyActions', () => { + let appMock: AppMockRenderer; + + const props = { + isLoading: false, + onEdit: jest.fn(), + onQuote: jest.fn(), + }; + + beforeEach(() => { + appMock = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders the correct number of actions', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.getByTestId('property-actions-group').children.length).toBe(2); + expect(result.queryByTestId('property-actions-pencil')).toBeInTheDocument(); + expect(result.queryByTestId('property-actions-quote')).toBeInTheDocument(); + }); + + it('edits the description correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-pencil')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-pencil')); + + expect(props.onEdit).toHaveBeenCalled(); + }); + + it('quotes the description correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-quote')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-quote')); + + expect(props.onQuote).toHaveBeenCalled(); + }); + + it('does not show the property actions without permissions', async () => { + appMock = createAppMockRenderer({ permissions: noCasesPermissions() }); + const result = appMock.render(); + + expect(result.queryByTestId('property-actions')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/description_property_actions.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/description_property_actions.tsx new file mode 100644 index 0000000000000..5ef72a5590140 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/description_property_actions.tsx @@ -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 React, { useMemo } from 'react'; +import { useCasesContext } from '../../cases_context/use_cases_context'; +import * as i18n from './translations'; +import { UserActionPropertyActions } from './property_actions'; + +interface Props { + isLoading: boolean; + onEdit: () => void; + onQuote: () => void; +} + +const DescriptionPropertyActionsComponent: React.FC = ({ isLoading, onEdit, onQuote }) => { + const { permissions } = useCasesContext(); + + const propertyActions = useMemo(() => { + const showEditPencilIcon = permissions.update; + const showQuoteIcon = permissions.create; + + return [ + ...(showEditPencilIcon + ? [ + { + iconType: 'pencil', + label: i18n.EDIT_DESCRIPTION, + onClick: onEdit, + }, + ] + : []), + ...(showQuoteIcon + ? [ + { + iconType: 'quote', + label: i18n.QUOTE, + onClick: onQuote, + }, + ] + : []), + ]; + }, [permissions.update, permissions.create, onEdit, onQuote]); + + return ; +}; + +DescriptionPropertyActionsComponent.displayName = 'DescriptionPropertyActions'; + +export const DescriptionPropertyActions = React.memo(DescriptionPropertyActionsComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/property_actions.test.tsx new file mode 100644 index 0000000000000..c7cfdb25bb359 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/property_actions.test.tsx @@ -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 React from 'react'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import userEvent from '@testing-library/user-event'; +import type { AppMockRenderer } from '../../../common/mock'; +import { createAppMockRenderer } from '../../../common/mock'; +import { UserActionPropertyActions } from './property_actions'; + +describe('UserActionPropertyActions', () => { + let appMock: AppMockRenderer; + const onClick = jest.fn(); + + const props = { + isLoading: false, + propertyActions: [ + { + iconType: 'pencil', + label: 'Edit', + onClick, + }, + ], + }; + + beforeEach(() => { + appMock = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders the loading spinner correctly when loading', async () => { + const result = appMock.render(); + + expect(result.getByTestId('user-action-title-loading')).toBeInTheDocument(); + expect(result.queryByTestId('property-actions')).not.toBeInTheDocument(); + }); + + it('renders the property actions', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.getByTestId('property-actions-group').children.length).toBe(1); + expect(result.queryByTestId('property-actions-pencil')).toBeInTheDocument(); + }); + + it('does not render if properties are empty', async () => { + const result = appMock.render( + + ); + + expect(result.queryByTestId('property-actions')).not.toBeInTheDocument(); + expect(result.queryByTestId('user-action-title-loading')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/property_actions.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/property_actions.tsx new file mode 100644 index 0000000000000..abf897404711a --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/property_actions.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import React from 'react'; +import type { PropertyActionButtonProps } from '../../property_actions'; +import { PropertyActions } from '../../property_actions'; + +interface Props { + isLoading: boolean; + propertyActions: PropertyActionButtonProps[]; +} + +const UserActionPropertyActionsComponent: React.FC = ({ isLoading, propertyActions }) => { + if (propertyActions.length === 0) { + return null; + } + + return ( + + {isLoading ? ( + + ) : ( + + )} + + ); +}; + +UserActionPropertyActionsComponent.displayName = 'UserActionPropertyActions'; + +export const UserActionPropertyActions = React.memo(UserActionPropertyActionsComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx new file mode 100644 index 0000000000000..a756f43893e03 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx @@ -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 React from 'react'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import { waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import type { AppMockRenderer } from '../../../common/mock'; +import { + noCasesPermissions, + onlyDeleteCasesPermission, + createAppMockRenderer, +} from '../../../common/mock'; +import { RegisteredAttachmentsPropertyActions } from './registered_attachments_property_actions'; + +describe('RegisteredAttachmentsPropertyActions', () => { + let appMock: AppMockRenderer; + + const props = { + isLoading: false, + onDelete: jest.fn(), + }; + + beforeEach(() => { + appMock = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders the correct number of actions', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.getByTestId('property-actions-group').children.length).toBe(1); + expect(result.queryByTestId('property-actions-trash')).toBeInTheDocument(); + }); + + it('renders the modal info correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-trash')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-trash')); + + await waitFor(() => { + expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + }); + + expect(result.getByTestId('confirmModalTitleText')).toHaveTextContent('Delete attachment'); + expect(result.getByText('Delete')).toBeInTheDocument(); + }); + + it('remove attachments correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-trash')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-trash')); + + await waitFor(() => { + expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + }); + + userEvent.click(result.getByText('Delete')); + expect(props.onDelete).toHaveBeenCalled(); + }); + + it('does not show the property actions without delete permissions', async () => { + appMock = createAppMockRenderer({ permissions: noCasesPermissions() }); + const result = appMock.render(); + + expect(result.queryByTestId('property-actions')).not.toBeInTheDocument(); + }); + + it('does show the property actions with only delete permissions', async () => { + appMock = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.tsx new file mode 100644 index 0000000000000..28d82525246f5 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.tsx @@ -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 React, { useMemo } from 'react'; +import { useCasesContext } from '../../cases_context/use_cases_context'; +import * as i18n from './translations'; +import { UserActionPropertyActions } from './property_actions'; +import { DeleteAttachmentConfirmationModal } from '../delete_attachment_confirmation_modal'; +import { useDeletePropertyAction } from './use_delete_property_action'; + +interface Props { + isLoading: boolean; + onDelete: () => void; +} + +const RegisteredAttachmentsPropertyActionsComponent: React.FC = ({ + isLoading, + onDelete, +}) => { + const { permissions } = useCasesContext(); + const { showDeletionModal, onModalOpen, onConfirm, onCancel } = useDeletePropertyAction({ + onDelete, + }); + + const propertyActions = useMemo(() => { + const showTrashIcon = permissions.delete; + + return [ + ...(showTrashIcon + ? [ + { + iconType: 'trash', + label: i18n.DELETE_ATTACHMENT, + onClick: onModalOpen, + }, + ] + : []), + ]; + }, [permissions.delete, onModalOpen]); + + return ( + <> + + {showDeletionModal ? ( + + ) : null} + + ); +}; + +RegisteredAttachmentsPropertyActionsComponent.displayName = 'RegisteredAttachmentsPropertyActions'; + +export const RegisteredAttachmentsPropertyActions = React.memo( + RegisteredAttachmentsPropertyActionsComponent +); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/translations.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/translations.tsx new file mode 100644 index 0000000000000..fd54ac491bc7a --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/translations.tsx @@ -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 { i18n } from '@kbn/i18n'; +export * from '../translations'; + +export const DELETE_ATTACHMENT = i18n.translate('xpack.cases.userActions.deleteAttachment', { + defaultMessage: 'Delete attachment', +}); + +export const REMOVE_ALERTS = (totalAlerts: number): string => + i18n.translate('xpack.cases.caseView.alerts.removeAlerts', { + values: { totalAlerts }, + defaultMessage: 'Remove {totalAlerts, plural, =1 {alert} other {alerts}}', + }); + +export const REMOVE = i18n.translate('xpack.cases.caseView.alerts.remove', { + defaultMessage: 'Remove', +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.test.tsx new file mode 100644 index 0000000000000..2db865ee3b22b --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.test.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 { renderHook, act } from '@testing-library/react-hooks'; +import type { AppMockRenderer } from '../../../common/mock'; +import { createAppMockRenderer } from '../../../common/mock'; +import { useDeletePropertyAction } from './use_delete_property_action'; + +describe('UserActionPropertyActions', () => { + let appMockRender: AppMockRenderer; + const onDelete = jest.fn(); + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('init', async () => { + const { result } = renderHook(() => useDeletePropertyAction({ onDelete }), { + wrapper: appMockRender.AppWrapper, + }); + + expect(result.current.showDeletionModal).toBe(false); + }); + + it('opens the modal', async () => { + const { result } = renderHook(() => useDeletePropertyAction({ onDelete }), { + wrapper: appMockRender.AppWrapper, + }); + + act(() => { + result.current.onModalOpen(); + }); + + expect(result.current.showDeletionModal).toBe(true); + }); + + it('closes the modal', async () => { + const { result } = renderHook(() => useDeletePropertyAction({ onDelete }), { + wrapper: appMockRender.AppWrapper, + }); + + act(() => { + result.current.onModalOpen(); + }); + + expect(result.current.showDeletionModal).toBe(true); + + act(() => { + result.current.onCancel(); + }); + + expect(result.current.showDeletionModal).toBe(false); + }); + + it('calls onDelete on confirm', async () => { + const { result } = renderHook(() => useDeletePropertyAction({ onDelete }), { + wrapper: appMockRender.AppWrapper, + }); + + act(() => { + result.current.onModalOpen(); + }); + + expect(result.current.showDeletionModal).toBe(true); + + act(() => { + result.current.onConfirm(); + }); + + expect(result.current.showDeletionModal).toBe(false); + expect(onDelete).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.tsx new file mode 100644 index 0000000000000..4045beff6347d --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.tsx @@ -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, useState } from 'react'; + +interface Props { + onDelete: () => void; +} + +export const useDeletePropertyAction = ({ onDelete }: Props) => { + const [showDeletionModal, setShowDeletionModal] = useState(false); + + const onModalOpen = useCallback(() => { + setShowDeletionModal(true); + }, []); + + const onConfirm = useCallback(() => { + setShowDeletionModal(false); + onDelete(); + }, [onDelete]); + + const onCancel = useCallback(() => { + setShowDeletionModal(false); + }, []); + + return { showDeletionModal, onModalOpen, onConfirm, onCancel }; +}; diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.test.tsx new file mode 100644 index 0000000000000..557dae707c20f --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import userEvent from '@testing-library/user-event'; +import type { AppMockRenderer } from '../../../common/mock'; +import { + noCasesPermissions, + onlyDeleteCasesPermission, + createAppMockRenderer, +} from '../../../common/mock'; +import { UserCommentPropertyActions } from './user_comment_property_actions'; +import { waitFor } from '@testing-library/react'; + +describe('UserCommentPropertyActions', () => { + let appMock: AppMockRenderer; + + const props = { + isLoading: false, + onEdit: jest.fn(), + onQuote: jest.fn(), + onDelete: jest.fn(), + }; + + beforeEach(() => { + appMock = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders the correct number of actions', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.getByTestId('property-actions-group').children.length).toBe(3); + expect(result.queryByTestId('property-actions-pencil')).toBeInTheDocument(); + expect(result.queryByTestId('property-actions-trash')).toBeInTheDocument(); + expect(result.queryByTestId('property-actions-quote')).toBeInTheDocument(); + }); + + it('edits the comment correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-pencil')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-pencil')); + + expect(props.onEdit).toHaveBeenCalled(); + }); + + it('quotes the comment correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-quote')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-quote')); + + expect(props.onQuote).toHaveBeenCalled(); + }); + + it('deletes the comment correctly', async () => { + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-ellipses')); + await waitForEuiPopoverOpen(); + + expect(result.queryByTestId('property-actions-trash')).toBeInTheDocument(); + + userEvent.click(result.getByTestId('property-actions-trash')); + + await waitFor(() => { + expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + }); + + userEvent.click(result.getByText('Delete')); + expect(props.onDelete).toHaveBeenCalled(); + }); + + it('does not show the property actions without delete permissions', async () => { + appMock = createAppMockRenderer({ permissions: noCasesPermissions() }); + const result = appMock.render(); + + expect(result.queryByTestId('property-actions')).not.toBeInTheDocument(); + }); + + it('does show the property actions with only delete permissions', async () => { + appMock = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); + const result = appMock.render(); + + expect(result.getByTestId('property-actions')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.tsx new file mode 100644 index 0000000000000..90d16dfc2bf61 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { useCasesContext } from '../../cases_context/use_cases_context'; +import { useLensOpenVisualization } from '../../markdown_editor/plugins/lens/use_lens_open_visualization'; +import * as i18n from './translations'; +import { UserActionPropertyActions } from './property_actions'; +import { DeleteAttachmentConfirmationModal } from '../delete_attachment_confirmation_modal'; +import { useDeletePropertyAction } from './use_delete_property_action'; + +interface Props { + isLoading: boolean; + commentContent?: string; + onEdit: () => void; + onDelete: () => void; + onQuote: () => void; +} + +const UserCommentPropertyActionsComponent: React.FC = ({ + isLoading, + commentContent, + onEdit, + onDelete, + onQuote, +}) => { + const { permissions } = useCasesContext(); + const { showDeletionModal, onModalOpen, onConfirm, onCancel } = useDeletePropertyAction({ + onDelete, + }); + + const { canUseEditor, actionConfig } = useLensOpenVisualization({ + comment: commentContent ?? '', + }); + + const propertyActions = useMemo(() => { + const showEditPencilIcon = permissions.update; + const showTrashIcon = permissions.delete; + const showQuoteIcon = permissions.create; + + const showLensEditor = permissions.update && canUseEditor && actionConfig; + + return [ + ...(showEditPencilIcon + ? [ + { + iconType: 'pencil', + label: i18n.EDIT_COMMENT, + onClick: onEdit, + }, + ] + : []), + ...(showTrashIcon + ? [ + { + iconType: 'trash', + label: i18n.DELETE_COMMENT, + onClick: onModalOpen, + }, + ] + : []), + ...(showQuoteIcon + ? [ + { + iconType: 'quote', + label: i18n.QUOTE, + onClick: onQuote, + }, + ] + : []), + ...(showLensEditor ? [actionConfig] : []), + ]; + }, [ + permissions.update, + permissions.delete, + permissions.create, + canUseEditor, + actionConfig, + onEdit, + onModalOpen, + onQuote, + ]); + + return ( + <> + + {showDeletionModal ? ( + + ) : null} + + ); +}; + +UserCommentPropertyActionsComponent.displayName = 'UserCommentPropertyActions'; + +export const UserCommentPropertyActions = React.memo(UserCommentPropertyActionsComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/translations.ts b/x-pack/plugins/cases/public/components/user_actions/translations.ts index 91425c368286d..28531421c7703 100644 --- a/x-pack/plugins/cases/public/components/user_actions/translations.ts +++ b/x-pack/plugins/cases/public/components/user_actions/translations.ts @@ -75,7 +75,7 @@ export const CANCEL_BUTTON = i18n.translate('xpack.cases.caseView.delete.cancel' defaultMessage: 'Cancel', }); -export const CONFIRM_BUTTON = i18n.translate('xpack.cases.caseView.delete.confirm', { +export const DELETE = i18n.translate('xpack.cases.caseView.delete.confirm', { defaultMessage: 'Delete', }); diff --git a/x-pack/plugins/cases/public/components/user_actions/types.ts b/x-pack/plugins/cases/public/components/user_actions/types.ts index 978de436b377e..c6bb80b274f39 100644 --- a/x-pack/plugins/cases/public/components/user_actions/types.ts +++ b/x-pack/plugins/cases/public/components/user_actions/types.ts @@ -58,13 +58,13 @@ export interface UserActionBuilderArgs { loadingCommentIds: string[]; loadingAlertData: boolean; alertData: Record; + actionsNavigation?: ActionsNavigation; handleOutlineComment: (id: string) => void; handleManageMarkdownEditId: (id: string) => void; handleSaveComment: ({ id, version }: { id: string; version: string }, content: string) => void; handleDeleteComment: (id: string) => void; handleManageQuote: (quote: string) => void; onShowAlertDetails: (alertId: string, index: string) => void; - actionsNavigation?: ActionsNavigation; getRuleDetailsHref?: RuleDetailsNavigation['href']; onRuleDetailsClick?: RuleDetailsNavigation['onClick']; } diff --git a/x-pack/plugins/cases/public/containers/mock.ts b/x-pack/plugins/cases/public/containers/mock.ts index cada10b9eb109..cdaa9d56aea96 100644 --- a/x-pack/plugins/cases/public/containers/mock.ts +++ b/x-pack/plugins/cases/public/containers/mock.ts @@ -775,9 +775,9 @@ export const getJiraConnector = (overrides?: Partial): CaseConnec export const jiraFields = { fields: { issueType: '10006', priority: null, parent: null } }; -export const getAlertUserAction = (): SnakeToCamelCase< - UserActionWithResponse -> => ({ +export const getAlertUserAction = ( + overrides?: Record +): SnakeToCamelCase> => ({ ...getUserAction(ActionTypes.comment, Actions.create), actionId: 'alert-action-id', commentId: 'alert-comment-id', @@ -794,6 +794,29 @@ export const getAlertUserAction = (): SnakeToCamelCase< }, }, }, + ...overrides, +}); + +export const getMultipleAlertsUserAction = ( + overrides?: Record +): SnakeToCamelCase> => ({ + ...getUserAction(ActionTypes.comment, Actions.create), + actionId: 'alert-action-id', + commentId: 'alert-comment-id', + type: ActionTypes.comment, + payload: { + comment: { + type: CommentType.alert, + alertId: ['alert-id-1', 'alert-id-2'], + index: ['index-id-1', 'index-id-2'], + owner: SECURITY_SOLUTION_OWNER, + rule: { + id: 'rule-id-1', + name: 'Awesome rule', + }, + }, + }, + ...overrides, }); export const getHostIsolationUserAction = ( @@ -860,9 +883,9 @@ export const basicCaseClosed: Case = { status: CaseStatuses.closed, }; -export const getExternalReferenceUserAction = (): SnakeToCamelCase< - UserActionWithResponse -> => ({ +export const getExternalReferenceUserAction = ( + overrides?: Record +): SnakeToCamelCase> => ({ ...getUserAction(ActionTypes.comment, Actions.create), actionId: 'external-reference-action-id', type: ActionTypes.comment, @@ -877,6 +900,7 @@ export const getExternalReferenceUserAction = (): SnakeToCamelCase< owner: SECURITY_SOLUTION_OWNER, }, }, + ...overrides, }); export const getExternalReferenceAttachment = ( @@ -892,9 +916,9 @@ export const getExternalReferenceAttachment = ( }), }); -export const getPersistableStateUserAction = (): SnakeToCamelCase< - UserActionWithResponse -> => ({ +export const getPersistableStateUserAction = ( + overrides?: Record +): SnakeToCamelCase> => ({ ...getUserAction(ActionTypes.comment, Actions.create), actionId: 'persistable-state-action-id', type: ActionTypes.comment, @@ -907,6 +931,7 @@ export const getPersistableStateUserAction = (): SnakeToCamelCase< owner: SECURITY_SOLUTION_OWNER, }, }, + ...overrides, }); export const getPersistableStateAttachment = ( diff --git a/x-pack/plugins/enterprise_search/common/types/pipelines.ts b/x-pack/plugins/enterprise_search/common/types/pipelines.ts index 016ddb55c1377..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[]; } 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/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 5b9bd33643469..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; @@ -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_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/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 8e1caa17e2b78..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'], }, @@ -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/files/public/components/context.tsx b/x-pack/plugins/files/public/components/context.tsx index e55c0c45e4da6..a18ea212beffe 100644 --- a/x-pack/plugins/files/public/components/context.tsx +++ b/x-pack/plugins/files/public/components/context.tsx @@ -7,9 +7,14 @@ import React, { createContext, useContext, type FunctionComponent } from 'react'; import { FileKindsRegistry, getFileKindsRegistry } from '../../common/file_kinds_registry'; +import type { FilesClient } from '../types'; export interface FilesContextValue { registry: FileKindsRegistry; + /** + * A files client that will be used process uploads. + */ + client: FilesClient; } const FilesContextObject = createContext(null as unknown as FilesContextValue); @@ -21,10 +26,18 @@ export const useFilesContext = () => { } return ctx; }; -export const FilesContext: FunctionComponent = ({ children }) => { + +interface ContextProps { + /** + * A files client that will be used process uploads. + */ + client: FilesClient; +} +export const FilesContext: FunctionComponent = ({ client, children }) => { return ( diff --git a/x-pack/plugins/files/public/components/file_picker/components/clear_filter_button.tsx b/x-pack/plugins/files/public/components/file_picker/components/clear_filter_button.tsx new file mode 100644 index 0000000000000..14356b9b02bd4 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/clear_filter_button.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import type { FunctionComponent } from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { EuiLink } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { useFilePickerContext } from '../context'; + +import { i18nTexts } from '../i18n_texts'; + +interface Props { + onClick: () => void; +} + +export const ClearFilterButton: FunctionComponent = ({ onClick }) => { + const { state } = useFilePickerContext(); + const query = useObservable(state.queryDebounced$); + if (!query) { + return null; + } + return ( +
    + {i18nTexts.clearFilterButton} +
    + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/error_content.tsx b/x-pack/plugins/files/public/components/file_picker/components/error_content.tsx new file mode 100644 index 0000000000000..c2925c793fe63 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/error_content.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; +import { i18nTexts } from '../i18n_texts'; +import { useFilePickerContext } from '../context'; +import { useBehaviorSubject } from '../../use_behavior_subject'; + +interface Props { + error: Error; +} + +export const ErrorContent: FunctionComponent = ({ error }) => { + const { state } = useFilePickerContext(); + const isLoading = useBehaviorSubject(state.isLoading$); + return ( + {i18nTexts.loadingFilesErrorTitle}} + body={error.message} + actions={ + + {i18nTexts.retryButtonLabel} + + } + /> + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/file_card.scss b/x-pack/plugins/files/public/components/file_picker/components/file_card.scss new file mode 100644 index 0000000000000..f2a10651f6dea --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/file_card.scss @@ -0,0 +1,5 @@ +.filesFilePicker { + .euiCard__content, .euiCard__description { + margin :0; // make the cards a little bit more compact + } +} \ No newline at end of file diff --git a/x-pack/plugins/files/public/components/file_picker/components/file_card.tsx b/x-pack/plugins/files/public/components/file_picker/components/file_card.tsx new file mode 100644 index 0000000000000..4c290b1b114e7 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/file_card.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import numeral from '@elastic/numeral'; +import useObservable from 'react-use/lib/useObservable'; +import { EuiCard, EuiText, EuiIcon, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { FileImageMetadata, FileJSON } from '../../../../common'; +import { Image } from '../../image'; +import { isImage } from '../../util'; +import { useFilePickerContext } from '../context'; + +import './file_card.scss'; + +interface Props { + file: FileJSON; +} + +export const FileCard: FunctionComponent = ({ file }) => { + const { kind, state, client } = useFilePickerContext(); + const { euiTheme } = useEuiTheme(); + const displayImage = isImage({ type: file.mimeType }); + + const isSelected = useObservable(state.watchFileSelected$(file.id), false); + + const imageHeight = `calc(${euiTheme.size.xxxl} * 2)`; + return ( + (isSelected ? state.unselectFile(file.id) : state.selectFile(file.id)), + }} + image={ +
    + {displayImage ? ( + {file.alt + ) : ( +
    + +
    + )} +
    + } + description={ + <> + + {file.name} + + + {numeral(file.size).format('0[.]0 b')} + {file.extension && ( + <> +   ·   + + {file.extension} + + + )} + + + } + hasBorder + /> + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/file_grid.tsx b/x-pack/plugins/files/public/components/file_picker/components/file_grid.tsx new file mode 100644 index 0000000000000..2f2a9722d55b7 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/file_grid.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import { useEuiTheme, EuiEmptyPrompt } from '@elastic/eui'; +import { css } from '@emotion/react'; +import useObservable from 'react-use/lib/useObservable'; + +import { i18nTexts } from '../i18n_texts'; +import { useFilePickerContext } from '../context'; +import { FileCard } from './file_card'; + +export const FileGrid: FunctionComponent = () => { + const { state } = useFilePickerContext(); + const { euiTheme } = useEuiTheme(); + const files = useObservable(state.files$, []); + if (!files.length) { + return {i18nTexts.emptyFileGridPrompt}} titleSize="s" />; + } + return ( +
    + {files.map((file, idx) => ( + + ))} +
    + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/modal_footer.tsx b/x-pack/plugins/files/public/components/file_picker/components/modal_footer.tsx new file mode 100644 index 0000000000000..d0d0e146d2c3b --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/modal_footer.tsx @@ -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 { EuiFlexGroup, EuiModalFooter } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; + +import { Pagination } from './pagination'; +import { SelectButton, Props as SelectButtonProps } from './select_button'; + +interface Props { + onDone: SelectButtonProps['onClick']; +} + +export const ModalFooter: FunctionComponent = ({ onDone }) => { + return ( + + + + + + + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/pagination.tsx b/x-pack/plugins/files/public/components/file_picker/components/pagination.tsx new file mode 100644 index 0000000000000..bc2d0d444ba45 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/pagination.tsx @@ -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 React from 'react'; +import type { FunctionComponent } from 'react'; +import { EuiPagination } from '@elastic/eui'; +import { useFilePickerContext } from '../context'; +import { useBehaviorSubject } from '../../use_behavior_subject'; + +export const Pagination: FunctionComponent = () => { + const { state } = useFilePickerContext(); + const page = useBehaviorSubject(state.currentPage$); + const pageCount = useBehaviorSubject(state.totalPages$); + return ; +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/search_field.tsx b/x-pack/plugins/files/public/components/file_picker/components/search_field.tsx new file mode 100644 index 0000000000000..0235b03dd3fc1 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/search_field.tsx @@ -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 { FunctionComponent } from 'react'; +import React from 'react'; +import { EuiFieldSearch } from '@elastic/eui'; +import { i18nTexts } from '../i18n_texts'; +import { useFilePickerContext } from '../context'; +import { useBehaviorSubject } from '../../use_behavior_subject'; + +export const SearchField: FunctionComponent = () => { + const { state } = useFilePickerContext(); + const query = useBehaviorSubject(state.query$); + const isLoading = useBehaviorSubject(state.isLoading$); + const hasFiles = useBehaviorSubject(state.hasFiles$); + return ( + state.setQuery(ev.target.value)} + /> + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/select_button.tsx b/x-pack/plugins/files/public/components/file_picker/components/select_button.tsx new file mode 100644 index 0000000000000..ac5e241c01d53 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/select_button.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 { EuiButton } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; +import { useBehaviorSubject } from '../../use_behavior_subject'; +import { useFilePickerContext } from '../context'; +import { i18nTexts } from '../i18n_texts'; + +export interface Props { + onClick: (selectedFiles: string[]) => void; +} + +export const SelectButton: FunctionComponent = ({ onClick }) => { + const { state } = useFilePickerContext(); + const selectedFiles = useBehaviorSubject(state.selectedFileIds$); + return ( + onClick(selectedFiles)} + > + {selectedFiles.length > 1 + ? i18nTexts.selectFilesLabel(selectedFiles.length) + : i18nTexts.selectFileLabel} + + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/components/title.tsx b/x-pack/plugins/files/public/components/file_picker/components/title.tsx new file mode 100644 index 0000000000000..de1015241f656 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/title.tsx @@ -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 React from 'react'; +import type { FunctionComponent } from 'react'; +import { EuiTitle } from '@elastic/eui'; +import { i18nTexts } from '../i18n_texts'; + +export const Title: FunctionComponent = () => ( + +

    {i18nTexts.title}

    +
    +); diff --git a/x-pack/plugins/files/public/components/file_picker/components/upload_files.tsx b/x-pack/plugins/files/public/components/file_picker/components/upload_files.tsx new file mode 100644 index 0000000000000..143d20fd63ec0 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/components/upload_files.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiEmptyPrompt, EuiText } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import { UploadFile } from '../../upload_file'; +import { useFilePickerContext } from '../context'; +import { i18nTexts } from '../i18n_texts'; + +interface Props { + kind: string; +} + +export const UploadFilesPrompt: FunctionComponent = ({ kind }) => { + const { state } = useFilePickerContext(); + return ( + {i18nTexts.emptyStatePrompt}} + body={ + +

    {i18nTexts.emptyStatePromptSubtitle}

    +
    + } + titleSize="s" + actions={[ + // TODO: We can remove this once the entire modal is an upload area + { + state.selectFile(file.map(({ id }) => id)); + state.retry(); + }} + />, + ]} + /> + ); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/context.tsx b/x-pack/plugins/files/public/components/file_picker/context.tsx new file mode 100644 index 0000000000000..67e745b745829 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/context.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { createContext, useContext, useMemo, useEffect } from 'react'; +import type { FunctionComponent } from 'react'; +import { useFilesContext, FilesContextValue } from '../context'; +import { FilePickerState, createFilePickerState } from './file_picker_state'; + +interface FilePickerContextValue extends FilesContextValue { + state: FilePickerState; + kind: string; +} + +const FilePickerCtx = createContext( + null as unknown as FilePickerContextValue +); + +interface FilePickerContextProps { + kind: string; + pageSize: number; +} +export const FilePickerContext: FunctionComponent = ({ + kind, + pageSize, + children, +}) => { + const filesContext = useFilesContext(); + const { client } = filesContext; + const state = useMemo( + () => createFilePickerState({ pageSize, client, kind }), + [pageSize, client, kind] + ); + useEffect(() => state.dispose, [state]); + return ( + + {children} + + ); +}; + +export const useFilePickerContext = (): FilePickerContextValue => { + const ctx = useContext(FilePickerCtx); + if (!ctx) throw new Error('FilePickerContext not found!'); + return ctx; +}; diff --git a/x-pack/plugins/files/public/components/file_picker/file_picker.scss b/x-pack/plugins/files/public/components/file_picker/file_picker.scss new file mode 100644 index 0000000000000..a7ec792564500 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/file_picker.scss @@ -0,0 +1,8 @@ +.filesFilePicker--fixed { + @include euiBreakpoint('m', 'l', 'xl', 'xxl') { + width: 75vw; + .euiModal__flex { + height: 75vw; + } + } +} \ No newline at end of file diff --git a/x-pack/plugins/files/public/components/file_picker/file_picker.stories.tsx b/x-pack/plugins/files/public/components/file_picker/file_picker.stories.tsx new file mode 100644 index 0000000000000..9d40b112b4060 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/file_picker.stories.tsx @@ -0,0 +1,198 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { ComponentMeta, ComponentStory } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import type { FileJSON } from '../../../common'; +import { FilesClient, FilesClientResponses } from '../../types'; +import { register } from '../stories_shared'; +import { base64dLogo } from '../image/image.constants.stories'; +import { FilesContext } from '../context'; +import { FilePicker, Props as FilePickerProps } from './file_picker'; + +const kind = 'filepicker'; +register({ + id: kind, + http: {}, + allowedMimeTypes: ['*'], +}); + +const defaultProps: FilePickerProps = { + kind, + onDone: action('done!'), + onClose: action('close!'), +}; + +export default { + title: 'components/FilePicker', + component: FilePicker, + args: defaultProps, + decorators: [ + (Story) => ( + Promise.reject(new Error('not so fast buster!')), + list: async (): Promise => ({ + files: [], + total: 0, + }), + } as unknown as FilesClient + } + > + + + ), + ], +} as ComponentMeta; + +const Template: ComponentStory = (props) => ; + +export const Empty = Template.bind({}); + +const d = new Date(); +let id = 0; +function createFileJSON(file?: Partial): FileJSON { + return { + alt: '', + created: d.toISOString(), + updated: d.toISOString(), + extension: 'png', + fileKind: kind, + id: String(++id), + meta: { + width: 1000, + height: 1000, + }, + mimeType: 'image/png', + name: 'my file', + size: 1, + status: 'READY', + ...file, + }; +} +export const BasicOne = Template.bind({}); +BasicOne.decorators = [ + (Story) => ( + `data:image/png;base64,${base64dLogo}`, + list: async (): Promise => ({ + files: [createFileJSON()], + total: 1, + }), + } as unknown as FilesClient + } + > + + + ), +]; + +export const BasicMany = Template.bind({}); +BasicMany.decorators = [ + (Story) => { + const files = [ + createFileJSON({ name: 'abc' }), + createFileJSON({ name: 'def' }), + createFileJSON({ name: 'efg' }), + createFileJSON({ name: 'foo' }), + createFileJSON({ name: 'bar' }), + createFileJSON(), + createFileJSON(), + ]; + + return ( + `data:image/png;base64,${base64dLogo}`, + list: async (): Promise => ({ + files, + total: files.length, + }), + } as unknown as FilesClient + } + > + + + ); + }, +]; + +export const BasicManyMany = Template.bind({}); +BasicManyMany.decorators = [ + (Story) => { + const array = new Array(102); + array.fill(null); + return ( + `data:image/png;base64,${base64dLogo}`, + list: async (): Promise => ({ + files: array.map((_, idx) => createFileJSON({ id: String(idx) })), + total: array.length, + }), + } as unknown as FilesClient + } + > + + + ); + }, +]; + +export const ErrorLoading = Template.bind({}); +ErrorLoading.decorators = [ + (Story) => { + const array = new Array(102); + array.fill(createFileJSON()); + return ( + `data:image/png;base64,${base64dLogo}`, + list: async () => { + throw new Error('stop'); + }, + } as unknown as FilesClient + } + > + + + ); + }, +]; + +export const TryFilter = Template.bind({}); +TryFilter.decorators = [ + (Story) => { + const array = { files: [createFileJSON()], total: 1 }; + return ( + <> +

    Try entering a filter!

    + `data:image/png;base64,${base64dLogo}`, + list: async ({ name }: { name: string[] }) => { + if (name) { + return { files: [], total: 0 }; + } + return array; + }, + } as unknown as FilesClient + } + > + + + + ); + }, +]; diff --git a/x-pack/plugins/files/public/components/file_picker/file_picker.test.tsx b/x-pack/plugins/files/public/components/file_picker/file_picker.test.tsx new file mode 100644 index 0000000000000..14b621050a0ef --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/file_picker.test.tsx @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { EuiButtonEmpty } from '@elastic/eui'; +import { act } from 'react-dom/test-utils'; +import { registerTestBed } from '@kbn/test-jest-helpers'; + +import { createMockFilesClient } from '../../mocks'; +import { FilesContext } from '../context'; +import { FilePicker, Props } from './file_picker'; +import { + FileKindsRegistryImpl, + getFileKindsRegistry, + setFileKindsRegistry, +} from '../../../common/file_kinds_registry'; +import { FileJSON } from '../../../common'; + +describe('FilePicker', () => { + const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms)); + let client: ReturnType; + let onDone: jest.Mock; + let onClose: jest.Mock; + + async function initTestBed(props?: Partial) { + const createTestBed = registerTestBed((p: Props) => ( + + + + )); + + const testBed = await createTestBed({ + client, + kind: 'test', + onClose, + onDone, + ...props, + } as Props); + + const baseTestSubj = `filePickerModal`; + + const testSubjects = { + base: baseTestSubj, + searchField: `${baseTestSubj}.searchField`, + emptyPrompt: `${baseTestSubj}.emptyPrompt`, + errorPrompt: `${baseTestSubj}.errorPrompt`, + selectButton: `${baseTestSubj}.selectButton`, + loadingSpinner: `${baseTestSubj}.loadingSpinner`, + fileGrid: `${baseTestSubj}.fileGrid`, + }; + + return { + ...testBed, + actions: { + select: (n: number) => + act(() => { + const file = testBed.find(testSubjects.fileGrid).childAt(n).find(EuiButtonEmpty); + file.simulate('click'); + testBed.component.update(); + }), + done: () => + act(() => { + testBed.find(testSubjects.selectButton).simulate('click'); + }), + waitUntilLoaded: async () => { + let tries = 5; + while (tries) { + await act(async () => { + await sleep(100); + testBed.component.update(); + }); + if (!testBed.exists(testSubjects.loadingSpinner)) { + break; + } + --tries; + } + }, + }, + testSubjects, + }; + } + + beforeAll(() => { + setFileKindsRegistry(new FileKindsRegistryImpl()); + getFileKindsRegistry().register({ + id: 'test', + maxSizeBytes: 10000, + http: {}, + }); + }); + + beforeEach(() => { + jest.resetAllMocks(); + client = createMockFilesClient(); + onDone = jest.fn(); + onClose = jest.fn(); + }); + + it('intially shows a loadings spinner, then content', async () => { + client.list.mockImplementation(() => Promise.resolve({ files: [], total: 0 })); + const { exists, testSubjects, actions } = await initTestBed(); + expect(exists(testSubjects.loadingSpinner)).toBe(true); + await actions.waitUntilLoaded(); + expect(exists(testSubjects.loadingSpinner)).toBe(false); + }); + it('shows empty prompt when there are no files', async () => { + client.list.mockImplementation(() => Promise.resolve({ files: [], total: 0 })); + const { exists, testSubjects, actions } = await initTestBed(); + await actions.waitUntilLoaded(); + expect(exists(testSubjects.emptyPrompt)).toBe(true); + }); + it('returns the IDs of the selected files', async () => { + client.list.mockImplementation(() => + Promise.resolve({ files: [{ id: 'a' }, { id: 'b' }] as FileJSON[], total: 2 }) + ); + const { find, testSubjects, actions } = await initTestBed(); + await actions.waitUntilLoaded(); + expect(find(testSubjects.selectButton).props().disabled).toBe(true); + actions.select(0); + actions.select(1); + expect(find(testSubjects.selectButton).props().disabled).toBe(false); + actions.done(); + expect(onDone).toHaveBeenCalledTimes(1); + expect(onDone).toHaveBeenNthCalledWith(1, ['a', 'b']); + }); +}); diff --git a/x-pack/plugins/files/public/components/file_picker/file_picker.tsx b/x-pack/plugins/files/public/components/file_picker/file_picker.tsx new file mode 100644 index 0000000000000..72920b72a865d --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/file_picker.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { + EuiModal, + EuiModalBody, + EuiModalHeader, + EuiLoadingSpinner, + EuiSpacer, + EuiFlexGroup, +} from '@elastic/eui'; + +import { useBehaviorSubject } from '../use_behavior_subject'; +import { useFilePickerContext, FilePickerContext } from './context'; + +import { Title } from './components/title'; +import { ErrorContent } from './components/error_content'; +import { UploadFilesPrompt } from './components/upload_files'; +import { FileGrid } from './components/file_grid'; +import { SearchField } from './components/search_field'; +import { ModalFooter } from './components/modal_footer'; + +import './file_picker.scss'; +import { ClearFilterButton } from './components/clear_filter_button'; + +export interface Props { + /** + * The file kind that was passed to the registry. + */ + kind: Kind; + /** + * Will be called when the modal is closed + */ + onClose: () => void; + /** + * Will be called after a user has a selected a set of files + */ + onDone: (fileIds: string[]) => void; + /** + * The number of results to show per page. + */ + pageSize?: number; +} + +const Component: FunctionComponent = ({ onClose, onDone }) => { + const { state, kind } = useFilePickerContext(); + + const hasFiles = useBehaviorSubject(state.hasFiles$); + const hasQuery = useBehaviorSubject(state.hasQuery$); + const isLoading = useBehaviorSubject(state.isLoading$); + const error = useBehaviorSubject(state.loadingError$); + + useObservable(state.files$); + + const renderFooter = () => ; + + return ( + + + + <SearchField /> + </EuiModalHeader> + {isLoading ? ( + <> + <EuiModalBody> + <EuiFlexGroup justifyContent="center" alignItems="center" gutterSize="none"> + <EuiLoadingSpinner data-test-subj="loadingSpinner" size="xl" /> + </EuiFlexGroup> + </EuiModalBody> + {renderFooter()} + </> + ) : Boolean(error) ? ( + <EuiModalBody> + <ErrorContent error={error as Error} /> + </EuiModalBody> + ) : !hasFiles && !hasQuery ? ( + <EuiModalBody> + <UploadFilesPrompt kind={kind} /> + </EuiModalBody> + ) : ( + <> + <EuiModalBody> + <FileGrid /> + <EuiSpacer /> + <ClearFilterButton onClick={() => state.setQuery(undefined)} /> + </EuiModalBody> + {renderFooter()} + </> + )} + </EuiModal> + ); +}; + +export const FilePicker: FunctionComponent<Props> = (props) => ( + <FilePickerContext pageSize={props.pageSize ?? 20} kind={props.kind}> + <Component {...props} /> + </FilePickerContext> +); + +/* eslint-disable import/no-default-export */ +export default FilePicker; diff --git a/x-pack/plugins/files/public/components/file_picker/file_picker_state.test.ts b/x-pack/plugins/files/public/components/file_picker/file_picker_state.test.ts new file mode 100644 index 0000000000000..79eb5cbfa529d --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/file_picker_state.test.ts @@ -0,0 +1,171 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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('rxjs', () => { + const rxjs = jest.requireActual('rxjs'); + return { + ...rxjs, + debounceTime: rxjs.tap, + }; +}); + +import { TestScheduler } from 'rxjs/testing'; +import { merge, tap, of, NEVER } from 'rxjs'; +import { FileJSON } from '../../../common'; +import { FilePickerState, createFilePickerState } from './file_picker_state'; +import { createMockFilesClient } from '../../mocks'; + +const getTestScheduler = () => + new TestScheduler((actual, expected) => expect(actual).toEqual(expected)); + +describe('FilePickerState', () => { + let filePickerState: FilePickerState; + let filesClient: ReturnType<typeof createMockFilesClient>; + beforeEach(() => { + filesClient = createMockFilesClient(); + filePickerState = createFilePickerState({ + client: filesClient, + pageSize: 20, + kind: 'test', + }); + }); + it('starts off empty', () => { + expect(filePickerState.hasFilesSelected()).toBe(false); + }); + it('updates when files are added', () => { + getTestScheduler().run(({ expectObservable, cold, flush }) => { + const addFiles$ = cold('--a-b|').pipe(tap((id) => filePickerState.selectFile(id))); + expectObservable(addFiles$).toBe('--a-b|'); + expectObservable(filePickerState.selectedFileIds$).toBe('a-b-c-', { + a: [], + b: ['a'], + c: ['a', 'b'], + }); + flush(); + expect(filePickerState.hasFilesSelected()).toBe(true); + expect(filePickerState.getSelectedFileIds()).toEqual(['a', 'b']); + }); + }); + it('adds files simultaneously as one update', () => { + getTestScheduler().run(({ expectObservable, cold, flush }) => { + const addFiles$ = cold('--a|').pipe(tap(() => filePickerState.selectFile(['1', '2', '3']))); + expectObservable(addFiles$).toBe('--a|'); + expectObservable(filePickerState.selectedFileIds$).toBe('a-b-', { + a: [], + b: ['1', '2', '3'], + }); + flush(); + expect(filePickerState.hasFilesSelected()).toBe(true); + expect(filePickerState.getSelectedFileIds()).toEqual(['1', '2', '3']); + }); + }); + it('updates when files are removed', () => { + getTestScheduler().run(({ expectObservable, cold, flush }) => { + const addFiles$ = cold(' --a-b---c|').pipe(tap((id) => filePickerState.selectFile(id))); + const removeFiles$ = cold('------a|').pipe(tap((id) => filePickerState.unselectFile(id))); + expectObservable(merge(addFiles$, removeFiles$)).toBe('--a-b-a-c|'); + expectObservable(filePickerState.selectedFileIds$).toBe('a-b-c-d-e-', { + a: [], + b: ['a'], + c: ['a', 'b'], + d: ['b'], + e: ['b', 'c'], + }); + flush(); + expect(filePickerState.hasFilesSelected()).toBe(true); + expect(filePickerState.getSelectedFileIds()).toEqual(['b', 'c']); + }); + }); + it('does not add duplicates', () => { + getTestScheduler().run(({ expectObservable, cold, flush }) => { + const addFiles$ = cold('--a-b-a-a-a|').pipe(tap((id) => filePickerState.selectFile(id))); + expectObservable(addFiles$).toBe('--a-b-a-a-a|'); + expectObservable(filePickerState.selectedFileIds$).toBe('a-b-c-d-e-f-', { + a: [], + b: ['a'], + c: ['a', 'b'], + d: ['a', 'b'], + e: ['a', 'b'], + f: ['a', 'b'], + }); + flush(); + expect(filePickerState.hasFilesSelected()).toBe(true); + expect(filePickerState.getSelectedFileIds()).toEqual(['a', 'b']); + }); + }); + it('calls the API with the expected args', () => { + getTestScheduler().run(({ expectObservable, cold, flush }) => { + const files = [ + { id: 'a', name: 'a' }, + { id: 'b', name: 'b' }, + ] as FileJSON[]; + filesClient.list.mockImplementation(() => of({ files }) as any); + + const inputQuery = '-------a---b|'; + const inputPage = ' ---------------2|'; + + const query$ = cold(inputQuery).pipe(tap((q) => filePickerState.setQuery(q))); + expectObservable(query$).toBe(inputQuery); + + const page$ = cold(inputPage).pipe(tap((p) => filePickerState.setPage(+p))); + expectObservable(page$).toBe(inputPage); + + expectObservable(filePickerState.files$, '----^').toBe('----a--b---c---d', { + a: files, + b: files, + c: files, + d: files, + }); + + flush(); + expect(filesClient.list).toHaveBeenCalledTimes(4); + expect(filesClient.list).toHaveBeenNthCalledWith(1, { + abortSignal: expect.any(AbortSignal), + kind: 'test', + name: undefined, + page: 1, + perPage: 20, + status: ['READY'], + }); + expect(filesClient.list).toHaveBeenNthCalledWith(2, { + abortSignal: expect.any(AbortSignal), + kind: 'test', + name: ['*a*'], + page: 1, + perPage: 20, + status: ['READY'], + }); + expect(filesClient.list).toHaveBeenNthCalledWith(3, { + abortSignal: expect.any(AbortSignal), + kind: 'test', + name: ['*b*'], + page: 1, + perPage: 20, + status: ['READY'], + }); + expect(filesClient.list).toHaveBeenNthCalledWith(4, { + abortSignal: expect.any(AbortSignal), + kind: 'test', + name: ['*b*'], + page: 3, + perPage: 20, + status: ['READY'], + }); + }); + }); + it('cancels in flight requests', () => { + getTestScheduler().run(({ expectObservable, cold }) => { + filesClient.list.mockImplementationOnce(() => NEVER as any); + filesClient.list.mockImplementationOnce(() => of({ files: [], total: 0 }) as any); + const inputQuery = '------a|'; + const input$ = cold(inputQuery).pipe(tap((q) => filePickerState.setQuery(q))); + expectObservable(input$).toBe(inputQuery); + expectObservable(filePickerState.files$, '--^').toBe('------a-', { a: [] }); + expectObservable(filePickerState.loadingError$).toBe('a-b---c-', {}); + }); + }); +}); diff --git a/x-pack/plugins/files/public/components/file_picker/file_picker_state.ts b/x-pack/plugins/files/public/components/file_picker/file_picker_state.ts new file mode 100644 index 0000000000000..3ca6ee9ffca99 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/file_picker_state.ts @@ -0,0 +1,205 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + map, + tap, + from, + switchMap, + Observable, + shareReplay, + debounceTime, + Subscription, + combineLatest, + BehaviorSubject, + distinctUntilChanged, +} from 'rxjs'; +import { FileJSON } from '../../../common'; +import { FilesClient } from '../../types'; + +function naivelyFuzzify(query: string): string { + return query.includes('*') ? query : `*${query}*`; +} + +export class FilePickerState { + /** + * Files the user has selected + */ + public readonly selectedFileIds$ = new BehaviorSubject<string[]>([]); + + public readonly isLoading$ = new BehaviorSubject<boolean>(true); + public readonly loadingError$ = new BehaviorSubject<undefined | Error>(undefined); + public readonly hasFiles$ = new BehaviorSubject<boolean>(false); + public readonly hasQuery$ = new BehaviorSubject<boolean>(false); + public readonly query$ = new BehaviorSubject<undefined | string>(undefined); + public readonly queryDebounced$ = this.query$.pipe(debounceTime(100)); + public readonly currentPage$ = new BehaviorSubject<number>(0); + public readonly totalPages$ = new BehaviorSubject<undefined | number>(undefined); + + /** + * This is how we keep a deduplicated list of file ids representing files a user + * has selected + */ + private readonly fileSet = new Set<string>(); + private readonly retry$ = new BehaviorSubject<void>(undefined); + private readonly subscriptions: Subscription[] = []; + private readonly internalIsLoading$ = new BehaviorSubject<boolean>(true); + + constructor( + private readonly client: FilesClient, + private readonly kind: string, + public readonly pageSize: number + ) { + this.subscriptions = [ + this.query$ + .pipe( + tap(() => this.setIsLoading(true)), + map((query) => Boolean(query)), + distinctUntilChanged() + ) + .subscribe(this.hasQuery$), + this.internalIsLoading$ + .pipe(debounceTime(100), distinctUntilChanged()) + .subscribe(this.isLoading$), + ]; + } + + /** + * File objects we have loaded on the front end, stored here so that it can + * easily be passed to all relevant UI. + * + * @note This is not explicitly kept in sync with the selected files! + * @note This is not explicitly kept in sync with the selected files! + */ + public readonly files$ = combineLatest([ + this.currentPage$.pipe(distinctUntilChanged()), + this.query$.pipe(distinctUntilChanged(), debounceTime(100)), + this.retry$, + ]).pipe( + switchMap(([page, query]) => this.sendRequest(page, query)), + tap(({ total }) => this.updateTotalPages({ total })), + tap(({ total }) => this.hasFiles$.next(Boolean(total))), + map(({ files }) => files), + shareReplay() + ); + + private updateTotalPages = ({ total }: { total: number }): void => { + this.totalPages$.next(Math.ceil(total / this.pageSize)); + }; + + private sendNextSelectedFiles() { + this.selectedFileIds$.next(this.getSelectedFileIds()); + } + + private setIsLoading(value: boolean) { + this.internalIsLoading$.next(value); + } + + public selectFile = (fileId: string | string[]): void => { + (Array.isArray(fileId) ? fileId : [fileId]).forEach((id) => this.fileSet.add(id)); + this.sendNextSelectedFiles(); + }; + + private abort: undefined | (() => void) = undefined; + private sendRequest = ( + page: number, + query: undefined | string + ): Observable<{ files: FileJSON[]; total: number }> => { + if (this.abort) this.abort(); + this.setIsLoading(true); + this.loadingError$.next(undefined); + + const abortController = new AbortController(); + this.abort = () => { + try { + abortController.abort(); + } catch (e) { + // ignore + } + }; + + const request$ = from( + this.client.list({ + kind: this.kind, + name: query ? [naivelyFuzzify(query)] : undefined, + page: page + 1, + status: ['READY'], + perPage: this.pageSize, + abortSignal: abortController.signal, + }) + ).pipe( + tap(() => { + this.setIsLoading(false); + this.abort = undefined; + }), + shareReplay() + ); + + request$.subscribe({ + error: (e: Error) => { + if (e.name === 'AbortError') return; + this.setIsLoading(false); + this.loadingError$.next(e); + }, + }); + + return request$; + }; + + public retry = (): void => { + this.retry$.next(); + }; + + public hasFilesSelected = (): boolean => { + return this.fileSet.size > 0; + }; + + public unselectFile = (fileId: string): void => { + if (this.fileSet.delete(fileId)) this.sendNextSelectedFiles(); + }; + + public isFileIdSelected = (fileId: string): boolean => { + return this.fileSet.has(fileId); + }; + + public getSelectedFileIds = (): string[] => { + return Array.from(this.fileSet); + }; + + public setQuery = (query: undefined | string): void => { + if (query) this.query$.next(query); + else this.query$.next(undefined); + this.currentPage$.next(0); + }; + + public setPage = (page: number): void => { + this.currentPage$.next(page); + }; + + public dispose = (): void => { + for (const sub of this.subscriptions) sub.unsubscribe(); + }; + + watchFileSelected$ = (id: string): Observable<boolean> => { + return this.selectedFileIds$.pipe( + map(() => this.fileSet.has(id)), + distinctUntilChanged() + ); + }; +} + +interface CreateFilePickerArgs { + client: FilesClient; + kind: string; + pageSize: number; +} +export const createFilePickerState = ({ + pageSize, + client, + kind, +}: CreateFilePickerArgs): FilePickerState => { + return new FilePickerState(client, kind, pageSize); +}; diff --git a/x-pack/plugins/files/public/components/file_picker/i18n_texts.ts b/x-pack/plugins/files/public/components/file_picker/i18n_texts.ts new file mode 100644 index 0000000000000..2670ecd71b084 --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/i18n_texts.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 { i18n } from '@kbn/i18n'; + +export const i18nTexts = { + title: i18n.translate('xpack.files.filePicker.title', { + defaultMessage: 'Select a file', + }), + loadingFilesErrorTitle: i18n.translate('xpack.files.filePicker.error.loadingTitle', { + defaultMessage: 'Could not load files', + }), + retryButtonLabel: i18n.translate('xpack.files.filePicker.error.retryButtonLabel', { + defaultMessage: 'Retry', + }), + emptyStatePrompt: i18n.translate('xpack.files.filePicker.emptyStatePrompt', { + defaultMessage: 'No files found', + }), + emptyStatePromptSubtitle: i18n.translate('xpack.files.filePicker.emptyStatePromptSubtitle', { + defaultMessage: 'Upload your first file.', + }), + selectFileLabel: i18n.translate('xpack.files.filePicker.selectFileButtonLable', { + defaultMessage: 'Select file', + }), + selectFilesLabel: (nrOfFiles: number) => + i18n.translate('xpack.files.filePicker.selectFilesButtonLable', { + defaultMessage: 'Select {nrOfFiles} files', + values: { nrOfFiles }, + }), + searchFieldPlaceholder: i18n.translate('xpack.files.filePicker.searchFieldPlaceholder', { + defaultMessage: 'my-file-*', + }), + emptyFileGridPrompt: i18n.translate('xpack.files.filePicker.emptyGridPrompt', { + defaultMessage: 'No files matched filter', + }), + loadMoreButtonLabel: i18n.translate('xpack.files.filePicker.loadMoreButtonLabel', { + defaultMessage: 'Load more', + }), + clearFilterButton: i18n.translate('xpack.files.filePicker.clearFilterButtonLabel', { + defaultMessage: 'Clear filter', + }), +}; diff --git a/x-pack/plugins/files/public/components/file_picker/index.tsx b/x-pack/plugins/files/public/components/file_picker/index.tsx new file mode 100644 index 0000000000000..47c892ef1cadd --- /dev/null +++ b/x-pack/plugins/files/public/components/file_picker/index.tsx @@ -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 React, { lazy, Suspense } from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; +import type { Props } from './file_picker'; + +export type { Props as FilePickerProps }; + +const FilePickerContainer = lazy(() => import('./file_picker')); + +export const FilePicker = (props: Props) => ( + <Suspense fallback={<EuiLoadingSpinner size="xl" />}> + <FilePickerContainer {...props} /> + </Suspense> +); diff --git a/x-pack/plugins/files/public/components/image/image.stories.tsx b/x-pack/plugins/files/public/components/image/image.stories.tsx index 02daf7badb329..ff8825485f9cb 100644 --- a/x-pack/plugins/files/public/components/image/image.stories.tsx +++ b/x-pack/plugins/files/public/components/image/image.stories.tsx @@ -13,6 +13,7 @@ import { FilesContext } from '../context'; import { getImageMetadata } from '../util'; import { Image, Props } from './image'; import { getImageData as getBlob, base64dLogo } from './image.constants.stories'; +import { FilesClient } from '../../types'; const defaultArgs: Props = { alt: 'test', src: `data:image/png;base64,${base64dLogo}` }; @@ -22,7 +23,7 @@ export default { args: defaultArgs, decorators: [ (Story) => ( - <FilesContext> + <FilesContext client={{} as unknown as FilesClient}> <Story /> </FilesContext> ), diff --git a/x-pack/plugins/files/public/components/image/image.tsx b/x-pack/plugins/files/public/components/image/image.tsx index 915f45c828f66..b83739d180c94 100644 --- a/x-pack/plugins/files/public/components/image/image.tsx +++ b/x-pack/plugins/files/public/components/image/image.tsx @@ -32,6 +32,15 @@ export interface Props extends ImgHTMLAttributes<HTMLImageElement> { * Emits when the image first becomes visible */ onFirstVisible?: () => void; + + /** + * As an optimisation images are only loaded when they are visible. + * This setting overrides this behavior and loads an image as soon as the + * component mounts. + * + * @default true + */ + lazy?: boolean; } /** @@ -46,13 +55,26 @@ export interface Props extends ImgHTMLAttributes<HTMLImageElement> { */ export const Image = React.forwardRef<HTMLImageElement, Props>( ( - { src, alt, onFirstVisible, onLoad, onError, meta, wrapperProps, size = 'original', ...rest }, + { + src, + alt, + onFirstVisible, + onLoad, + onError, + meta, + wrapperProps, + size = 'original', + lazy = true, + ...rest + }, ref ) => { const [isLoaded, setIsLoaded] = useState<boolean>(false); const [blurDelayExpired, setBlurDelayExpired] = useState(false); const { isVisible, ref: observerRef } = useViewportObserver({ onFirstVisible }); + const loadImage = lazy ? isVisible : true; + useEffect(() => { let unmounted = false; const id = window.setTimeout(() => { @@ -90,8 +112,8 @@ export const Image = React.forwardRef<HTMLImageElement, Props>( observerRef={observerRef} ref={ref} size={size} - hidden={!isVisible} - src={isVisible ? src : undefined} + hidden={!loadImage} + src={loadImage ? src : undefined} alt={alt} onLoad={(ev) => { setIsLoaded(true); diff --git a/x-pack/plugins/files/public/components/image/viewport_observer.ts b/x-pack/plugins/files/public/components/image/viewport_observer.ts index a73e0f4067881..c0efe3d095594 100644 --- a/x-pack/plugins/files/public/components/image/viewport_observer.ts +++ b/x-pack/plugins/files/public/components/image/viewport_observer.ts @@ -25,7 +25,10 @@ export class ViewportObserver { opts: IntersectionObserverInit ) => IntersectionObserver ) { - this.intersectionObserver = getIntersectionObserver(this.handleChange, { root: null }); + this.intersectionObserver = getIntersectionObserver(this.handleChange, { + rootMargin: '0px', + root: null, + }); } /** diff --git a/x-pack/plugins/files/public/components/index.ts b/x-pack/plugins/files/public/components/index.ts index 533b37505b961..c5ab1382b4dfa 100644 --- a/x-pack/plugins/files/public/components/index.ts +++ b/x-pack/plugins/files/public/components/index.ts @@ -7,4 +7,5 @@ export { Image, type ImageProps } from './image'; export { UploadFile, type UploadFileProps } from './upload_file'; +export { FilePicker, type FilePickerProps } from './file_picker'; export { FilesContext } from './context'; diff --git a/x-pack/plugins/files/public/components/stories_shared.ts b/x-pack/plugins/files/public/components/stories_shared.ts new file mode 100644 index 0000000000000..a82ec3295b1d0 --- /dev/null +++ b/x-pack/plugins/files/public/components/stories_shared.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FileKind } from '../../common'; +import { + setFileKindsRegistry, + getFileKindsRegistry, + FileKindsRegistryImpl, +} from '../../common/file_kinds_registry'; + +setFileKindsRegistry(new FileKindsRegistryImpl()); +const fileKindsRegistry = getFileKindsRegistry(); +export const register: FileKindsRegistryImpl['register'] = (fileKind: FileKind) => { + if (!fileKindsRegistry.getAll().find((kind) => kind.id === fileKind.id)) { + getFileKindsRegistry().register(fileKind); + } +}; diff --git a/x-pack/plugins/files/public/components/upload_file/components/cancel_button.tsx b/x-pack/plugins/files/public/components/upload_file/components/cancel_button.tsx index 33a579ccc4c5f..b71a6221f3b2d 100644 --- a/x-pack/plugins/files/public/components/upload_file/components/cancel_button.tsx +++ b/x-pack/plugins/files/public/components/upload_file/components/cancel_button.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButtonEmpty } from '@elastic/eui'; +import { EuiButton, EuiButtonIcon } from '@elastic/eui'; import type { FunctionComponent } from 'react'; import React from 'react'; import { useBehaviorSubject } from '../../use_behavior_subject'; @@ -13,22 +13,33 @@ import { useUploadState } from '../context'; import { i18nTexts } from '../i18n_texts'; interface Props { + compressed?: boolean; onClick: () => void; } -export const CancelButton: FunctionComponent<Props> = ({ onClick }) => { +export const CancelButton: FunctionComponent<Props> = ({ onClick, compressed }) => { const uploadState = useUploadState(); const uploading = useBehaviorSubject(uploadState.uploading$); - return ( - <EuiButtonEmpty + const disabled = !uploading; + return compressed ? ( + <EuiButtonIcon + color="danger" + data-test-subj="cancelButtonIcon" + disabled={disabled} + iconType="cross" + aria-label={i18nTexts.cancel} + onClick={onClick} + /> + ) : ( + <EuiButton key="cancelButton" size="s" data-test-subj="cancelButton" - disabled={!uploading} + disabled={disabled} onClick={onClick} color="danger" > {i18nTexts.cancel} - </EuiButtonEmpty> + </EuiButton> ); }; diff --git a/x-pack/plugins/files/public/components/upload_file/components/control_button.tsx b/x-pack/plugins/files/public/components/upload_file/components/control_button.tsx index 6898adc9cce36..351cf2c39edd1 100644 --- a/x-pack/plugins/files/public/components/upload_file/components/control_button.tsx +++ b/x-pack/plugins/files/public/components/upload_file/components/control_button.tsx @@ -5,56 +5,36 @@ * 2.0. */ -import { EuiFlexGroup, EuiIcon, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; import type { FunctionComponent } from 'react'; import React from 'react'; import useObservable from 'react-use/lib/useObservable'; -import { euiThemeVars } from '@kbn/ui-theme'; import { useBehaviorSubject } from '../../use_behavior_subject'; import { useUploadState } from '../context'; -import { i18nTexts } from '../i18n_texts'; import { UploadButton } from './upload_button'; import { RetryButton } from './retry_button'; import { CancelButton } from './cancel_button'; -const { euiButtonHeightSmall } = euiThemeVars; - interface Props { onCancel: () => void; onUpload: () => void; immediate?: boolean; + compressed?: boolean; } -export const ControlButton: FunctionComponent<Props> = ({ onCancel, onUpload, immediate }) => { +export const ControlButton: FunctionComponent<Props> = ({ + onCancel, + onUpload, + immediate, + compressed, +}) => { const uploadState = useUploadState(); - const { - euiTheme: { size }, - } = useEuiTheme(); const uploading = useBehaviorSubject(uploadState.uploading$); const files = useObservable(uploadState.files$, []); - const done = useObservable(uploadState.done$); const retry = Boolean(files.some((f) => f.status === 'upload_failed')); - if (uploading) return <CancelButton onClick={onCancel} />; + if (compressed || uploading) return <CancelButton compressed={compressed} onClick={onCancel} />; if (retry) return <RetryButton onClick={onUpload} />; - if (!done && !immediate) return <UploadButton onClick={onUpload} />; + if (!immediate) return <UploadButton onClick={onUpload} />; - if (done) { - return ( - <EuiFlexGroup alignItems="center" gutterSize="none"> - <EuiIcon - css={css` - margin-inline: ${size.m}; - height: ${euiButtonHeightSmall}; - `} - data-test-subj="uploadSuccessIcon" - type="checkInCircleFilled" - color="success" - aria-label={i18nTexts.uploadDone} - /> - </EuiFlexGroup> - ); - } return null; }; diff --git a/x-pack/plugins/files/public/components/upload_file/components/retry_button.tsx b/x-pack/plugins/files/public/components/upload_file/components/retry_button.tsx index 55df91c5be3e8..355495aa25c17 100644 --- a/x-pack/plugins/files/public/components/upload_file/components/retry_button.tsx +++ b/x-pack/plugins/files/public/components/upload_file/components/retry_button.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiButtonEmpty } from '@elastic/eui'; +import { EuiButton } from '@elastic/eui'; import type { FunctionComponent } from 'react'; import React from 'react'; import { useBehaviorSubject } from '../../use_behavior_subject'; @@ -20,7 +20,7 @@ export const RetryButton: FunctionComponent<Props> = ({ onClick }) => { const uploading = useBehaviorSubject(uploadState.uploading$); return ( - <EuiButtonEmpty + <EuiButton key="retryButton" size="s" data-test-subj="retryButton" @@ -28,6 +28,6 @@ export const RetryButton: FunctionComponent<Props> = ({ onClick }) => { onClick={onClick} > {i18nTexts.retry} - </EuiButtonEmpty> + </EuiButton> ); }; diff --git a/x-pack/plugins/files/public/components/upload_file/components/upload_button.tsx b/x-pack/plugins/files/public/components/upload_file/components/upload_button.tsx index c9918874f7895..ff6320ab0b95a 100644 --- a/x-pack/plugins/files/public/components/upload_file/components/upload_button.tsx +++ b/x-pack/plugins/files/public/components/upload_file/components/upload_button.tsx @@ -21,16 +21,20 @@ export const UploadButton: FunctionComponent<Props> = ({ onClick }) => { const uploadState = useUploadState(); const uploading = useBehaviorSubject(uploadState.uploading$); const error = useBehaviorSubject(uploadState.error$); + const done = useObservable(uploadState.done$); const files = useObservable(uploadState.files$, []); return ( <EuiButton key="uploadButton" - disabled={Boolean(!files.length || uploading || error)} + isLoading={uploading} + color={done ? 'success' : 'primary'} + iconType={done ? 'checkInCircleFilled' : undefined} + disabled={Boolean(!files.length || error || done)} onClick={onClick} size="s" data-test-subj="uploadButton" > - {uploading ? i18nTexts.uploading : i18nTexts.upload} + {done ? i18nTexts.uploadComplete : uploading ? i18nTexts.uploading : i18nTexts.upload} </EuiButton> ); }; diff --git a/x-pack/plugins/files/public/components/upload_file/i18n_texts.ts b/x-pack/plugins/files/public/components/upload_file/i18n_texts.ts index 2077d635d3050..b58616e3d86b0 100644 --- a/x-pack/plugins/files/public/components/upload_file/i18n_texts.ts +++ b/x-pack/plugins/files/public/components/upload_file/i18n_texts.ts @@ -17,6 +17,9 @@ export const i18nTexts = { uploading: i18n.translate('xpack.files.uploadFile.uploadingButtonLabel', { defaultMessage: 'Uploading', }), + uploadComplete: i18n.translate('xpack.files.uploadFile.uploadCompleteButtonLabel', { + defaultMessage: 'Upload complete', + }), retry: i18n.translate('xpack.files.uploadFile.retryButtonLabel', { defaultMessage: 'Retry', }), diff --git a/x-pack/plugins/files/public/components/upload_file/upload_file.component.tsx b/x-pack/plugins/files/public/components/upload_file/upload_file.component.tsx index f4f5986d2f00b..8c81ae3fdcb21 100644 --- a/x-pack/plugins/files/public/components/upload_file/upload_file.component.tsx +++ b/x-pack/plugins/files/public/components/upload_file/upload_file.component.tsx @@ -12,6 +12,7 @@ import { EuiFlexItem, EuiFlexGroup, EuiFilePicker, + useEuiTheme, useGeneratedHtmlId, } from '@elastic/eui'; import { euiThemeVars } from '@kbn/ui-theme'; @@ -25,15 +26,36 @@ import { useUploadState } from './context'; export interface Props { meta?: unknown; accept?: string; + multiple?: boolean; + fullWidth?: boolean; immediate?: boolean; allowClear?: boolean; + compressed?: boolean; initialFilePromptText?: string; } const { euiFormMaxWidth, euiButtonHeightSmall } = euiThemeVars; +const horizontalContainer = css` + display: flex; + flex-direction: row; +`; + export const UploadFile = React.forwardRef<EuiFilePicker, Props>( - ({ meta, accept, immediate, allowClear = false, initialFilePromptText }, ref) => { + ( + { + compressed, + meta, + accept, + immediate, + allowClear = false, + multiple, + initialFilePromptText, + fullWidth, + }, + ref + ) => { + const { euiTheme } = useEuiTheme(); const uploadState = useUploadState(); const uploading = useBehaviorSubject(uploadState.uploading$); const error = useBehaviorSubject(uploadState.error$); @@ -47,43 +69,59 @@ export const UploadFile = React.forwardRef<EuiFilePicker, Props>( return ( <div data-test-subj="filesUploadFile" - css={css` - max-width: ${euiFormMaxWidth}; - `} + css={[ + css` + max-width: ${fullWidth ? '100%' : euiFormMaxWidth}; + `, + compressed ? horizontalContainer : undefined, + ]} > <EuiFilePicker + fullWidth={fullWidth} aria-label={i18nTexts.defaultPickerLabel} id={id} ref={ref} onChange={(fs) => { uploadState.setFiles(Array.from(fs ?? [])); - if (immediate) uploadState.upload(meta); + if (immediate && uploadState.hasFiles()) uploadState.upload(meta); }} - multiple={false} + multiple={multiple} initialPromptText={initialFilePromptText} isLoading={uploading} isInvalid={isInvalid} accept={accept} disabled={Boolean(done?.length || uploading)} aria-describedby={errorMessage ? errorId : undefined} + display={compressed ? 'default' : 'large'} /> - <EuiSpacer size="s" /> + <EuiSpacer + size="s" + css={ + compressed + ? css` + width: ${euiTheme.size.s}; + ` + : undefined + } + /> <EuiFlexGroup justifyContent="flexStart" - alignItems="flexStart" - direction="rowReverse" - gutterSize="m" + alignItems={compressed ? 'center' : 'flexStart'} + direction={compressed ? undefined : 'rowReverse'} + gutterSize={compressed ? 'none' : 'm'} + responsive={false} > <EuiFlexItem grow={false}> <ControlButton + compressed={compressed} immediate={immediate} onCancel={uploadState.abort} onUpload={() => uploadState.upload(meta)} /> </EuiFlexItem> - {Boolean(!done && !uploading && errorMessage) && ( + {!compressed && Boolean(!done && !uploading && errorMessage) && ( <EuiFlexItem> <EuiText data-test-subj="error" @@ -99,7 +137,7 @@ export const UploadFile = React.forwardRef<EuiFilePicker, Props>( </EuiText> </EuiFlexItem> )} - {done?.length && allowClear && ( + {!compressed && done?.length && allowClear && ( <> <EuiFlexItem /> {/* Occupy middle space */} <EuiFlexItem grow={false}> diff --git a/x-pack/plugins/files/public/components/upload_file/upload_file.stories.tsx b/x-pack/plugins/files/public/components/upload_file/upload_file.stories.tsx index c5a64d6d91a52..635400223fc17 100644 --- a/x-pack/plugins/files/public/components/upload_file/upload_file.stories.tsx +++ b/x-pack/plugins/files/public/components/upload_file/upload_file.stories.tsx @@ -5,14 +5,10 @@ * 2.0. */ import React from 'react'; -import { ComponentStory } from '@storybook/react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; import { action } from '@storybook/addon-actions'; -import { - FileKindsRegistryImpl, - setFileKindsRegistry, - getFileKindsRegistry, -} from '../../../common/file_kinds_registry'; +import { register } from '../stories_shared'; import { FilesClient } from '../../types'; import { FilesContext } from '../context'; import { UploadFile, Props } from './upload_file'; @@ -24,28 +20,36 @@ const defaultArgs: Props = { kind, onDone: action('onDone'), onError: action('onError'), - client: { - create: async () => ({ file: { id: 'test' } }), - upload: () => sleep(1000), - } as unknown as FilesClient, }; export default { title: 'stateful/UploadFile', component: UploadFile, args: defaultArgs, -}; - -setFileKindsRegistry(new FileKindsRegistryImpl()); - -getFileKindsRegistry().register({ + decorators: [ + (Story) => ( + <FilesContext + client={ + { + create: async () => ({ file: { id: 'test' } }), + upload: () => sleep(1000), + } as unknown as FilesClient + } + > + <Story /> + </FilesContext> + ), + ], +} as ComponentMeta<typeof UploadFile>; + +register({ id: kind, http: {}, allowedMimeTypes: ['*'], }); const miniFile = 'miniFile'; -getFileKindsRegistry().register({ +register({ id: miniFile, http: {}, maxSizeBytes: 1, @@ -53,17 +57,13 @@ getFileKindsRegistry().register({ }); const zipOnly = 'zipOnly'; -getFileKindsRegistry().register({ +register({ id: zipOnly, http: {}, allowedMimeTypes: ['application/zip'], }); -const Template: ComponentStory<typeof UploadFile> = (props: Props) => ( - <FilesContext> - <UploadFile {...props} /> - </FilesContext> -); +const Template: ComponentStory<typeof UploadFile> = (props: Props) => <UploadFile {...props} />; export const Basic = Template.bind({}); @@ -73,27 +73,43 @@ AllowRepeatedUploads.args = { }; export const LongErrorUX = Template.bind({}); -LongErrorUX.args = { - client: { - create: async () => ({ file: { id: 'test' } }), - upload: async () => { - await sleep(1000); - throw new Error('Something went wrong while uploading! '.repeat(10).trim()); - }, - delete: async () => {}, - } as unknown as FilesClient, -}; +LongErrorUX.decorators = [ + (Story) => ( + <FilesContext + client={ + { + create: async () => ({ file: { id: 'test' } }), + upload: async () => { + await sleep(1000); + throw new Error('Something went wrong while uploading! '.repeat(10).trim()); + }, + delete: async () => {}, + } as unknown as FilesClient + } + > + <Story /> + </FilesContext> + ), +]; export const Abort = Template.bind({}); -Abort.args = { - client: { - create: async () => ({ file: { id: 'test' } }), - upload: async () => { - await sleep(60000); - }, - delete: async () => {}, - } as unknown as FilesClient, -}; +Abort.decorators = [ + (Story) => ( + <FilesContext + client={ + { + create: async () => ({ file: { id: 'test' } }), + upload: async () => { + await sleep(60000); + }, + delete: async () => {}, + } as unknown as FilesClient + } + > + <Story /> + </FilesContext> + ), +]; export const MaxSize = Template.bind({}); MaxSize.args = { @@ -118,24 +134,72 @@ ImmediateUpload.args = { export const ImmediateUploadError = Template.bind({}); ImmediateUploadError.args = { immediate: true, - client: { - create: async () => ({ file: { id: 'test' } }), - upload: async () => { - await sleep(1000); - throw new Error('Something went wrong while uploading!'); - }, - delete: async () => {}, - } as unknown as FilesClient, }; +ImmediateUploadError.decorators = [ + (Story) => ( + <FilesContext + client={ + { + create: async () => ({ file: { id: 'test' } }), + upload: async () => { + await sleep(1000); + throw new Error('Something went wrong while uploading!'); + }, + delete: async () => {}, + } as unknown as FilesClient + } + > + <Story /> + </FilesContext> + ), +]; export const ImmediateUploadAbort = Template.bind({}); +ImmediateUploadAbort.decorators = [ + (Story) => ( + <FilesContext + client={ + { + create: async () => ({ file: { id: 'test' } }), + upload: async () => { + await sleep(60000); + }, + delete: async () => {}, + } as unknown as FilesClient + } + > + <Story /> + </FilesContext> + ), +]; ImmediateUploadAbort.args = { immediate: true, - client: { - create: async () => ({ file: { id: 'test' } }), - upload: async () => { - await sleep(60000); - }, - delete: async () => {}, - } as unknown as FilesClient, }; + +export const Compressed = Template.bind({}); +Compressed.args = { + compressed: true, +}; + +export const CompressedError = Template.bind({}); +CompressedError.args = { + compressed: true, +}; +CompressedError.decorators = [ + (Story) => ( + <FilesContext + client={ + { + create: async () => ({ file: { id: 'test' } }), + upload: async () => { + await sleep(1000); + throw new Error('Something went wrong while uploading! '.repeat(10).trim()); + }, + delete: async () => {}, + } as unknown as FilesClient + } + > + <Story /> + </FilesContext> + ), +]; diff --git a/x-pack/plugins/files/public/components/upload_file/upload_file.test.tsx b/x-pack/plugins/files/public/components/upload_file/upload_file.test.tsx index 1812f74e180e3..7682b085eb060 100644 --- a/x-pack/plugins/files/public/components/upload_file/upload_file.test.tsx +++ b/x-pack/plugins/files/public/components/upload_file/upload_file.test.tsx @@ -30,7 +30,7 @@ describe('UploadFile', () => { async function initTestBed(props?: Partial<Props>) { const createTestBed = registerTestBed((p: Props) => ( - <FilesContext> + <FilesContext client={client}> <UploadFile {...p} /> </FilesContext> )); @@ -50,8 +50,8 @@ describe('UploadFile', () => { uploadButton: `${baseTestSubj}.uploadButton`, retryButton: `${baseTestSubj}.retryButton`, cancelButton: `${baseTestSubj}.cancelButton`, + cancelButtonIcon: `${baseTestSubj}.cancelButtonIcon`, errorMessage: `${baseTestSubj}.error`, - successIcon: `${baseTestSubj}.uploadSuccessIcon`, }; return { @@ -110,12 +110,12 @@ describe('UploadFile', () => { client.create.mockResolvedValue({ file: { id: 'test', size: 1 } as FileJSON }); client.upload.mockResolvedValue({ size: 1, ok: true }); - const { actions, exists, testSubjects } = await initTestBed(); + const { actions, find, exists, testSubjects } = await initTestBed(); await actions.addFiles([{ name: 'test', size: 1 } as File]); await actions.upload(); await sleep(1000); expect(exists(testSubjects.errorMessage)).toBe(false); - expect(exists(testSubjects.successIcon)).toBe(true); + expect(find(testSubjects.uploadButton).text()).toMatch(/upload complete/i); expect(onDone).toHaveBeenCalledTimes(1); }); @@ -200,4 +200,20 @@ describe('UploadFile', () => { expect(onDone).not.toHaveBeenCalled(); }); + + it('only shows the cancel control in compressed mode', async () => { + const { actions, testSubjects, exists } = await initTestBed({ compressed: true }); + const assertButtons = () => { + expect(exists(testSubjects.cancelButtonIcon)).toBe(true); + expect(exists(testSubjects.cancelButton)).toBe(false); + expect(exists(testSubjects.retryButton)).toBe(false); + expect(exists(testSubjects.uploadButton)).toBe(false); + }; + + assertButtons(); + await actions.addFiles([{ name: 'test', size: 1 } as File]); + assertButtons(); + await actions.wait(1000); + assertButtons(); + }); }); diff --git a/x-pack/plugins/files/public/components/upload_file/upload_file.tsx b/x-pack/plugins/files/public/components/upload_file/upload_file.tsx index e85460ca7c1e3..d0ca3577b27a0 100644 --- a/x-pack/plugins/files/public/components/upload_file/upload_file.tsx +++ b/x-pack/plugins/files/public/components/upload_file/upload_file.tsx @@ -7,7 +7,6 @@ import { EuiFilePicker } from '@elastic/eui'; import React, { type FunctionComponent, useRef, useEffect, useMemo } from 'react'; -import { FilesClient } from '../../types'; import { useFilesContext } from '../context'; @@ -37,10 +36,6 @@ export interface Props<Kind extends string = string> { * A file kind that should be registered during plugin startup. See {@link FileServiceStart}. */ kind: Kind; - /** - * A files client that will be used process uploads. - */ - client: FilesClient<any>; /** * Allow users to clear a file after uploading. * @@ -56,6 +51,10 @@ export interface Props<Kind extends string = string> { * Metadata that you want to associate with any uploaded files */ meta?: Record<string, unknown>; + /** + * Whether to display the file picker with width 100%; + */ + fullWidth?: boolean; /** * Whether this component should display a "done" state after processing an * upload or return to the initial state to allow for another upload. @@ -63,6 +62,10 @@ export interface Props<Kind extends string = string> { * @default false */ allowRepeatedUploads?: boolean; + /** + * The initial text prompt + */ + initialPromptText?: string; /** * Called when the an upload process fully completes */ @@ -72,6 +75,22 @@ export interface Props<Kind extends string = string> { * Called when an error occurs during upload */ onError?: (e: Error) => void; + + /** + * Whether to display the component in it's compact form. + * + * @default false + * + * @note passing "true" here implies true for allowRepeatedUplods and immediate. + */ + compressed?: boolean; + + /** + * Allow upload more than one file at a time + * + * @default false + */ + multiple?: boolean; } /** @@ -82,25 +101,29 @@ export interface Props<Kind extends string = string> { */ export const UploadFile = <Kind extends string = string>({ meta, - client, onDone, onError, + fullWidth, allowClear, + compressed = false, kind: kindId, + multiple = false, + initialPromptText, immediate = false, allowRepeatedUploads = false, }: Props<Kind>): ReturnType<FunctionComponent> => { - const { registry } = useFilesContext(); + const { registry, client } = useFilesContext(); const ref = useRef<null | EuiFilePicker>(null); const fileKind = registry.get(kindId); + const repeatedUploads = compressed || allowRepeatedUploads; const uploadState = useMemo( () => createUploadState({ client, fileKind, - allowRepeatedUploads, + allowRepeatedUploads: repeatedUploads, }), - [client, allowRepeatedUploads, fileKind] + [client, repeatedUploads, fileKind] ); /** @@ -122,11 +145,15 @@ export const UploadFile = <Kind extends string = string>({ return ( <context.Provider value={uploadState}> <Component + compressed={compressed} ref={ref} accept={fileKind.allowedMimeTypes?.join(',')} meta={meta} - immediate={immediate} + immediate={compressed || immediate} allowClear={allowClear} + fullWidth={fullWidth} + initialFilePromptText={initialPromptText} + multiple={multiple} /> </context.Provider> ); diff --git a/x-pack/plugins/files/public/components/upload_file/upload_state.test.ts b/x-pack/plugins/files/public/components/upload_file/upload_state.test.ts index 3a4e19adf8114..a834103a2c9cb 100644 --- a/x-pack/plugins/files/public/components/upload_file/upload_state.test.ts +++ b/x-pack/plugins/files/public/components/upload_file/upload_state.test.ts @@ -206,4 +206,14 @@ describe('UploadState', () => { expectObservable(uploadState.clear$, '^').toBe(' ---0-', [undefined]); }); }); + + it('correctly detects when files are ready for upload', () => { + const file1 = { name: 'test' } as File; + const file2 = { name: 'test 2.png' } as File; + expect(uploadState.hasFiles()).toBe(false); + uploadState.setFiles([file1, file2]); + expect(uploadState.hasFiles()).toBe(true); + uploadState.setFiles([]); + expect(uploadState.hasFiles()).toBe(false); + }); }); diff --git a/x-pack/plugins/files/public/components/upload_file/upload_state.ts b/x-pack/plugins/files/public/components/upload_file/upload_state.ts index dd03eb7aee56a..13c4cc020b05a 100644 --- a/x-pack/plugins/files/public/components/upload_file/upload_state.ts +++ b/x-pack/plugins/files/public/components/upload_file/upload_state.ts @@ -239,6 +239,10 @@ export class UploadState { public dispose = (): void => { for (const sub of this.subscriptions) sub.unsubscribe(); }; + + public hasFiles(): boolean { + return this.files$$.getValue().length > 0; + } } export const createUploadState = ({ diff --git a/x-pack/plugins/files/public/components/util/image_metadata.ts b/x-pack/plugins/files/public/components/util/image_metadata.ts index 9358dda9d05ad..9c6e74f4c0101 100644 --- a/x-pack/plugins/files/public/components/util/image_metadata.ts +++ b/x-pack/plugins/files/public/components/util/image_metadata.ts @@ -8,8 +8,8 @@ import * as bh from 'blurhash'; import type { FileImageMetadata } from '../../../common'; -export function isImage(file: Blob | File): boolean { - return file.type?.startsWith('image/'); +export function isImage(file: { type?: string }): boolean { + return Boolean(file.type?.startsWith('image/')); } export const boxDimensions = { diff --git a/x-pack/plugins/files/public/files_client/files_client.ts b/x-pack/plugins/files/public/files_client/files_client.ts index a17929a4a100b..f92b2c91d2796 100644 --- a/x-pack/plugins/files/public/files_client/files_client.ts +++ b/x-pack/plugins/files/public/files_client/files_client.ts @@ -102,11 +102,12 @@ export function createFilesClient({ getById: ({ kind, ...args }) => { return http.get(apiRoutes.getByIdRoute(scopedFileKind ?? kind, args.id)); }, - list: ({ kind, page, perPage, ...body } = { kind: '' }) => { + list: ({ kind, page, perPage, abortSignal, ...body } = { kind: '' }) => { return http.post(apiRoutes.getListRoute(scopedFileKind ?? kind), { headers: commonBodyHeaders, query: { page, perPage }, body: JSON.stringify(body), + signal: abortSignal, }); }, update: ({ kind, id, ...body }) => { diff --git a/x-pack/plugins/files/public/index.ts b/x-pack/plugins/files/public/index.ts index f08b073e7485b..a9bd88615ff12 100644 --- a/x-pack/plugins/files/public/index.ts +++ b/x-pack/plugins/files/public/index.ts @@ -19,6 +19,8 @@ export { type ImageProps, UploadFile, type UploadFileProps, + FilePicker, + type FilePickerProps, } from './components'; export function plugin() { diff --git a/x-pack/plugins/files/public/types.ts b/x-pack/plugins/files/public/types.ts index 1cc69ac4ed23e..fcc5c11b1ae45 100644 --- a/x-pack/plugins/files/public/types.ts +++ b/x-pack/plugins/files/public/types.ts @@ -25,7 +25,9 @@ import type { } from '../common/api_routes'; type UnscopedClientMethodFrom<E extends HttpApiInterfaceEntryDefinition> = ( - args: E['inputs']['body'] & E['inputs']['params'] & E['inputs']['query'] + args: E['inputs']['body'] & + E['inputs']['params'] & + E['inputs']['query'] & { abortSignal?: AbortSignal } ) => Promise<E['output']>; /** 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<FileServiceStart> => ({ create: jest.fn(), @@ -26,3 +28,51 @@ export const createFileServiceFactoryMock = (): DeeplyMockedKeys<FileServiceFact asInternal: jest.fn(createFileServiceMock), asScoped: jest.fn((_: KibanaRequest) => createFileServiceMock()), }); + +export const createFileMock = (): DeeplyMockedKeys<File> => { + const fileMock: DeeplyMockedKeys<File> = { + 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<FileClient> => { + 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/infra/common/http_api/snapshot_api.ts b/x-pack/plugins/infra/common/http_api/snapshot_api.ts index 9c4fd65ce3fec..eb39f6a440a79 100644 --- a/x-pack/plugins/infra/common/http_api/snapshot_api.ts +++ b/x-pack/plugins/infra/common/http_api/snapshot_api.ts @@ -17,6 +17,9 @@ export const SnapshotNodePathRT = rt.intersection([ rt.partial({ ip: rt.union([rt.string, rt.null]), }), + rt.partial({ + os: rt.union([rt.string, rt.null]), + }), ]); const SnapshotNodeMetricOptionalRT = rt.partial({ diff --git a/x-pack/plugins/infra/common/inventory_models/host/index.ts b/x-pack/plugins/infra/common/inventory_models/host/index.ts index 8e2582c5e1f6f..7420ca3f15939 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/index.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/index.ts @@ -33,6 +33,7 @@ export const host: InventoryModel = { fields: { id: 'host.name', name: 'host.name', + os: 'host.os.name', ip: 'host.ip', }, metrics, diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts index 2190140cc0a5e..8a60c4a066502 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts @@ -6,10 +6,12 @@ */ import { cpu } from './snapshot/cpu'; +import { cpuCores } from './snapshot/cpu_cores'; import { count } from '../../shared/metrics/snapshot/count'; import { load } from './snapshot/load'; import { logRate } from './snapshot/log_rate'; import { memory } from './snapshot/memory'; +import { memoryTotal } from './snapshot/memory_total'; import { rx } from './snapshot/rx'; import { tx } from './snapshot/tx'; @@ -33,7 +35,7 @@ import { hostDockerInfo } from './tsvb/host_docker_info'; import { InventoryMetrics } from '../../types'; -const exposedHostSnapshotMetrics = { cpu, load, logRate, memory, rx, tx }; +const exposedHostSnapshotMetrics = { cpu, load, logRate, memory, rx, tx, cpuCores, memoryTotal }; // not sure why this is the only model with "count" const hostSnapshotMetrics = { count, ...exposedHostSnapshotMetrics }; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu_cores.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/infra/common/inventory_models/host/metrics/snapshot/cpu_cores.ts index 538348dcc3275..3cc90ebfdca95 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_bulk_schema.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu_cores.ts @@ -5,8 +5,12 @@ * 2.0. */ -import * as t from 'io-ts'; -import { updateRulesSchema } from './rule_schemas'; +import { MetricsUIAggregation } from '../../../types'; -export const updateRulesBulkSchema = t.array(updateRulesSchema); -export type UpdateRulesBulkSchema = t.TypeOf<typeof updateRulesBulkSchema>; +export const cpuCores: MetricsUIAggregation = { + cpuCores: { + max: { + field: 'system.cpu.cores', + }, + }, +}; diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/memory_total.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/memory_total.ts new file mode 100644 index 0000000000000..c3d0a8063b93f --- /dev/null +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/memory_total.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 { MetricsUIAggregation } from '../../../types'; + +export const memoryTotal: MetricsUIAggregation = { + memory_total: { + avg: { + field: 'system.memory.total', + }, + }, + memoryTotal: { + bucket_script: { + buckets_path: { + memoryTotal: 'memory_total', + }, + script: { + source: 'params.memoryTotal / 1000000', // Convert to MB + lang: 'painless', + }, + gap_policy: 'skip', + }, + }, +}; diff --git a/x-pack/plugins/infra/common/inventory_models/types.ts b/x-pack/plugins/infra/common/inventory_models/types.ts index 9459933a489d3..8c0118d40fa4b 100644 --- a/x-pack/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/plugins/infra/common/inventory_models/types.ts @@ -339,8 +339,10 @@ export type MetricsUIAggregation = rt.TypeOf<typeof MetricsUIAggregationRT>; export const SnapshotMetricTypeKeys = { count: null, cpu: null, + cpuCores: null, load: null, memory: null, + memoryTotal: null, tx: null, rx: null, logRate: null, @@ -382,6 +384,7 @@ export interface InventoryModel { fields: { id: string; name: string; + os?: string; ip?: string; }; crosslinkSupport: { diff --git a/x-pack/plugins/infra/kibana.json b/x-pack/plugins/infra/kibana.json index 4290fb0382cc6..2226c89ab90f6 100644 --- a/x-pack/plugins/infra/kibana.json +++ b/x-pack/plugins/infra/kibana.json @@ -15,8 +15,7 @@ "triggersActionsUi", "observability", "ruleRegistry", - "unifiedSearch", - "lens" + "unifiedSearch" ], "optionalPlugins": ["ml", "home", "embeddable", "osquery"], "server": true, diff --git a/x-pack/plugins/infra/public/apps/metrics_app.tsx b/x-pack/plugins/infra/public/apps/metrics_app.tsx index ce8123b5f2223..159c6dab7a66e 100644 --- a/x-pack/plugins/infra/public/apps/metrics_app.tsx +++ b/x-pack/plugins/infra/public/apps/metrics_app.tsx @@ -47,7 +47,6 @@ export const renderApp = ( return () => { core.chrome.docTitle.reset(); ReactDOM.unmountComponentAtNode(element); - plugins.data.search.session.clear(); }; }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx index 143f7fedb1420..f81f80faca73e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx @@ -5,549 +5,24 @@ * 2.0. */ -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import type { Query, TimeRange } from '@kbn/es-query'; -import React, { useState } from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import { i18n } from '@kbn/i18n'; -import { NoData } from '../../../../components/empty_states'; -import { InfraClientStartDeps } from '../../../../types'; - -const getLensHostsTable = ( - metricsDataView: DataView, - query: Query -): TypedLensByValueInput['attributes'] => - ({ - visualizationType: 'lnsDatatable', - title: 'Lens visualization', - references: [ - { - id: metricsDataView.id, - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: metricsDataView.id, - name: 'indexpattern-datasource-layer-cbe5d8a0-381d-49bf-b8ac-f8f312ec7129', - type: 'index-pattern', - }, - ], - state: { - datasourceStates: { - formBased: { - layers: { - 'cbe5d8a0-381d-49bf-b8ac-f8f312ec7129': { - columns: { - '8d17458d-31af-41d1-a23c-5180fd960bee': { - label: 'Name', - dataType: 'string', - operationType: 'terms', - scale: 'ordinal', - sourceField: 'host.name', - isBucketed: true, - params: { - size: 10000, - orderBy: { - type: 'column', - columnId: '467de550-9186-4e18-8cfa-bce07087801a', - }, - orderDirection: 'desc', - otherBucket: true, - missingBucket: false, - parentFormat: { - id: 'terms', - }, - }, - customLabel: true, - }, - '155fc728-d010-498e-8126-0bc46cad2be2': { - label: 'Operating system', - dataType: 'string', - operationType: 'terms', - scale: 'ordinal', - sourceField: 'host.os.type', - isBucketed: true, - params: { - size: 10000, - orderBy: { - type: 'column', - columnId: '467de550-9186-4e18-8cfa-bce07087801a', - }, - orderDirection: 'desc', - otherBucket: false, - missingBucket: false, - parentFormat: { - id: 'terms', - }, - }, - customLabel: true, - }, - '467de550-9186-4e18-8cfa-bce07087801a': { - label: '# of CPUs', - dataType: 'number', - operationType: 'max', - sourceField: 'system.cpu.cores', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: true, - }, - customLabel: true, - }, - '3eca2307-228e-4842-a023-57e15c8c364d': { - label: 'Disk latency (avg.)', - dataType: 'number', - operationType: 'formula', - isBucketed: false, - scale: 'ratio', - params: { - formula: 'average(system.diskio.io.time) / 1000', - isFormulaBroken: false, - format: { - id: 'number', - params: { - decimals: 0, - suffix: 'ms', - }, - }, - }, - references: ['3eca2307-228e-4842-a023-57e15c8c364dX1'], - customLabel: true, - }, - '0a9bd0fa-9966-489b-8c95-70997a7aad4c': { - label: 'Memory total (avg.)', - dataType: 'number', - operationType: 'formula', - isBucketed: false, - scale: 'ratio', - params: { - formula: 'average(system.memory.total)', - isFormulaBroken: false, - format: { - id: 'bytes', - params: { - decimals: 0, - }, - }, - }, - references: ['0a9bd0fa-9966-489b-8c95-70997a7aad4cX0'], - customLabel: true, - }, - 'fe5a4d7d-6f48-45ab-974c-96bc864ac36f': { - label: 'Memory usage (avg.)', - dataType: 'number', - operationType: 'formula', - isBucketed: false, - scale: 'ratio', - params: { - formula: 'average(system.memory.used.pct)', - isFormulaBroken: false, - format: { - id: 'percent', - params: { - decimals: 0, - }, - }, - }, - references: ['fe5a4d7d-6f48-45ab-974c-96bc864ac36fX0'], - customLabel: true, - }, - '0a9bd0fa-9966-489b-8c95-70997a7aad4cX0': { - label: 'Part of Memory Total (avg)', - dataType: 'number', - operationType: 'average', - sourceField: 'system.memory.total', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: false, - }, - customLabel: true, - }, - 'fe5a4d7d-6f48-45ab-974c-96bc864ac36fX0': { - label: 'Part of Memory Usage (avg)', - dataType: 'number', - operationType: 'average', - sourceField: 'system.memory.used.pct', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: false, - }, - customLabel: true, - }, - '3eca2307-228e-4842-a023-57e15c8c364dX0': { - label: 'Part of Disk Latency (avg ms)', - dataType: 'number', - operationType: 'average', - sourceField: 'system.diskio.io.time', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: false, - }, - customLabel: true, - }, - '3eca2307-228e-4842-a023-57e15c8c364dX1': { - label: 'Part of Disk Latency (avg ms)', - dataType: 'number', - operationType: 'math', - isBucketed: false, - scale: 'ratio', - params: { - tinymathAst: { - type: 'function', - name: 'divide', - args: ['3eca2307-228e-4842-a023-57e15c8c364dX0', 1000], - location: { - min: 0, - max: 37, - }, - text: 'average(system.diskio.io.time) / 1000', - }, - }, - references: ['3eca2307-228e-4842-a023-57e15c8c364dX0'], - customLabel: true, - }, - '02e9d54c-bbe0-42dc-839c-55080a29838dX0': { - label: 'Part of RX (avg)', - dataType: 'number', - operationType: 'average', - sourceField: 'host.network.ingress.bytes', - isBucketed: false, - scale: 'ratio', - filter: { - query: 'host.network.ingress.bytes: *', - language: 'kuery', - }, - params: { - emptyAsNull: false, - }, - customLabel: true, - }, - '02e9d54c-bbe0-42dc-839c-55080a29838dX1': { - label: 'Part of RX (avg)', - dataType: 'number', - operationType: 'max', - sourceField: 'metricset.period', - isBucketed: false, - scale: 'ratio', - filter: { - query: 'host.network.ingress.bytes: *', - language: 'kuery', - }, - params: { - emptyAsNull: false, - }, - customLabel: true, - }, - '02e9d54c-bbe0-42dc-839c-55080a29838dX2': { - label: 'Part of RX (avg)', - dataType: 'number', - operationType: 'math', - isBucketed: false, - scale: 'ratio', - params: { - tinymathAst: { - type: 'function', - name: 'divide', - args: [ - { - type: 'function', - name: 'multiply', - args: ['02e9d54c-bbe0-42dc-839c-55080a29838dX0', 8], - location: { - min: 1, - max: 40, - }, - text: 'average(host.network.ingress.bytes) * 8', - }, - { - type: 'function', - name: 'divide', - args: ['02e9d54c-bbe0-42dc-839c-55080a29838dX1', 1000], - location: { - min: 45, - max: 73, - }, - text: 'max(metricset.period) / 1000', - }, - ], - location: { - min: 0, - max: 75, - }, - text: '(average(host.network.ingress.bytes) * 8) / (max(metricset.period) / 1000)\n', - }, - }, - references: [ - '02e9d54c-bbe0-42dc-839c-55080a29838dX0', - '02e9d54c-bbe0-42dc-839c-55080a29838dX1', - ], - customLabel: true, - }, - '02e9d54c-bbe0-42dc-839c-55080a29838d': { - label: 'RX (avg.)', - dataType: 'number', - operationType: 'formula', - isBucketed: false, - scale: 'ratio', - params: { - formula: - '(average(host.network.ingress.bytes) * 8) / (max(metricset.period) / 1000)\n', - isFormulaBroken: false, - format: { - id: 'bits', - params: { - decimals: 0, - suffix: '/s', - }, - }, - }, - references: ['02e9d54c-bbe0-42dc-839c-55080a29838dX2'], - filter: { - query: 'host.network.ingress.bytes: *', - language: 'kuery', - }, - customLabel: true, - }, - '7802ef93-622c-44df-94fa-03eec01bb7b6X0': { - label: 'Part of TX', - dataType: 'number', - operationType: 'average', - sourceField: 'host.network.egress.bytes', - isBucketed: false, - scale: 'ratio', - filter: { - query: 'host.network.egress.bytes: *', - language: 'kuery', - }, - params: { - emptyAsNull: false, - }, - customLabel: true, - }, - '7802ef93-622c-44df-94fa-03eec01bb7b6X1': { - label: 'Part of TX', - dataType: 'number', - operationType: 'max', - sourceField: 'metricset.period', - isBucketed: false, - scale: 'ratio', - filter: { - query: 'host.network.egress.bytes: *', - language: 'kuery', - }, - params: { - emptyAsNull: false, - }, - customLabel: true, - }, - '7802ef93-622c-44df-94fa-03eec01bb7b6X2': { - label: 'Part of TX', - dataType: 'number', - operationType: 'math', - isBucketed: false, - scale: 'ratio', - params: { - tinymathAst: { - type: 'function', - name: 'divide', - args: [ - { - type: 'function', - name: 'multiply', - args: ['7802ef93-622c-44df-94fa-03eec01bb7b6X0', 8], - location: { - min: 1, - max: 39, - }, - text: 'average(host.network.egress.bytes) * 8', - }, - { - type: 'function', - name: 'divide', - args: ['7802ef93-622c-44df-94fa-03eec01bb7b6X1', 1000], - location: { - min: 44, - max: 72, - }, - text: 'max(metricset.period) / 1000', - }, - ], - location: { - min: 0, - max: 74, - }, - text: '(average(host.network.egress.bytes) * 8) / (max(metricset.period) / 1000)\n', - }, - }, - references: [ - '7802ef93-622c-44df-94fa-03eec01bb7b6X0', - '7802ef93-622c-44df-94fa-03eec01bb7b6X1', - ], - customLabel: true, - }, - '7802ef93-622c-44df-94fa-03eec01bb7b6': { - label: 'TX (avg.)', - dataType: 'number', - operationType: 'formula', - isBucketed: false, - scale: 'ratio', - params: { - formula: - '(average(host.network.egress.bytes) * 8) / (max(metricset.period) / 1000)\n', - isFormulaBroken: false, - format: { - id: 'bits', - params: { - decimals: 0, - suffix: '/s', - }, - }, - }, - references: ['7802ef93-622c-44df-94fa-03eec01bb7b6X2'], - filter: { - query: 'host.network.egress.bytes: *', - language: 'kuery', - }, - customLabel: true, - }, - }, - columnOrder: [ - '8d17458d-31af-41d1-a23c-5180fd960bee', - '155fc728-d010-498e-8126-0bc46cad2be2', - '467de550-9186-4e18-8cfa-bce07087801a', - '3eca2307-228e-4842-a023-57e15c8c364d', - '02e9d54c-bbe0-42dc-839c-55080a29838d', - '7802ef93-622c-44df-94fa-03eec01bb7b6', - '0a9bd0fa-9966-489b-8c95-70997a7aad4c', - 'fe5a4d7d-6f48-45ab-974c-96bc864ac36f', - '0a9bd0fa-9966-489b-8c95-70997a7aad4cX0', - 'fe5a4d7d-6f48-45ab-974c-96bc864ac36fX0', - '3eca2307-228e-4842-a023-57e15c8c364dX0', - '3eca2307-228e-4842-a023-57e15c8c364dX1', - '02e9d54c-bbe0-42dc-839c-55080a29838dX0', - '02e9d54c-bbe0-42dc-839c-55080a29838dX1', - '02e9d54c-bbe0-42dc-839c-55080a29838dX2', - '7802ef93-622c-44df-94fa-03eec01bb7b6X0', - '7802ef93-622c-44df-94fa-03eec01bb7b6X1', - '7802ef93-622c-44df-94fa-03eec01bb7b6X2', - ], - incompleteColumns: {}, - indexPatternId: '305688db-9e02-4046-acc1-5d0d8dd73ef6', - }, - }, - }, - }, - visualization: { - layerId: 'cbe5d8a0-381d-49bf-b8ac-f8f312ec7129', - layerType: 'data', - columns: [ - { - columnId: '8d17458d-31af-41d1-a23c-5180fd960bee', - width: 296.16666666666663, - isTransposed: false, - }, - { - columnId: '155fc728-d010-498e-8126-0bc46cad2be2', - isTransposed: false, - width: 152.36666666666667, - }, - { - columnId: '467de550-9186-4e18-8cfa-bce07087801a', - isTransposed: false, - width: 121.11666666666667, - }, - { - columnId: '3eca2307-228e-4842-a023-57e15c8c364d', - isTransposed: false, - }, - { - columnId: '0a9bd0fa-9966-489b-8c95-70997a7aad4c', - isTransposed: false, - }, - { - columnId: 'fe5a4d7d-6f48-45ab-974c-96bc864ac36f', - isTransposed: false, - }, - { - isTransposed: false, - columnId: '02e9d54c-bbe0-42dc-839c-55080a29838d', - }, - { - isTransposed: false, - columnId: '7802ef93-622c-44df-94fa-03eec01bb7b6', - }, - ], - paging: { - size: 10, - enabled: true, - }, - headerRowHeight: 'custom', - headerRowHeightLines: 2, - rowHeight: 'single', - rowHeightLines: 1, - }, - filters: [], - query, - }, - } as TypedLensByValueInput['attributes']); +import React from 'react'; +import { EuiBasicTable } from '@elastic/eui'; +import type { SnapshotNode } from '../../../../../common/http_api'; +import { HostsTableColumns } from './hosts_table_columns'; +import { useHostTable } from '../hooks/use_host_table'; interface Props { - dataView: DataView; - timeRange: TimeRange; - query: Query; - searchSessionId: string; - onRefetch: () => void; - onLoading: (isLoading: boolean) => void; - isLensLoading: boolean; + nodes: SnapshotNode[]; } -export const HostsTable: React.FunctionComponent<Props> = ({ - dataView, - timeRange, - query, - searchSessionId, - onRefetch, - onLoading, - isLensLoading, -}) => { - const { - services: { lens }, - } = useKibana<InfraClientStartDeps>(); - const LensComponent = lens?.EmbeddableComponent; - const [noData, setNoData] = useState(false); - if (noData && !isLensLoading) { - return ( - <NoData - titleText={i18n.translate('xpack.infra.metrics.emptyViewTitle', { - defaultMessage: 'There is no data to display.', - })} - bodyText={i18n.translate('xpack.infra.metrics.emptyViewDescription', { - defaultMessage: 'Try adjusting your time or filter.', - })} - refetchText={i18n.translate('xpack.infra.metrics.refetchButtonLabel', { - defaultMessage: 'Check for new data', - })} - onRefetch={onRefetch} - testString="metricsEmptyViewState" - /> - ); - } +export const HostsTable: React.FunctionComponent<Props> = ({ nodes }) => { + const items = useHostTable(nodes); + return ( - <LensComponent - id="hostsView" - timeRange={timeRange} - attributes={getLensHostsTable(dataView, query)} - searchSessionId={searchSessionId} - onLoad={(isLoading, adapters) => { - if (!isLoading && adapters?.tables) { - setNoData(adapters?.tables.tables.default?.rows.length === 0); - onLoading(false); - } - }} + <EuiBasicTable + tableCaption="Infrastructure metrics for hosts" + items={items} + columns={HostsTableColumns} /> ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table_columns.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table_columns.tsx new file mode 100644 index 0000000000000..7bd8184b0e464 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table_columns.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 { EuiBasicTableColumn } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiText } from '@elastic/eui'; +import { scaleUpPercentage } from '../../../../components/infrastructure_node_metrics_tables/shared/hooks'; +import type { SnapshotNodeMetric } from '../../../../../common/http_api/snapshot_api'; +import { NumberCell } from '../../../../components/infrastructure_node_metrics_tables/shared/components'; + +interface HostNodeRow extends HostMetics { + os?: string | null | undefined; + servicesOnHost?: number | null | undefined; +} + +export interface HostMetics { + cpuCores: SnapshotNodeMetric; + rx: SnapshotNodeMetric; + tx: SnapshotNodeMetric; + memory: SnapshotNodeMetric; + memoryTotal: SnapshotNodeMetric; +} + +export const HostsTableColumns: Array<EuiBasicTableColumn<HostNodeRow>> = [ + { + name: i18n.translate('xpack.infra.hostsTable.nameColumnHeader', { + defaultMessage: 'Name', + }), + field: 'label', + truncateText: true, + textOnly: true, + render: (name: string) => <EuiText size="s">{name}</EuiText>, + }, + { + name: i18n.translate('xpack.infra.hostsTable.operatingSystemColumnHeader', { + defaultMessage: 'Operating System', + }), + field: 'os', + render: (os: string) => <EuiText size="s">{os ?? '-'}</EuiText>, + }, + { + name: i18n.translate('xpack.infra.hostsTable.numberOfCpusColumnHeader', { + defaultMessage: '# of CPUs', + }), + field: 'cpuCores', + render: (cpuCores: { value: number }) => <NumberCell value={cpuCores.value} />, + }, + { + name: i18n.translate('xpack.infra.hostsTable.diskLatencyColumnHeader', { + defaultMessage: 'Disk Latency', + }), + field: 'diskLatency', + render: (ds: number) => <NumberCell value={ds} unit=" ms" />, + }, + { + name: i18n.translate('xpack.infra.hostsTable.averageTxColumnHeader', { + defaultMessage: 'TX (avg.)', + }), + field: 'tx', + render: (tx: { avg: number }) => <NumberCell value={tx.avg} />, + }, + { + name: i18n.translate('xpack.infra.hostsTable.averageRxColumnHeader', { + defaultMessage: 'RX (avg.)', + }), + field: 'rx', + render: (rx: { avg: number }) => <NumberCell value={rx.avg} />, + }, + { + name: i18n.translate('xpack.infra.hostsTable.averageMemoryTotalColumnHeader', { + defaultMessage: 'Memory total (avg.)', + }), + field: 'memoryTotal', + render: (memoryTotal: { avg: number }) => ( + <NumberCell value={Math.floor(memoryTotal.avg)} unit=" MB" /> + ), + }, + { + name: i18n.translate('xpack.infra.hostsTable.servicesOnHostColumnHeader', { + defaultMessage: 'Services on Host', + }), + field: 'servicesOnHost', + render: (servicesOnHost: number) => <NumberCell value={servicesOnHost} />, + }, + { + name: i18n.translate('xpack.infra.hostsTable.averageMemoryUsageColumnHeader', { + defaultMessage: 'Memory usage (avg.)', + }), + field: 'memory', + render: (memory: { avg: number }) => ( + <NumberCell value={scaleUpPercentage(memory.avg)} unit="%" /> + ), + }, +]; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.test.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.test.ts new file mode 100644 index 0000000000000..e0d26413f0453 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.test.ts @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useHostTable } from './use_host_table'; +import { renderHook } from '@testing-library/react-hooks'; + +describe('useHostTable hook', () => { + it('it should map the nodes returned from the snapshot api to a format matching eui table items', () => { + const nodes = [ + { + metrics: [ + { + name: 'rx', + avg: 252456.92916666667, + }, + { + name: 'tx', + avg: 252758.425, + }, + { + name: 'memory', + avg: 0.94525, + }, + { + name: 'cpuCores', + value: 10, + }, + { + name: 'memoryTotal', + avg: 34359.738368, + }, + ], + path: [{ value: 'host-0', label: 'host-0', os: null }], + name: 'host-0', + }, + { + metrics: [ + { + name: 'rx', + avg: 95.86339715321859, + }, + { + name: 'tx', + avg: 110.38566859563191, + }, + { + name: 'memory', + avg: 0.5400000214576721, + }, + { + name: 'cpuCores', + value: 8, + }, + { + name: 'memoryTotal', + avg: 9.194304, + }, + ], + path: [ + { value: 'host-1', label: 'host-1' }, + { value: 'host-1', label: 'host-1', ip: '243.86.94.22', os: 'macOS' }, + ], + name: 'host-1', + }, + ]; + + const items = [ + { + rx: { + name: 'rx', + avg: 252456.92916666667, + }, + tx: { + name: 'tx', + avg: 252758.425, + }, + memory: { + name: 'memory', + avg: 0.94525, + }, + cpuCores: { + name: 'cpuCores', + value: 10, + }, + memoryTotal: { + name: 'memoryTotal', + + avg: 34359.738368, + }, + value: 'host-0', + label: 'host-0', + os: null, + }, + { + rx: { + name: 'rx', + avg: 95.86339715321859, + }, + tx: { + name: 'tx', + avg: 110.38566859563191, + }, + memory: { + name: 'memory', + avg: 0.5400000214576721, + }, + cpuCores: { + name: 'cpuCores', + value: 8, + }, + memoryTotal: { + name: 'memoryTotal', + avg: 9.194304, + }, + value: 'host-1', + label: 'host-1', + ip: '243.86.94.22', + os: 'macOS', + }, + ]; + const result = renderHook(() => useHostTable(nodes)); + + expect(result.result.current).toStrictEqual(items); + }); +}); diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.ts new file mode 100644 index 0000000000000..4c604b2a27217 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_table.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 { last } from 'lodash'; +import { useMemo } from 'react'; +import type { SnapshotNode, SnapshotNodeMetric } from '../../../../../common/http_api'; +import { HostMetics } from '../components/hosts_table_columns'; + +type MappedMetrics = Record<keyof HostMetics, SnapshotNodeMetric>; + +export const useHostTable = (nodes: SnapshotNode[]) => { + const items: MappedMetrics[] = useMemo(() => { + return nodes.map(({ metrics, path }) => ({ + ...last(path), + ...metrics.reduce((data, metric) => { + data[metric.name as keyof HostMetics] = metric; + return data; + }, {} as MappedMetrics), + })); + }, [nodes]); + + return items; +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx index 2fc841d651e21..25aa168ca8dc0 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hosts_content.tsx @@ -6,28 +6,25 @@ */ import type { Query, TimeRange } from '@kbn/es-query'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; import { i18n } from '@kbn/i18n'; import React, { useState, useCallback } from 'react'; import { SearchBar } from '@kbn/unified-search-plugin/public'; +import { EuiSpacer } from '@elastic/eui'; +import { NoData } from '../../../components/empty_states'; import { InfraLoadingPanel } from '../../../components/loading'; import { useMetricsDataViewContext } from './hooks/use_data_view'; import { HostsTable } from './components/hosts_table'; -import { InfraClientStartDeps } from '../../../types'; import { useSourceContext } from '../../../containers/metrics_source'; +import { useSnapshot } from '../inventory_view/hooks/use_snaphot'; +import type { SnapshotMetricType } from '../../../../common/inventory_models/types'; export const HostsContent: React.FunctionComponent = () => { - const { - services: { data }, - } = useKibana<InfraClientStartDeps>(); - const { source } = useSourceContext(); + const { source, sourceId } = useSourceContext(); const [dateRange, setDateRange] = useState<TimeRange>({ from: 'now-15m', to: 'now' }); const [query, setQuery] = useState<Query>({ query: '', language: 'kuery' }); const { metricsDataView, hasFailedCreatingDataView, hasFailedFetchingDataView } = useMetricsDataViewContext(); // needed to refresh the lens table when filters havent changed - const [searchSessionId, setSearchSessionId] = useState(data.search.session.start()); - const [isLensLoading, setIsLensLoading] = useState(false); const onQuerySubmit = useCallback( (payload: { dateRange: TimeRange; query?: Query }) => { @@ -35,52 +32,75 @@ export const HostsContent: React.FunctionComponent = () => { if (payload.query) { setQuery(payload.query); } - setIsLensLoading(true); - setSearchSessionId(data.search.session.start()); }, - [setDateRange, setQuery, data.search.session] + [setDateRange, setQuery] ); - const onLoading = useCallback( - (isLoading: boolean) => { - if (isLensLoading) { - setIsLensLoading(isLoading); - } - }, - [setIsLensLoading, isLensLoading] + const hostMetrics: Array<{ type: SnapshotMetricType }> = [ + { type: 'rx' }, + { type: 'tx' }, + { type: 'memory' }, + { type: 'cpuCores' }, + { type: 'memoryTotal' }, + ]; + + const { loading, nodes, reload } = useSnapshot( + '', // use the unified search query, supported type? + hostMetrics, + [], + 'host', + sourceId, + 1666081614879, // currentTime. need to add support for TimeRange? + '', + '', + true, + { + from: 1666081614879, // dynamic time range needs to be supported + interval: '1m', + lookbackSize: 5, + to: 1666082814879, + } ); - const onRefetch = useCallback(() => { - setIsLensLoading(true); - setSearchSessionId(data.search.session.start()); - }, [data.search.session]); + const noData = !loading && nodes && nodes.length === 0; return ( <div> - {metricsDataView ? ( - <> - <SearchBar - showFilterBar={false} - showDatePicker={true} - showAutoRefreshOnly={false} - showSaveQuery={true} - showQueryInput={true} - query={query} - dateRangeFrom={dateRange.from} - dateRangeTo={dateRange.to} - indexPatterns={[metricsDataView]} - onQuerySubmit={onQuerySubmit} - /> - <HostsTable - dataView={metricsDataView} - timeRange={dateRange} - query={query} - searchSessionId={searchSessionId} - onRefetch={onRefetch} - onLoading={onLoading} - isLensLoading={isLensLoading} + {metricsDataView && !loading ? ( + noData ? ( + <NoData + titleText={i18n.translate('xpack.infra.waffle.noDataTitle', { + defaultMessage: 'There is no data to display.', + })} + bodyText={i18n.translate('xpack.infra.waffle.noDataDescription', { + defaultMessage: 'Try adjusting your time or filter.', + })} + refetchText={i18n.translate('xpack.infra.waffle.checkNewDataButtonLabel', { + defaultMessage: 'Check for new data', + })} + onRefetch={() => { + reload(); + }} + testString="noMetricsDataPrompt" /> - </> + ) : ( + <> + <SearchBar + showFilterBar={false} + showDatePicker={true} + showAutoRefreshOnly={false} + showSaveQuery={true} + showQueryInput={true} + query={query} + dateRangeFrom={dateRange.from} + dateRangeTo={dateRange.to} + indexPatterns={[metricsDataView]} + onQuerySubmit={onQuerySubmit} + /> + <EuiSpacer /> + <HostsTable nodes={nodes} /> + </> + ) ) : hasFailedCreatingDataView || hasFailedFetchingDataView ? ( <div> <div>There was an error trying to load or create the Data View:</div> diff --git a/x-pack/plugins/infra/public/types.ts b/x-pack/plugins/infra/public/types.ts index 461ed1261233a..be8c4d877c61c 100644 --- a/x-pack/plugins/infra/public/types.ts +++ b/x-pack/plugins/infra/public/types.ts @@ -28,7 +28,6 @@ import type { } from '@kbn/observability-plugin/public'; // import type { OsqueryPluginStart } from '../../osquery/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import type { LensPublicStart } from '@kbn/lens-plugin/public'; import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { UnwrapPromise } from '../common/utility_types'; import type { @@ -75,7 +74,6 @@ export interface InfraClientStartDeps { embeddable?: EmbeddableStart; osquery?: unknown; // OsqueryPluginStart; share: SharePluginStart; - lens: LensPublicStart; storage: IStorageWrapper; } diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/apply_metadata_to_last_path.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/apply_metadata_to_last_path.ts index 2931555fc06b0..07fa1ac9cd1cf 100644 --- a/x-pack/plugins/infra/server/routes/snapshot/lib/apply_metadata_to_last_path.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/apply_metadata_to_last_path.ts @@ -46,7 +46,7 @@ export const applyMetadataToLastPath = ( // Set the label as the name and fallback to the id OR path.value lastPath.label = (firstMetaDoc[inventoryFields.name] ?? lastPath.value) as string; // If the inventory fields contain an ip address, we need to try and set that - // on the path object. IP addersses are typically stored as multiple fields. We will + // on the path object. IP addresses are typically stored as multiple fields. We will // use the first IPV4 address we find. if (inventoryFields.ip) { const ipAddresses = get(firstMetaDoc, inventoryFields.ip) as string[]; @@ -56,6 +56,9 @@ export const applyMetadataToLastPath = ( lastPath.ip = ipAddresses; } } + if (inventoryFields.os) { + lastPath.os = get(firstMetaDoc, inventoryFields.os) as string; + } return [...node.path.slice(0, node.path.length - 1), lastPath]; } } diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/transform_request_to_metrics_api_request.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/transform_request_to_metrics_api_request.ts index b7e389cae9126..87fbbdac9a701 100644 --- a/x-pack/plugins/infra/server/routes/snapshot/lib/transform_request_to_metrics_api_request.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/transform_request_to_metrics_api_request.ts @@ -93,6 +93,11 @@ export const transformRequestToMetricsAPIRequest = async ({ if (inventoryFields.ip) { metaAggregation.aggregations[META_KEY].top_metrics.metrics.push({ field: inventoryFields.ip }); } + + if (inventoryFields.os) { + metaAggregation.aggregations[META_KEY].top_metrics.metrics.push({ field: inventoryFields.os }); + } + metricsApiRequest.metrics.push(metaAggregation); if (filters.length) { 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 dcfdebf5c6b82..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<FormulaIndexPatternColumn>['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() @@ -831,47 +844,21 @@ export function FormulaEditor({ </EuiLink> </EuiToolTip> ) : ( - <TooltipWrapper - tooltipContent={i18n.translate( - 'xpack.lens.formula.editorHelpOverlayToolTip', - { - defaultMessage: 'Function reference', - } - )} - condition={!isHelpOpen} - position="top" - delay="regular" - > - <EuiPopover - panelClassName="lnsFormula__docs lnsFormula__docs--overlay" - panelPaddingSize="none" - anchorPosition="leftCenter" - isOpen={isHelpOpen} - closePopover={() => setIsHelpOpen(false)} - button={ - <EuiButtonIcon - className="lnsFormula__editorHelp lnsFormula__editorHelp--overlay" - onClick={() => { - setIsHelpOpen(!isHelpOpen); - }} - iconType="documentation" - color="text" - aria-label={i18n.translate( - 'xpack.lens.formula.editorHelpInlineShowToolTip', - { - defaultMessage: 'Show function reference', - } - )} - /> - } - > - <MemoizedFormulaHelp - isFullscreen={isFullscreen} - indexPattern={indexPattern} - operationDefinitionMap={visibleOperationsMap} - /> - </EuiPopover> - </TooltipWrapper> + <LanguageDocumentationPopover + language="Formula" + sections={documentationSections} + buttonProps={{ + color: 'text', + className: 'lnsFormula__editorHelp lnsFormula__editorHelp--overlay', + 'data-test-subj': 'unifiedTextLangEditor-documentation', + 'aria-label': i18n.translate( + 'xpack.lens.formula.editorHelpInlineShowToolTip', + { + defaultMessage: 'Show function reference', + } + ), + }} + /> )} </EuiFlexItem> @@ -928,12 +915,12 @@ export function FormulaEditor({ </div> </div> + {/* fix the css here */} {isFullscreen && isHelpOpen ? ( - <div className="lnsFormula__docs lnsFormula__docs--inline"> - <MemoizedFormulaHelp - isFullscreen={isFullscreen} - indexPattern={indexPattern} - operationDefinitionMap={visibleOperationsMap} + <div className="lnsFormula__docs documentation__docs--inline"> + <LanguageDocumentationPopoverContent + language="Formula" + sections={documentationSections} /> </div> ) : 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<string, GenericOperationDefinition>; - isFullscreen: boolean; }) { - const [selectedFunction, setSelectedFunction] = useState<string | undefined>(); - const scrollTargets = useRef<Record<string, HTMLElement>>({}); - - 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 ( - <> - <EuiPopoverTitle className="lnsFormula__docsHeader" paddingSize="m"> - {i18n.translate('xpack.lens.formulaDocumentation.header', { - defaultMessage: 'Formula reference', - })} - </EuiPopoverTitle> - - <EuiFlexGroup - className="lnsFormula__docsContent" - gutterSize="none" - responsive={false} - alignItems="stretch" - > - <EuiFlexItem className="lnsFormula__docsSidebar" grow={1}> - <EuiFlexGroup - className="lnsFormula__docsSidebarInner" - direction="column" - gutterSize="none" - responsive={false} - > - <EuiFlexItem className="lnsFormula__docsSearch" grow={false}> - <EuiFieldSearch - value={searchText} - onChange={(e) => { - setSearchText(e.target.value); - }} - placeholder={i18n.translate('xpack.lens.formulaSearchPlaceholder', { - defaultMessage: 'Search functions', - })} - /> - </EuiFlexItem> - - <EuiFlexItem className="lnsFormula__docsNav"> - {filteredHelpGroups.map((helpGroup, index) => { - return ( - <nav className="lnsFormula__docsNavGroup" key={helpGroup.label}> - <EuiTitle size="xxs"> - <h6> - <EuiLink - className="lnsFormula__docsNavGroupLink" - color="text" - onClick={() => { - setSelectedFunction(helpGroup.label); - }} - > - <EuiHighlight search={searchText}>{helpGroup.label}</EuiHighlight> - </EuiLink> - </h6> - </EuiTitle> - - {helpGroup.items.length ? ( - <> - <EuiSpacer size="s" /> - - <EuiListGroup gutterSize="none"> - {helpGroup.items.map((helpItem) => { - return ( - <EuiListGroupItem - key={helpItem.label} - label={ - <EuiHighlight search={searchText}>{helpItem.label}</EuiHighlight> - } - size="s" - onClick={() => { - setSelectedFunction(helpItem.label); - }} - /> - ); - })} - </EuiListGroup> - </> - ) : null} - </nav> - ); - })} - </EuiFlexItem> - </EuiFlexGroup> - </EuiFlexItem> - - <EuiFlexItem className="lnsFormula__docsText" grow={2}> - <EuiText size="s"> - <section - className="lnsFormula__docsTextIntro" - ref={(el) => { - if (el) { - scrollTargets.current[helpGroups[0].label] = el; - } - }} - > - <Markdown - markdown={i18n.translate('xpack.lens.formulaDocumentation.markdown', { - defaultMessage: `## How it works + const sections = { + groups: helpGroups, + initialSection: ( + <Markdown + markdown={i18n.translate('xpack.lens.formulaDocumentation.markdown', { + defaultMessage: `## How it works Lens formulas let you do math using a combination of Elasticsearch aggregations and math functions. There are three main types of functions: @@ -464,9 +321,9 @@ An example formula that uses all of these: \`\`\` round(100 * moving_average( - average(cpu.load.pct), - window=10, - kql='datacenter.name: east*' +average(cpu.load.pct), +window=10, +kql='datacenter.name: east*' )) \`\`\` @@ -482,54 +339,16 @@ queries. If your search has a single quote in it, use a backslash to escape, lik Math functions can take positional arguments, like pow(count(), 3) is the same as count() * count() * count() Use the symbols +, -, /, and * to perform basic math. - `, - description: - 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', - })} - /> - </section> - - {helpGroups.slice(1).map((helpGroup, index) => { - return ( - <section - className="lnsFormula__docsTextGroup" - key={helpGroup.label} - ref={(el) => { - if (el) { - scrollTargets.current[helpGroup.label] = el; - } - }} - > - <h2>{helpGroup.label}</h2> - - <p>{helpGroup.description}</p> - - {helpGroups[index + 1].items.map((helpItem) => { - return ( - <article - className="lnsFormula__docsTextItem" - key={helpItem.label} - ref={(el) => { - if (el) { - scrollTargets.current[helpItem.label] = el; - } - }} - > - {helpItem.description} - </article> - ); - })} - </section> - ); - })} - </EuiText> - </EuiFlexItem> - </EuiFlexGroup> - </> - ); -} + `, + 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/visualizations/metric/visualization.test.ts b/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts index c6194956c2f0b..2a89ef784492d 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts +++ b/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts @@ -758,6 +758,16 @@ describe('metric visualization', () => { `); }); + 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/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts index a7afbbd7e85eb..6d6ff971e7067 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts @@ -40,6 +40,7 @@ describe('ESGeoGridSource', () => { const mockIndexPatternService = { get() { return { + getIndexPattern: () => 'foo-*', fields: { getByName() { return { @@ -310,7 +311,7 @@ describe('ESGeoGridSource', () => { const tileUrl = await mvtGeogridSource.getTileUrl(vectorSourceRequestMeta, '1234', false); expect(tileUrl).toEqual( - "rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&gridPrecision=8&hasLabels=false&requestBody=(foobar%3AES_DSL_PLACEHOLDER%2Cparams%3A('0'%3A('0'%3Aindex%2C'1'%3A(fields%3A()))%2C'1'%3A('0'%3Asize%2C'1'%3A0)%2C'2'%3A('0'%3Afilter%2C'1'%3A!())%2C'3'%3A('0'%3Aquery)%2C'4'%3A('0'%3Aindex%2C'1'%3A(fields%3A()))%2C'5'%3A('0'%3Aquery%2C'1'%3A(language%3AKQL%2Cquery%3A''))%2C'6'%3A('0'%3Aaggs%2C'1'%3A())))&renderAs=heatmap&token=1234" + "rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foo-*&gridPrecision=8&hasLabels=false&requestBody=(foobar%3AES_DSL_PLACEHOLDER%2Cparams%3A('0'%3A('0'%3Aindex%2C'1'%3A(fields%3A()))%2C'1'%3A('0'%3Asize%2C'1'%3A0)%2C'2'%3A('0'%3Afilter%2C'1'%3A!())%2C'3'%3A('0'%3Aquery)%2C'4'%3A('0'%3Aindex%2C'1'%3A(fields%3A()))%2C'5'%3A('0'%3Aquery%2C'1'%3A(language%3AKQL%2Cquery%3A''))%2C'6'%3A('0'%3Aaggs%2C'1'%3A())))&renderAs=heatmap&token=1234" ); }); }); diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx index b0a230bebc3cd..314a2f1205bda 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx @@ -504,9 +504,9 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo refreshToken: string, hasLabels: boolean ): Promise<string> { - const indexPattern = await this.getIndexPattern(); + const dataView = await this.getIndexPattern(); const searchSource = await this.makeSearchSource(searchFilters, 0); - searchSource.setField('aggs', this.getValueAggsDsl(indexPattern)); + searchSource.setField('aggs', this.getValueAggsDsl(dataView)); const mvtUrlServicePath = getHttp().basePath.prepend( `/${GIS_API_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf` @@ -514,7 +514,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo return `${mvtUrlServicePath}\ ?geometryFieldName=${this._descriptor.geoField}\ -&index=${indexPattern.title}\ +&index=${dataView.getIndexPattern()}\ &gridPrecision=${this._getGeoGridPrecisionResolutionDelta()}\ &hasLabels=${hasLabels}\ &requestBody=${encodeMvtResponseBody(searchSource.getSearchRequestBody())}\ diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts index e374989e07892..3d41082dcdf73 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts @@ -37,6 +37,7 @@ describe('ESSearchSource', () => { const mockIndexPatternService = { get() { return { + getIndexPattern: () => 'foobar-title-*', title: 'foobar-title-*', fields: { getByName() { diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index f55f5be747dcd..ae639e9f2121d 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -463,12 +463,9 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } async getSourceIndexList(): Promise<string[]> { - await this.getIndexPattern(); - if (!(this.indexPattern && this.indexPattern.title)) { - return []; - } + const dataView = await this.getIndexPattern(); try { - const { success, matchingIndexes } = await getMatchingIndexes(this.indexPattern.title); + const { success, matchingIndexes } = await getMatchingIndexes(dataView.getIndexPattern()); return success ? matchingIndexes : []; } catch (e) { // Fail silently @@ -497,11 +494,8 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } async _isDrawingIndex(): Promise<boolean> { - await this.getIndexPattern(); - if (!(this.indexPattern && this.indexPattern.title)) { - return false; - } - const { success, isDrawingIndex } = await getIsDrawLayer(this.indexPattern.title); + const dataView = await this.getIndexPattern(); + const { success, isDrawingIndex } = await getIsDrawLayer(dataView.getIndexPattern()); return success && isDrawingIndex; } @@ -511,8 +505,8 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } async getMaxResultWindow(): Promise<number> { - const indexPattern = await this.getIndexPattern(); - const indexSettings = await loadIndexSettings(indexPattern.title); + const dataView = await this.getIndexPattern(); + const indexSettings = await loadIndexSettings(dataView.getIndexPattern()); return indexSettings.maxResultWindow; } @@ -832,8 +826,8 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource refreshToken: string, hasLabels: boolean ): Promise<string> { - const indexPattern = await this.getIndexPattern(); - const indexSettings = await loadIndexSettings(indexPattern.title); + const dataView = await this.getIndexPattern(); + const indexSettings = await loadIndexSettings(dataView.getIndexPattern()); const searchSource = await this.makeSearchSource(searchFilters, indexSettings.maxResultWindow); // searchSource calls dataView.getComputedFields to seed docvalueFields @@ -855,7 +849,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource return fieldName !== this._descriptor.geoField; }) .map((fieldName) => { - const field = indexPattern.fields.getByName(fieldName); + const field = dataView.fields.getByName(fieldName); return field && field.type === 'date' ? { field: fieldName, @@ -876,7 +870,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource return `${mvtUrlServicePath}\ ?geometryFieldName=${this._descriptor.geoField}\ -&index=${indexPattern.title}\ +&index=${dataView.getIndexPattern()}\ &hasLabels=${hasLabels}\ &requestBody=${encodeMvtResponseBody(requestBody)}\ &token=${refreshToken}`; diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/top_hits_form.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/top_hits_form.tsx index 2cbc47e4e9c76..a5786cb0bed0d 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/top_hits_form.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/top_hits_form.tsx @@ -70,8 +70,8 @@ export class TopHitsForm extends Component<Props, State> { async loadIndexSettings() { try { - const indexPattern = await getIndexPatternService().get(this.props.indexPatternId); - const { maxInnerResultWindow } = await loadIndexSettings(indexPattern!.title); + const dataView = await getIndexPatternService().get(this.props.indexPatternId); + const { maxInnerResultWindow } = await loadIndexSettings(dataView.getIndexPattern()); if (this._isMounted) { this.setState({ maxInnerResultWindow }); } diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx index ccd3b3913a085..230c24bb820a7 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/scaling_form.tsx @@ -64,8 +64,8 @@ export class ScalingForm extends Component<Props, State> { async loadIndexSettings() { try { - const indexPattern = await getIndexPatternService().get(this.props.indexPatternId); - const { maxResultWindow } = await loadIndexSettings(indexPattern!.title); + const dataView = await getIndexPatternService().get(this.props.indexPatternId); + const { maxResultWindow } = await loadIndexSettings(dataView.getIndexPattern()); if (this._isMounted) { this.setState({ maxResultWindow: maxResultWindow.toLocaleString() }); } diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts index a1a8a19674a81..0e4ee6d913e32 100644 --- a/x-pack/plugins/maps/public/kibana_services.ts +++ b/x-pack/plugins/maps/public/kibana_services.ts @@ -31,7 +31,7 @@ export const getIsCloud = () => isCloudEnabled; export const getIndexNameFormComponent = () => pluginsStart.fileUpload.IndexNameFormComponent; export const getFileUploadComponent = () => pluginsStart.fileUpload.FileUploadComponent; -export const getIndexPatternService = () => pluginsStart.data.indexPatterns; +export const getIndexPatternService = () => pluginsStart.data.dataViews; export const getAutocompleteService = () => pluginsStart.unifiedSearch.autocomplete; export const getInspector = () => pluginsStart.inspector; export const getFileUpload = () => pluginsStart.fileUpload; diff --git a/x-pack/plugins/maps/public/trigger_actions/visualize_geo_field_action.ts b/x-pack/plugins/maps/public/trigger_actions/visualize_geo_field_action.ts index 55983a54a61a3..fb04e98601b19 100644 --- a/x-pack/plugins/maps/public/trigger_actions/visualize_geo_field_action.ts +++ b/x-pack/plugins/maps/public/trigger_actions/visualize_geo_field_action.ts @@ -63,7 +63,7 @@ export const visualizeGeoFieldAction = createAction<VisualizeFieldContext>({ }); const getMapsLink = async (context: VisualizeFieldContext) => { - const indexPattern = await getIndexPatternService().get(context.dataViewSpec.id!); + const dataView = await getIndexPatternService().get(context.dataViewSpec.id!); // create initial layer descriptor const hasTooltips = context?.contextualFields?.length && context?.contextualFields[0] !== '_source'; @@ -76,7 +76,7 @@ const getMapsLink = async (context: VisualizeFieldContext) => { id: uuid(), type: SOURCE_TYPES.ES_SEARCH, tooltipProperties: hasTooltips ? context.contextualFields : [], - label: indexPattern.title, + label: dataView.getIndexPattern(), indexPatternId: context.dataViewSpec.id, geoField: context.fieldName, scalingType: SCALING_TYPES.MVT, diff --git a/x-pack/plugins/ml/common/types/anomalies.ts b/x-pack/plugins/ml/common/types/anomalies.ts index 9b6218e8c3f34..7fd71a81dfa88 100644 --- a/x-pack/plugins/ml/common/types/anomalies.ts +++ b/x-pack/plugins/ml/common/types/anomalies.ts @@ -183,6 +183,52 @@ export interface AnomalyRecordDoc { * purely single bucket and +5.0 means the anomaly is purely multi bucket. */ multi_bucket_impact?: number; + + /** + * An explanation for the anomaly score + */ + anomaly_score_explanation?: { + /** + * Type of the detected anomaly: spike or dip. + */ + anomaly_type?: 'dip' | 'spike'; + /** + * Length of the detected anomaly in the number of buckets. + */ + anomaly_length?: number; + /** + * Impact of the deviation between actual and typical in the current bucket. + */ + single_bucket_impact?: number; + /** + * Impact of the deviation between actual and typical in the past 12 buckets. + */ + multi_bucket_impact?: number; + /** + * Impact of the statistical properties of the detected anomalous interval. + */ + anomaly_characteristics_impact?: number; + /** + * Lower bound of the 95% confidence interval. + */ + lower_confidence_bound?: number; + /** + * Typical (expected) value for this bucket. + */ + typical_value?: number; + /** + * Upper bound of the 95% confidence interval. + */ + upper_confidence_bound?: number; + /** + * Indicates a reduction of anomaly score for the bucket with large confidence intervals. + */ + high_variance_penalty?: boolean; + /** + * Indicates a reduction of anomaly score if the bucket contains fewer samples than historically expected. + */ + incomplete_bucket_penalty?: boolean; + }; } /** @@ -283,6 +329,21 @@ export interface AnomaliesTableRecord { * Returns true if the anomaly record represented by the table row can be shown in the maps plugin */ isGeoRecord?: boolean; + + /** + * Returns true if the job has the model plot enabled + */ + modelPlotEnabled: boolean; +} + +/** + * Customized version of AnomaliesTableRecord which inserts the detector description + * and rules length. + * Used by the AnomaliesTable component + */ +export interface AnomaliesTableRecordExtended extends AnomaliesTableRecord { + detector: string; + rulesLength?: number; } export type PartitionFieldsType = typeof PARTITION_FIELDS[number]; diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/_anomalies_table.scss b/x-pack/plugins/ml/public/application/components/anomalies_table/_anomalies_table.scss index 813fbdcbe6f1f..06dfacf63a213 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/_anomalies_table.scss +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/_anomalies_table.scss @@ -91,28 +91,6 @@ } .ml-anomalies-table-details { - padding: $euiSizeXS $euiSizeXL; - max-height: 1000px; - overflow-y: auto; - - .anomaly-description-list { - - .euiDescriptionList__title { - margin-top: 0; - flex-basis: 15%; - font-size: inherit; - line-height: 1.5rem; - @include euiTextTruncate; - } - - .euiDescriptionList__description { - margin-top: 0; - flex-basis: 85%; - font-size: inherit; - line-height: 1.5rem; - } - - } + padding: $euiSizeM; } - } diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js index 9becc0dc75d5d..78c2c705c29e9 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js @@ -94,6 +94,8 @@ export class AnomaliesTableInternal extends Component { } } + const job = this.props.selectedJobs.find(({ id }) => id === item.jobId); + itemIdToExpandedRowMap[item.rowId] = ( <AnomalyDetails tabIndex={tab} @@ -104,6 +106,7 @@ export class AnomaliesTableInternal extends Component { filter={this.props.filter} influencerFilter={this.props.influencerFilter} influencersLimit={INFLUENCERS_LIMIT} + job={job} /> ); } @@ -277,4 +280,5 @@ AnomaliesTableInternal.propTypes = { tableState: PropTypes.object.isRequired, updateTableState: PropTypes.func.isRequired, sourceIndicesWithGeoFields: PropTypes.object.isRequired, + selectedJobs: PropTypes.array.isRequired, }; diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_constants.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_constants.ts similarity index 100% rename from x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_constants.js rename to x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_constants.ts diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.js deleted file mode 100644 index a4f8ab231d086..0000000000000 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.js +++ /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. - */ - -/* - * React component for displaying details of an anomaly in the expanded row section - * of the anomalies table. - */ - -import PropTypes from 'prop-types'; -import React, { Component, Fragment } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; - -import { - EuiDescriptionList, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiIconTip, - EuiLink, - EuiSpacer, - EuiTabbedContent, - EuiText, -} from '@elastic/eui'; - -import { getSeverity } from '../../../../common/util/anomaly_utils'; -import { MAX_CHARS } from './anomalies_table_constants'; - -import { getDetailsItems, getInfluencersItems } from './anomaly_details_utils'; - -export class AnomalyDetails extends Component { - static propTypes = { - anomaly: PropTypes.object.isRequired, - examples: PropTypes.array, - definition: PropTypes.object, - isAggregatedData: PropTypes.bool, - filter: PropTypes.func, - influencersLimit: PropTypes.number, - influencerFilter: PropTypes.func, - tabIndex: PropTypes.number.isRequired, - }; - - constructor(props) { - super(props); - this.state = { - showAllInfluencers: false, - }; - - if (this.props.examples !== undefined && this.props.examples.length > 0) { - this.tabs = [ - { - id: 'Details', - name: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.detailsTitle', { - defaultMessage: 'Details', - }), - content: ( - <Fragment> - <div - className="ml-anomalies-table-details" - data-test-subj="mlAnomaliesListRowDetails" - > - {this.renderDescription()} - <EuiSpacer size="m" /> - {this.renderDetails()} - {this.renderInfluencers()} - </div> - </Fragment> - ), - }, - { - id: 'category-examples', - name: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.categoryExamplesTitle', { - defaultMessage: 'Category examples', - }), - content: <Fragment>{this.renderCategoryExamples()}</Fragment>, - }, - ]; - } - } - - toggleAllInfluencers() { - this.setState({ showAllInfluencers: !this.state.showAllInfluencers }); - } - - renderCategoryExamples() { - const { examples, definition } = this.props; - - return ( - <EuiFlexGroup - direction="column" - justifyContent="center" - gutterSize="m" - className="mlAnomalyCategoryExamples" - > - {definition !== undefined && definition.terms && ( - <Fragment> - <EuiFlexItem key={`example-terms`}> - <EuiText size="xs"> - <h4 className="mlAnomalyCategoryExamples__header"> - {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.termsTitle', { - defaultMessage: 'Terms', - })} - </h4> -   - <EuiIconTip - aria-label={i18n.translate( - 'xpack.ml.anomaliesTable.anomalyDetails.termsDescriptionAriaLabel', - { - defaultMessage: 'Description', - } - )} - type="questionInCircle" - color="subdued" - size="s" - content={ - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.termsDescriptionTooltip" - defaultMessage="A space separated list of the common tokens that are matched in values of the category - (may have been truncated to a max character limit of {maxChars})" - values={{ maxChars: MAX_CHARS }} - /> - } - /> - </EuiText> - <EuiText size="xs">{definition.terms}</EuiText> - </EuiFlexItem> - <EuiSpacer size="xs" /> - </Fragment> - )} - {definition !== undefined && definition.regex && ( - <Fragment> - <EuiFlexItem key={`example-regex`}> - <EuiText size="xs"> - <h4 className="mlAnomalyCategoryExamples__header"> - {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.regexTitle', { - defaultMessage: 'Regex', - })} - </h4> -   - <EuiIconTip - aria-label={i18n.translate( - 'xpack.ml.anomaliesTable.anomalyDetails.regexDescriptionAriaLabel', - { - defaultMessage: 'Description', - } - )} - type="questionInCircle" - color="subdued" - size="s" - content={ - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.regexDescriptionTooltip" - defaultMessage="The regular expression that is used to search for values that match the category - (may have been truncated to a max character limit of {maxChars})" - values={{ maxChars: MAX_CHARS }} - /> - } - /> - </EuiText> - <EuiText size="xs">{definition.regex}</EuiText> - </EuiFlexItem> - <EuiSpacer size="xs" /> - </Fragment> - )} - - {examples.map((example, i) => { - return ( - <EuiFlexItem key={`example${i}`}> - {i === 0 && definition !== undefined && ( - <EuiText size="s"> - <h4> - {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.examplesTitle', { - defaultMessage: 'Examples', - })} - </h4> - </EuiText> - )} - <span className="mlAnomalyCategoryExamples__item">{example}</span> - </EuiFlexItem> - ); - })} - </EuiFlexGroup> - ); - } - - renderDescription() { - const anomaly = this.props.anomaly; - const source = anomaly.source; - - let anomalyDescription = i18n.translate( - 'xpack.ml.anomaliesTable.anomalyDetails.anomalyInLabel', - { - defaultMessage: '{anomalySeverity} anomaly in {anomalyDetector}', - values: { - anomalySeverity: getSeverity(anomaly.severity).label, - anomalyDetector: anomaly.detector, - }, - } - ); - if (anomaly.entityName !== undefined) { - anomalyDescription += i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.foundForLabel', { - defaultMessage: ' found for {anomalyEntityName} {anomalyEntityValue}', - values: { - anomalyEntityName: anomaly.entityName, - anomalyEntityValue: anomaly.entityValue, - }, - }); - } - - if ( - source.partition_field_name !== undefined && - source.partition_field_name !== anomaly.entityName - ) { - anomalyDescription += i18n.translate( - 'xpack.ml.anomaliesTable.anomalyDetails.detectedInLabel', - { - defaultMessage: ' detected in {sourcePartitionFieldName} {sourcePartitionFieldValue}', - values: { - sourcePartitionFieldName: source.partition_field_name, - sourcePartitionFieldValue: source.partition_field_value, - }, - } - ); - } - - // Check for a correlatedByFieldValue in the source which will be present for multivariate analyses - // where the record is anomalous due to relationship with another 'by' field value. - let mvDescription = undefined; - if (source.correlated_by_field_value !== undefined) { - mvDescription = i18n.translate( - 'xpack.ml.anomaliesTable.anomalyDetails.multivariateDescription', - { - defaultMessage: - 'multivariate correlations found in {sourceByFieldName}; ' + - '{sourceByFieldValue} is considered anomalous given {sourceCorrelatedByFieldValue}', - values: { - sourceByFieldName: source.by_field_name, - sourceByFieldValue: source.by_field_value, - sourceCorrelatedByFieldValue: source.correlated_by_field_value, - }, - } - ); - } - - return ( - <React.Fragment> - <EuiText size="xs"> - <h4> - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.descriptionTitle" - defaultMessage="Description" - /> - </h4> - {anomalyDescription} - </EuiText> - {mvDescription !== undefined && <EuiText size="xs">{mvDescription}</EuiText>} - </React.Fragment> - ); - } - - renderDetails() { - const detailItems = getDetailsItems(this.props.anomaly, this.props.filter); - const isInterimResult = this.props.anomaly.source?.is_interim ?? false; - return ( - <React.Fragment> - <EuiText size="xs"> - {this.props.isAggregatedData === true ? ( - <h4> - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.detailsOnHighestSeverityAnomalyTitle" - defaultMessage="Details on highest severity anomaly" - /> - </h4> - ) : ( - <h4> - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.anomalyDetailsTitle" - defaultMessage="Anomaly details" - /> - </h4> - )} - {isInterimResult === true && ( - <React.Fragment> - <EuiIcon type="alert" /> - <span className="interim-result"> - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.interimResultLabel" - defaultMessage="Interim result" - /> - </span> - </React.Fragment> - )} - </EuiText> - <EuiDescriptionList - type="column" - listItems={detailItems} - className="anomaly-description-list" - /> - </React.Fragment> - ); - } - - renderInfluencers() { - const anomalyInfluencers = this.props.anomaly.influencers; - let listItems = []; - let othersCount = 0; - let numToDisplay = 0; - if (anomalyInfluencers !== undefined) { - numToDisplay = - this.state.showAllInfluencers === true - ? anomalyInfluencers.length - : Math.min(this.props.influencersLimit, anomalyInfluencers.length); - othersCount = Math.max(anomalyInfluencers.length - numToDisplay, 0); - - if (othersCount === 1) { - // Display the 1 extra influencer as displaying "and 1 more" would also take up a line. - numToDisplay++; - othersCount = 0; - } - - listItems = getInfluencersItems( - anomalyInfluencers, - this.props.influencerFilter, - numToDisplay - ); - } - - if (listItems.length > 0) { - return ( - <React.Fragment> - <EuiSpacer size="m" /> - <EuiText size="xs"> - <h4> - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.influencersTitle" - defaultMessage="Influencers" - /> - </h4> - </EuiText> - <EuiDescriptionList - type="column" - listItems={listItems} - className="anomaly-description-list" - /> - {othersCount > 0 && ( - <EuiLink onClick={() => this.toggleAllInfluencers()}> - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.anomalyDescriptionListMoreLinkText" - defaultMessage="and {othersCount} more" - values={{ othersCount }} - /> - </EuiLink> - )} - {numToDisplay > this.props.influencersLimit + 1 && ( - <EuiLink onClick={() => this.toggleAllInfluencers()}> - <FormattedMessage - id="xpack.ml.anomaliesTable.anomalyDetails.anomalyDescriptionShowLessLinkText" - defaultMessage="Show less" - /> - </EuiLink> - )} - </React.Fragment> - ); - } - } - - render() { - const { tabIndex } = this.props; - - if (this.tabs !== undefined) { - return ( - <EuiTabbedContent - tabs={this.tabs} - size="s" - initialSelectedTab={this.tabs[tabIndex]} - onTabClick={() => {}} - /> - ); - } else { - return ( - <div className="ml-anomalies-table-details" data-test-subj="mlAnomaliesListRowDetails"> - {this.renderDescription()} - <EuiSpacer size="m" /> - {this.renderDetails()} - {this.renderInfluencers()} - </div> - ); - } - } -} diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js index 67f6a9b12dfa1..193c43631013a 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js @@ -6,7 +6,7 @@ */ import React from 'react'; -import { shallowWithIntl, mountWithIntl } from '@kbn/test-jest-helpers'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; import { AnomalyDetails } from './anomaly_details'; const props = { @@ -52,23 +52,25 @@ const props = { influencersLimit: 5, isAggregatedData: true, tabIndex: 0, + job: { + id: 'it-ops-count-by-mlcategory-one', + selected: false, + bucketSpanSeconds: 900, + isSingleMetricViewerJob: false, + sourceIndices: [''], + modelPlotEnabled: false, + }, }; describe('AnomalyDetails', () => { - test('Renders with anomaly details tab selected by default', () => { - const wrapper = shallowWithIntl(<AnomalyDetails {...props} />); - - expect(wrapper.prop('tabs').length).toBe(2); - expect(wrapper.prop('initialSelectedTab').id).toBe('Details'); - }); - - test('Renders with category tab selected when index set to 1', () => { + test('Renders two tabs', () => { const categoryTabProps = { ...props, tabIndex: 1, }; - const wrapper = shallowWithIntl(<AnomalyDetails {...categoryTabProps} />); - expect(wrapper.prop('initialSelectedTab').id).toBe('category-examples'); + const wrapper = mountWithIntl(<AnomalyDetails {...categoryTabProps} />); + expect(wrapper.containsMatchingElement(<span>Details</span>)).toBe(true); + expect(wrapper.containsMatchingElement(<span>Category examples</span>)).toBe(true); }); test('Renders with terms and regex when definition prop is not undefined', () => { diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.tsx b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.tsx new file mode 100644 index 0000000000000..56ff831b57992 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.tsx @@ -0,0 +1,457 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * React component for displaying details of an anomaly in the expanded row section + * of the anomalies table. + */ + +import React, { FC, useState, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { capitalize } from 'lodash'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiIconTip, + EuiLink, + EuiSpacer, + EuiTabbedContent, + EuiText, + useEuiTheme, +} from '@elastic/eui'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + +import { getSeverity } from '../../../../common/util/anomaly_utils'; +import { MAX_CHARS } from './anomalies_table_constants'; +import type { CategoryDefinition } from '../../services/ml_api_service/results'; +import { AnomaliesTableRecordExtended } from '../../../../common/types/anomalies'; +import { EntityCellFilter } from '../entity_cell'; +import { ExplorerJob } from '../../explorer/explorer_utils'; + +import { + getInfluencersItems, + AnomalyExplanationDetails, + DetailsItems, +} from './anomaly_details_utils'; + +interface Props { + anomaly: AnomaliesTableRecordExtended; + examples: string[]; + definition: CategoryDefinition; + isAggregatedData: boolean; + filter: EntityCellFilter; + influencersLimit: number; + influencerFilter: EntityCellFilter; + tabIndex: number; + job: ExplorerJob; +} + +export const AnomalyDetails: FC<Props> = ({ + anomaly, + examples, + definition, + isAggregatedData, + filter, + influencersLimit, + influencerFilter, + tabIndex, + job, +}) => { + if (examples !== undefined && examples.length > 0) { + const tabs = [ + { + id: 'Details', + name: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.detailsTitle', { + defaultMessage: 'Details', + }), + content: ( + <Contents + anomaly={anomaly} + filter={filter} + influencerFilter={influencerFilter} + influencersLimit={influencersLimit} + isAggregatedData={isAggregatedData} + job={job} + /> + ), + }, + { + id: 'category-examples', + name: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.categoryExamplesTitle', { + defaultMessage: 'Category examples', + }), + content: <CategoryExamples examples={examples} definition={definition} />, + }, + ]; + + return ( + <EuiFlexGroup> + <EuiFlexItem> + <EuiTabbedContent + tabs={tabs} + size="s" + initialSelectedTab={tabs[tabIndex]} + onTabClick={() => {}} + /> + </EuiFlexItem> + </EuiFlexGroup> + ); + } + + return ( + <Contents + anomaly={anomaly} + filter={filter} + influencerFilter={influencerFilter} + influencersLimit={influencersLimit} + isAggregatedData={isAggregatedData} + job={job} + /> + ); +}; + +const Contents: FC<{ + anomaly: AnomaliesTableRecordExtended; + isAggregatedData: boolean; + filter: EntityCellFilter; + influencersLimit: number; + influencerFilter: EntityCellFilter; + job: ExplorerJob; +}> = ({ anomaly, isAggregatedData, filter, influencersLimit, influencerFilter, job }) => { + const { + euiTheme: { colors }, + } = useEuiTheme(); + + const dividerStyle = useMemo(() => { + return isPopulatedObject(anomaly.source.anomaly_score_explanation) + ? { borderRight: `1px solid ${colors.lightShade}` } + : {}; + }, [colors, anomaly]); + + return ( + <EuiFlexGroup> + <EuiFlexItem> + <div className="ml-anomalies-table-details" data-test-subj="mlAnomaliesListRowDetails"> + <Description anomaly={anomaly} /> + <EuiSpacer size="m" /> + + <EuiFlexGroup gutterSize="l"> + <EuiFlexItem css={dividerStyle}> + <Details + anomaly={anomaly} + isAggregatedData={isAggregatedData} + filter={filter} + job={job} + /> + <Influencers + anomaly={anomaly} + influencerFilter={influencerFilter} + influencersLimit={influencersLimit} + /> + </EuiFlexItem> + <EuiFlexItem> + <AnomalyExplanationDetails anomaly={anomaly} /> + </EuiFlexItem> + </EuiFlexGroup> + </div> + </EuiFlexItem> + </EuiFlexGroup> + ); +}; + +const Description: FC<{ anomaly: AnomaliesTableRecordExtended }> = ({ anomaly }) => { + const source = anomaly.source; + + let anomalyDescription = i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.anomalyInLabel', { + defaultMessage: '{anomalySeverity} anomaly in {anomalyDetector}', + values: { + anomalySeverity: capitalize(getSeverity(anomaly.severity).label), + anomalyDetector: anomaly.detector, + }, + }); + if (anomaly.entityName !== undefined) { + anomalyDescription += i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.foundForLabel', { + defaultMessage: ' found for {anomalyEntityName} {anomalyEntityValue}', + values: { + anomalyEntityName: anomaly.entityName, + anomalyEntityValue: anomaly.entityValue, + }, + }); + } + + if ( + source.partition_field_name !== undefined && + source.partition_field_name !== anomaly.entityName + ) { + anomalyDescription += i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.detectedInLabel', { + defaultMessage: ' detected in {sourcePartitionFieldName} {sourcePartitionFieldValue}', + values: { + sourcePartitionFieldName: source.partition_field_name, + sourcePartitionFieldValue: source.partition_field_value, + }, + }); + } + + // Check for a correlatedByFieldValue in the source which will be present for multivariate analyses + // where the record is anomalous due to relationship with another 'by' field value. + let mvDescription; + if (source.correlated_by_field_value !== undefined) { + mvDescription = i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.multivariateDescription', + { + defaultMessage: + 'multivariate correlations found in {sourceByFieldName}; ' + + '{sourceByFieldValue} is considered anomalous given {sourceCorrelatedByFieldValue}', + values: { + sourceByFieldName: source.by_field_name, + sourceByFieldValue: source.by_field_value, + sourceCorrelatedByFieldValue: source.correlated_by_field_value, + }, + } + ); + } + + return ( + <> + <EuiText size="xs"> + <h4> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.descriptionTitle" + defaultMessage="Description" + /> + </h4> + {anomalyDescription} + </EuiText> + {mvDescription !== undefined && <EuiText size="xs">{mvDescription}</EuiText>} + </> + ); +}; + +const Details: FC<{ + anomaly: AnomaliesTableRecordExtended; + isAggregatedData: boolean; + filter: EntityCellFilter; + job: ExplorerJob; +}> = ({ anomaly, isAggregatedData, filter, job }) => { + const isInterimResult = anomaly.source?.is_interim ?? false; + return ( + <> + <EuiText size="xs"> + {isAggregatedData === true ? ( + <h4> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.detailsOnHighestSeverityAnomalyTitle" + defaultMessage="Details on highest severity anomaly" + /> + </h4> + ) : ( + <h4> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyDetailsTitle" + defaultMessage="Anomaly details" + /> + </h4> + )} + {isInterimResult === true && ( + <> + <EuiIcon type="alert" /> + <span className="interim-result"> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.interimResultLabel" + defaultMessage="Interim result" + /> + </span> + </> + )} + </EuiText> + + <EuiSpacer size="xs" /> + + <DetailsItems anomaly={anomaly} filter={filter} modelPlotEnabled={job.modelPlotEnabled} /> + </> + ); +}; + +const Influencers: FC<{ + anomaly: AnomaliesTableRecordExtended; + influencersLimit: number; + influencerFilter: EntityCellFilter; +}> = ({ anomaly, influencersLimit, influencerFilter }) => { + const [showAllInfluencers, setShowAllInfluencers] = useState(false); + const toggleAllInfluencers = setShowAllInfluencers.bind(null, (prev) => !prev); + + const anomalyInfluencers = anomaly.influencers; + let listItems: Array<{ title: string; description: React.ReactElement }> = []; + let othersCount = 0; + let numToDisplay = 0; + if (anomalyInfluencers !== undefined) { + numToDisplay = + showAllInfluencers === true + ? anomalyInfluencers.length + : Math.min(influencersLimit, anomalyInfluencers.length); + othersCount = Math.max(anomalyInfluencers.length - numToDisplay, 0); + + if (othersCount === 1) { + // Display the 1 extra influencer as displaying "and 1 more" would also take up a line. + numToDisplay++; + othersCount = 0; + } + + listItems = getInfluencersItems(anomalyInfluencers, influencerFilter, numToDisplay); + } + + if (listItems.length > 0) { + return ( + <> + <EuiSpacer size="m" /> + <EuiText size="xs"> + <h4> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.influencersTitle" + defaultMessage="Influencers" + /> + </h4> + </EuiText> + + {listItems.map(({ title, description }) => ( + <> + <EuiFlexGroup gutterSize="none"> + <EuiFlexItem style={{ width: '180px' }} grow={false}> + {title} + </EuiFlexItem> + <EuiFlexItem>{description}</EuiFlexItem> + </EuiFlexGroup> + <EuiSpacer size="xs" /> + </> + ))} + {othersCount > 0 && ( + <EuiLink onClick={() => toggleAllInfluencers()}> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyDescriptionListMoreLinkText" + defaultMessage="and {othersCount} more" + values={{ othersCount }} + /> + </EuiLink> + )} + {numToDisplay > influencersLimit + 1 && ( + <EuiLink onClick={() => toggleAllInfluencers()}> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyDescriptionShowLessLinkText" + defaultMessage="Show less" + /> + </EuiLink> + )} + </> + ); + } + return null; +}; + +const CategoryExamples: FC<{ definition: CategoryDefinition; examples: string[] }> = ({ + definition, + examples, +}) => { + return ( + <EuiFlexGroup + direction="column" + justifyContent="center" + gutterSize="m" + className="mlAnomalyCategoryExamples" + > + {definition !== undefined && definition.terms && ( + <> + <EuiFlexItem key={`example-terms`}> + <EuiText size="xs"> + <h4 className="mlAnomalyCategoryExamples__header"> + {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.termsTitle', { + defaultMessage: 'Terms', + })} + </h4> +   + <EuiIconTip + aria-label={i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.termsDescriptionAriaLabel', + { + defaultMessage: 'Description', + } + )} + type="questionInCircle" + color="subdued" + size="s" + content={ + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.termsDescriptionTooltip" + defaultMessage="A space separated list of the common tokens that are matched in values of the category + (may have been truncated to a max character limit of {maxChars})" + values={{ maxChars: MAX_CHARS }} + /> + } + /> + </EuiText> + <EuiText size="xs">{definition.terms}</EuiText> + </EuiFlexItem> + <EuiSpacer size="xs" /> + </> + )} + {definition !== undefined && definition.regex && ( + <> + <EuiFlexItem key={`example-regex`}> + <EuiText size="xs"> + <h4 className="mlAnomalyCategoryExamples__header"> + {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.regexTitle', { + defaultMessage: 'Regex', + })} + </h4> +   + <EuiIconTip + aria-label={i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.regexDescriptionAriaLabel', + { + defaultMessage: 'Description', + } + )} + type="questionInCircle" + color="subdued" + size="s" + content={ + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.regexDescriptionTooltip" + defaultMessage="The regular expression that is used to search for values that match the category + (may have been truncated to a max character limit of {maxChars})" + values={{ maxChars: MAX_CHARS }} + /> + } + /> + </EuiText> + <EuiText size="xs">{definition.regex}</EuiText> + </EuiFlexItem> + <EuiSpacer size="xs" /> + </> + )} + + {examples.map((example, i) => { + return ( + <EuiFlexItem key={`example${i}`}> + {i === 0 && definition !== undefined && ( + <EuiText size="s"> + <h4> + {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.examplesTitle', { + defaultMessage: 'Examples', + })} + </h4> + </EuiText> + )} + <span className="mlAnomalyCategoryExamples__item">{example}</span> + </EuiFlexItem> + ); + })} + </EuiFlexGroup> + ); +}; diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx index 89eedee36f344..17d479de1db8d 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx @@ -5,20 +5,28 @@ * 2.0. */ -import React from 'react'; +import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiToolTip, EuiIcon } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + EuiToolTip, + EuiIcon, + EuiFlexGroup, + EuiFlexItem, + useEuiTheme, + EuiText, + EuiSpacer, +} from '@elastic/eui'; import { EntityCell, EntityCellFilter } from '../entity_cell'; import { formatHumanReadableDateTimeSeconds } from '../../../../common/util/date_utils'; import { - getMultiBucketImpactLabel, showActualForFunction, showTypicalForFunction, } from '../../../../common/util/anomaly_utils'; -import { MULTI_BUCKET_IMPACT } from '../../../../common/constants/multi_bucket_impact'; -import { AnomaliesTableRecord } from '../../../../common/types/anomalies'; +import { AnomaliesTableRecord, MLAnomalyDoc } from '../../../../common/types/anomalies'; import { formatValue } from '../../formatters/format_value'; import { ML_JOB_AGGREGATION } from '../../../../common/constants/aggregation_types'; +import { getSeverityColor } from '../../../../common/util/anomaly_utils'; const TIME_FIELD_NAME = 'timestamp'; @@ -54,7 +62,11 @@ export function getInfluencersItems( return items; } -export function getDetailsItems(anomaly: AnomaliesTableRecord, filter: EntityCellFilter) { +export const DetailsItems: FC<{ + anomaly: AnomaliesTableRecord; + filter: EntityCellFilter; + modelPlotEnabled: boolean; +}> = ({ anomaly, filter, modelPlotEnabled }) => { const source = anomaly.source; // TODO - when multivariate analyses are more common, @@ -172,6 +184,31 @@ export function getDetailsItems(anomaly: AnomaliesTableRecord, filter: EntityCel }), description: formatValue(anomaly.typical, source.function, undefined, source), }); + + if ( + modelPlotEnabled === false && + anomaly.source.anomaly_score_explanation?.lower_confidence_bound !== undefined && + anomaly.source.anomaly_score_explanation?.upper_confidence_bound !== undefined + ) { + items.push({ + title: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.upperBoundsTitle', { + defaultMessage: 'Upper bounds', + }), + description: formatValue(anomaly.typical, source.function, undefined, source), + }); + + items.push({ + title: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.lowerBoundsTitle', { + defaultMessage: 'Lower bounds', + }), + description: formatValue( + anomaly.source.anomaly_score_explanation?.lower_confidence_bound, + source.function, + undefined, + source + ), + }); + } } items.push({ @@ -181,18 +218,6 @@ export function getDetailsItems(anomaly: AnomaliesTableRecord, filter: EntityCel description: anomaly.jobId, }); - if ( - source.multi_bucket_impact !== undefined && - source.multi_bucket_impact >= MULTI_BUCKET_IMPACT.LOW - ) { - items.push({ - title: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.multiBucketImpactTitle', { - defaultMessage: 'Multi-bucket impact', - }), - description: getMultiBucketImpactLabel(source.multi_bucket_impact), - }); - } - items.push({ title: ( <EuiToolTip @@ -241,7 +266,7 @@ export function getDetailsItems(anomaly: AnomaliesTableRecord, filter: EntityCel defaultMessage: 'Probability', }), description: - // @ts-expect-error parseFloat accept take a number + // @ts-expect-error parseFloat accepts a number source.probability !== undefined ? Number.parseFloat(source.probability).toPrecision(3) : '', }); @@ -276,5 +301,422 @@ export function getDetailsItems(anomaly: AnomaliesTableRecord, filter: EntityCel }); } - return items; + return ( + <> + {items.map(({ title, description }) => ( + <> + <EuiFlexGroup gutterSize="none"> + <EuiFlexItem css={{ width: '180px' }} grow={false}> + {title} + </EuiFlexItem> + <EuiFlexItem>{description}</EuiFlexItem> + </EuiFlexGroup> + <EuiSpacer size="xs" /> + </> + ))} + </> + ); +}; + +export const AnomalyExplanationDetails: FC<{ anomaly: AnomaliesTableRecord }> = ({ anomaly }) => { + const explanation = anomaly.source.anomaly_score_explanation; + if (explanation === undefined) { + return null; + } + const initialScore = Math.floor(1000 * anomaly.source.initial_record_score) / 1000; + const finalScore = Math.floor(1000 * anomaly.source.record_score) / 1000; + const scoreDifference = initialScore - finalScore; + const ACCEPTABLE_NORMALIZATION = 10; + + const yes = i18n.translate('xpack.ml.anomaliesTable.anomalyExplanationDetails.yes', { + defaultMessage: 'Yes', + }); + const no = i18n.translate('xpack.ml.anomaliesTable.anomalyExplanationDetails.no', { + defaultMessage: 'No', + }); + + const explanationDetails = []; + const anomalyType = getAnomalyType(explanation); + if (anomalyType !== null) { + explanationDetails.push({ + title: ( + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.anomalyType" + defaultMessage="Anomaly type" + /> + ), + description: <>{anomalyType}</>, + }); + } + + if (scoreDifference > ACCEPTABLE_NORMALIZATION) { + explanationDetails.push({ + title: ( + <EuiToolTip + position="left" + content={i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.recordScoreTooltip', + { + defaultMessage: + 'The initial record score has been reduced based on the analysis of subsequent data.', + } + )} + > + <span> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.recordScore" + defaultMessage="Record score reduction" + /> + <EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" /> + </span> + </EuiToolTip> + ), + description: ( + <EuiFlexGroup gutterSize="xs"> + <EuiFlexItem grow={false}> + <RecordScore score={initialScore} /> + </EuiFlexItem> + <EuiFlexItem grow={false}>{` -> `}</EuiFlexItem> + <EuiFlexItem grow={false}> + <RecordScore score={finalScore} /> + </EuiFlexItem> + </EuiFlexGroup> + ), + }); + } + + const impactDetails = []; + + if (explanation.anomaly_characteristics_impact !== undefined) { + impactDetails.push({ + title: ( + <EuiToolTip + position="left" + content={getImpactTooltip( + explanation.anomaly_characteristics_impact, + 'anomaly_characteristics' + )} + > + <span> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.anomalyCharacteristics" + defaultMessage="Anomaly characteristics impact" + /> + <EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" /> + </span> + </EuiToolTip> + ), + description: <ImpactVisual score={explanation.anomaly_characteristics_impact} />, + }); + } + + if (explanation.single_bucket_impact !== undefined) { + impactDetails.push({ + title: ( + <EuiToolTip + position="left" + content={getImpactTooltip(explanation.single_bucket_impact, 'single_bucket')} + > + <span> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.singleBucket" + defaultMessage="Single bucket impact" + /> + <EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" /> + </span> + </EuiToolTip> + ), + description: <ImpactVisual score={explanation.single_bucket_impact} />, + }); + } + if (explanation.multi_bucket_impact !== undefined) { + impactDetails.push({ + title: ( + <EuiToolTip + position="left" + content={getImpactTooltip(explanation.multi_bucket_impact, 'multi_bucket')} + > + <span> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multiBucket" + defaultMessage="Multi bucket impact" + /> + <EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" /> + </span> + </EuiToolTip> + ), + description: <ImpactVisual score={explanation.multi_bucket_impact} />, + }); + } + if (explanation.high_variance_penalty !== undefined) { + impactDetails.push({ + title: ( + <EuiToolTip + position="left" + content={i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.highVarianceTooltip', + { + defaultMessage: + 'Indicates reduction of anomaly score for the bucket with large confidence intervals. If a bucket has large confidence intervals, the score is reduced.', + } + )} + > + <span> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.highVariance" + defaultMessage="High variance interval" + /> + <EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" /> + </span> + </EuiToolTip> + ), + description: explanation.high_variance_penalty ? yes : no, + }); + } + if (explanation.incomplete_bucket_penalty !== undefined) { + impactDetails.push({ + title: ( + <EuiToolTip + position="left" + content={i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.incompleteBucketTooltip', + { + defaultMessage: + 'If the bucket contains fewer samples than expected, the score is reduced. If the bucket contains fewer samples than expected, the score is reduced.', + } + )} + > + <span> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.incompleteBucket" + defaultMessage="Incomplete bucket" + /> + <EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" /> + </span> + </EuiToolTip> + ), + description: explanation.incomplete_bucket_penalty ? yes : no, + }); + } + + return ( + <div> + <EuiText size="xs"> + <h4> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationTitle" + defaultMessage="Anomaly explanation" + /> + </h4> + </EuiText> + <EuiSpacer size="s" /> + + {explanationDetails.map(({ title, description }) => ( + <> + <EuiFlexGroup gutterSize="none"> + <EuiFlexItem style={{ width: '220px' }} grow={false}> + {title} + </EuiFlexItem> + <EuiFlexItem>{description}</EuiFlexItem> + </EuiFlexGroup> + <EuiSpacer size="xs" /> + </> + ))} + + <EuiSpacer size="s" /> + {impactDetails.length ? ( + <> + <EuiText size="xs"> + <h4> + <FormattedMessage + id="xpack.ml.anomaliesTable.anomalyDetails.impactOnScoreTitle" + defaultMessage="Impact on initial score" + /> + </h4> + </EuiText> + <EuiSpacer size="s" /> + + {impactDetails.map(({ title, description }) => ( + <> + <EuiFlexGroup gutterSize="none"> + <EuiFlexItem css={{ width: '220px' }} grow={false}> + {title} + </EuiFlexItem> + <EuiFlexItem>{description}</EuiFlexItem> + </EuiFlexGroup> + <EuiSpacer size="xs" /> + </> + ))} + </> + ) : null} + </div> + ); +}; + +const RecordScore: FC<{ score: number }> = ({ score }) => { + return ( + <div + css={{ + borderBottom: '2px solid', + }} + style={{ + borderBottomColor: getSeverityColor(score), + }} + > + {score} + </div> + ); +}; + +function getAnomalyType(explanation: MLAnomalyDoc['anomaly_score_explanation']) { + if ( + explanation === undefined || + explanation.anomaly_length === undefined || + explanation.anomaly_type === undefined + ) { + return null; + } + + const dip = i18n.translate('xpack.ml.anomaliesTable.anomalyExplanationDetails.anomalyType.dip', { + defaultMessage: 'Dip over {anomalyLength, plural, one {# bucket} other {# buckets}}', + values: { anomalyLength: explanation.anomaly_length }, + }); + const spike = i18n.translate( + 'xpack.ml.anomaliesTable.anomalyExplanationDetails.anomalyType.spike', + { + defaultMessage: 'Spike over {anomalyLength, plural, one {# bucket} other {# buckets}}', + values: { anomalyLength: explanation.anomaly_length }, + } + ); + + return explanation.anomaly_type === 'dip' ? dip : spike; +} + +function getImpactValue(score: number) { + if (score < 2) return 1; + if (score < 4) return 2; + if (score < 7) return 3; + if (score < 12) return 4; + return 5; } + +const impactTooltips = { + anomaly_characteristics: { + low: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.anomalyCharacteristicsTooltip.low', + { + defaultMessage: + 'Moderate impact from the duration and magnitude of the detected anomaly relative to the historical average.', + } + ), + medium: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.anomalyCharacteristicsTooltip.medium', + { + defaultMessage: + 'Medium impact from the duration and magnitude of the detected anomaly relative to the historical average.', + } + ), + high: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.anomalyCharacteristicsTooltip.high', + { + defaultMessage: + 'High impact from the duration and magnitude of the detected anomaly relative to the historical average.', + } + ), + }, + single_bucket: { + low: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.singleBucketTooltip.low', + { + defaultMessage: + 'The difference between actual and typical values in this bucket has a moderate impact.', + } + ), + medium: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.singleBucketTooltip.medium', + { + defaultMessage: + 'The difference between actual and typical values in this bucket has a significant impact.', + } + ), + high: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.singleBucketTooltip.high', + { + defaultMessage: + 'The difference between actual and typical values in this bucket has a high impact.', + } + ), + }, + multi_bucket: { + low: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multiBucketTooltip.low', + { + defaultMessage: + 'The differences between actual and typical values in the past 12 buckets have a moderate impact.', + } + ), + medium: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multiBucketTooltip.medium', + { + defaultMessage: + 'The differences between actual and typical values in the past 12 buckets have a significant impact.', + } + ), + high: i18n.translate( + 'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multiBucketTooltip.high', + { + defaultMessage: + 'The differences between actual and typical values in the past 12 buckets have a high impact.', + } + ), + }, +}; + +function getImpactTooltip( + score: number, + type: 'anomaly_characteristics' | 'single_bucket' | 'multi_bucket' +) { + const value = getImpactValue(score); + + if (value < 3) { + return impactTooltips[type].low; + } + if (value > 3) { + return impactTooltips[type].high; + } + + return impactTooltips[type].medium; +} + +const ImpactVisual: FC<{ score: number }> = ({ score }) => { + const { + euiTheme: { colors }, + } = useEuiTheme(); + + const impact = getImpactValue(score); + const boxPx = '10px'; + const emptyBox = colors.lightShade; + const fullBox = colors.primary; + return ( + <EuiFlexGroup gutterSize="xs"> + {Array(5) + .fill(null) + .map((v, i) => { + return ( + <EuiFlexItem grow={false}> + <div + css={{ + height: boxPx, + width: boxPx, + borderRadius: '2px', + }} + style={{ + backgroundColor: impact > i ? fullBox : emptyBox, + }} + /> + </EuiFlexItem> + ); + })} + </EuiFlexGroup> + ); +}; 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<Props> = ({ }; 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<Props> = ({ color="danger" iconType="cross" > - <p>{indexPatternErrorMessage}</p> + <p> + {indexPatternErrorMessage} + {needsDestIndexPattern ? ( + <IndexPatternPrompt destIndex={destIndex} color="text" /> + ) : null} + </p> </EuiCallOut> </EuiPanel> ); 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<Props> = ({ destIndex }) => { +export const IndexPatternPrompt: FC<Props> = ({ destIndex, color }) => { const { services: { http: { basePath }, @@ -30,20 +31,20 @@ export const IndexPatternPrompt: FC<Props> = ({ destIndex }) => { return ( <> - <EuiText size="xs" color="warning"> + <EuiText size="xs" color={color ?? 'warning'}> <FormattedMessage id="xpack.ml.dataframe.analytics.dataViewPromptMessage" defaultMessage="No data view exists for index {destIndex}. " values={{ - destIndex, + destIndex: destIndex ?? '', }} /> {canCreateDataView === true ? ( <FormattedMessage id="xpack.ml.dataframe.analytics.dataViewPromptLink" - defaultMessage="{linkToDataViewManagement} for {destIndex}." + defaultMessage="{linkToDataViewManagement}{destIndex}." values={{ - destIndex, + destIndex: destIndex ? ` for ${destIndex}` : '', linkToDataViewManagement: ( <EuiLink href={`${basePath.get()}/app/management/kibana/dataViews/create`} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx index 8086ee4f573bc..93ceccf2756dc 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx @@ -19,7 +19,12 @@ import { import { useScatterplotFieldOptions } from '../../../../../components/scatterplot_matrix'; import { SavedSearchQuery } from '../../../../../contexts/ml'; -import { defaultSearchQuery, isOutlierAnalysis, useResultsViewConfig } from '../../../../common'; +import { + defaultSearchQuery, + isOutlierAnalysis, + useResultsViewConfig, + getDestinationIndex, +} from '../../../../common'; import { FEATURE_INFLUENCE } from '../../../../common/constants'; import { @@ -33,6 +38,7 @@ import { getFeatureCount } from './common'; import { useOutlierData } from './use_outlier_data'; import { useExplorationUrlState } from '../../hooks/use_exploration_url_state'; import { ExplorationQueryBarProps } from '../exploration_query_bar/exploration_query_bar'; +import { IndexPatternPrompt } from '../index_pattern_prompt'; export type TableItem = Record<string, any>; @@ -90,6 +96,7 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) = jobConfig?.analyzed_fields?.excludes, resultsField ); + const destIndex = getDestinationIndex(jobConfig); if (indexPatternErrorMessage !== undefined) { return ( @@ -101,7 +108,12 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) = color="danger" iconType="cross" > - <p>{indexPatternErrorMessage}</p> + <p> + {indexPatternErrorMessage} + {needsDestIndexPattern ? ( + <IndexPatternPrompt destIndex={destIndex} color="text" /> + ) : null} + </p> </EuiCallOut> </EuiPanel> ); 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<DataFrameAnalyticsListRow, 'config' | 'stats'>) => { 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( + <> + <FormattedMessage + id="xpack.ml.dataframe.analyticsList.noSourceDataViewForClone" + defaultMessage="Unable to clone the analytics job. No data view exists for index {sourceIndex}." + values={{ sourceIndex }} + /> + {canCreateDataView ? ( + <EuiText size="xs" color="text"> + <FormattedMessage + id="xpack.ml.dataframe.analytics.cloneAction.dataViewPromptLink" + defaultMessage="{linkToDataViewManagement}" + values={{ + linkToDataViewManagement: ( + <EuiLink + href={`${basePath.get()}/app/management/kibana/dataViews/create`} + target="_blank" + > + <FormattedMessage + id="xpack.ml.dataframe.analytics.cloneAction.dataViewPromptLinkText" + defaultMessage="Create a data view for {sourceIndex}" + values={{ sourceIndex }} + /> + </EuiLink> + ), + }} + /> + </EuiText> + ) : null} + </>, + theme$ + ) + ), + }); } } catch (e) { const error = extractErrorMessage(e); diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.tsx b/x-pack/plugins/ml/public/application/explorer/explorer.tsx index 5fcab05f068b8..35fa1baf5460b 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.tsx +++ b/x-pack/plugins/ml/public/application/explorer/explorer.tsx @@ -609,6 +609,7 @@ export const Explorer: FC<ExplorerUIProps> = ({ tableData={tableData} influencerFilter={applyFilter} sourceIndicesWithGeoFields={sourceIndicesWithGeoFields} + selectedJobs={selectedJobs} /> </EuiPanel> )} diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts b/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts index 652517acc0dab..9fd9e4aaff576 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts @@ -57,6 +57,7 @@ export interface ExplorerJob { bucketSpanSeconds: number; isSingleMetricViewerJob?: boolean; sourceIndices?: string[]; + modelPlotEnabled: boolean; } export function isExplorerJob(arg: unknown): arg is ExplorerJob { @@ -143,6 +144,7 @@ export function createJobs(jobs: CombinedJob[]): ExplorerJob[] { bucketSpanSeconds: bucketSpan!.asSeconds(), isSingleMetricViewerJob: isTimeSeriesViewJob(job), sourceIndices: job.datafeed_config.indices, + modelPlotEnabled: job.model_plot_config?.enabled === true, }; }); } diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/results.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/results.ts index fbfdefed7950e..bbc2f36605483 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/results.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/results.ts @@ -26,6 +26,13 @@ import type { EntityField } from '../../../../common/util/anomaly_utils'; import type { InfluencersFilterQuery } from '../../../../common/types/es_client'; import type { ExplorerChartsData } from '../../../../common/types/results'; +export interface CategoryDefinition { + categoryId: number; + terms: string; + regex: string; + examples: string[]; +} + export const resultsApiProvider = (httpService: HttpService) => ({ getAnomaliesTableData( jobIds: string[], @@ -78,7 +85,7 @@ export const resultsApiProvider = (httpService: HttpService) => ({ getCategoryDefinition(jobId: string, categoryId: string) { const body = JSON.stringify({ jobId, categoryId }); - return httpService.http<any>({ + return httpService.http<CategoryDefinition>({ path: `${basePath()}/results/category_definition`, method: 'POST', body, diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 2005e7c878f7a..a4a12d3b17a6b 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -1317,6 +1317,12 @@ export class TimeSeriesExplorer extends React.Component { tableData={tableData} filter={this.tableFilter} sourceIndicesWithGeoFields={sourceIndicesWithGeoFields} + selectedJobs={[ + { + id: selectedJob.job_id, + modelPlotEnabled, + }, + ]} /> )} </TimeSeriesExplorerPage> diff --git a/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts b/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts index 451eb95b4f801..c2a329a0ba650 100644 --- a/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts +++ b/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts @@ -29,6 +29,7 @@ export function getJobsObservable( id: job.job_id, selected: true, bucketSpanSeconds: bucketSpan!.asSeconds(), + modelPlotEnabled: job.model_plot_config?.enabled === true, }; }); return explorerJobs; diff --git a/x-pack/plugins/ml/server/models/results_service/results_service.ts b/x-pack/plugins/ml/server/models/results_service/results_service.ts index 2b6ae2d2b51e7..deb222ef6b3bd 100644 --- a/x-pack/plugins/ml/server/models/results_service/results_service.ts +++ b/x-pack/plugins/ml/server/models/results_service/results_service.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { sortBy, slice, get, cloneDeep } from 'lodash'; import moment from 'moment'; import Boom from '@hapi/boom'; @@ -225,8 +226,8 @@ export function resultsServiceProvider(mlClient: MlClient, client?: IScopedClust anomalies: [], interval: 'second', }; - // @ts-expect-error incorrect search response type - if (body.hits.total.value > 0) { + + if ((body.hits.total as estypes.SearchTotalHits).value > 0) { let records: AnomalyRecordDoc[] = []; body.hits.hits.forEach((hit: any) => { records.push(hit._source); 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 d1fdd6bc7cf67..ecc58776c07f6 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 @@ -41,7 +41,7 @@ describe('Lens Attribute', () => { seriesConfig: reportViewConfig, seriesType: 'line', operationType: 'count', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: {}, time: { from: 'now-15m', to: 'now' }, color: 'green', @@ -76,7 +76,7 @@ describe('Lens Attribute', () => { seriesConfig: seriesConfigKpi, seriesType: 'line', operationType: 'count', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: { 'service.name': ['elastic-co'] }, time: { from: 'now-15m', to: 'now' }, color: 'green', @@ -107,7 +107,7 @@ describe('Lens Attribute', () => { from: 'now-1h', to: 'now', }, - indexPattern: mockDataView, + dataView: mockDataView, name: 'ux-series-1', breakdown: 'percentile', reportDefinitions: {}, @@ -218,7 +218,7 @@ describe('Lens Attribute', () => { seriesConfig: reportViewConfig, seriesType: 'line', operationType: 'count', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: { 'performance.metric': [LCP_FIELD] }, time: { from: 'now-15m', to: 'now' }, color: 'green', @@ -455,7 +455,7 @@ describe('Lens Attribute', () => { seriesConfig: reportViewConfig, seriesType: 'line', operationType: 'count', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: { 'performance.metric': [LCP_FIELD] }, breakdown: USER_AGENT_NAME, time: { from: 'now-15m', to: 'now' }, @@ -646,7 +646,7 @@ describe('Lens Attribute', () => { seriesConfig: reportViewConfig, seriesType: 'line', operationType: 'count', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: { 'performance.metric': [LCP_FIELD] }, time: { from: 'now-15m', to: 'now' }, color: 'green', @@ -667,7 +667,7 @@ describe('Lens Attribute', () => { const layerConfig1: LayerConfig = { seriesConfig: reportViewConfig, seriesType: 'line', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: {}, time: { from: 'now-15m', to: 'now' }, color: 'green', 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 60f554d5344c4..9d39286f68998 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 { DataViewSpec } from '@kbn/data-views-plugin/common'; import { LegendSize } from '@kbn/visualizations-plugin/common/constants'; import { urlFiltersToKueryString } from '../utils/stringify_kueries'; import { @@ -141,7 +142,7 @@ export interface LayerConfig { operationType?: OperationType; reportDefinitions: URLReportDefinition; time: { to: string; from: string }; - indexPattern: DataView; // TODO: Figure out if this can be renamed or if it's a Lens requirement + dataView: DataView; selectedMetricField: string; color: string; name: string; @@ -158,7 +159,7 @@ export class LensAttributes { { layerData: PersistedIndexPatternLayer; layerState: XYState['layers']; - indexPattern: DataView; + dataView: DataView; } >; globalFilter?: { query: string; language: string }; @@ -503,7 +504,7 @@ export class LensAttributes { return this.getBreakdownColumn({ layerId, layerConfig, - indexPattern: layerConfig.indexPattern, + indexPattern: layerConfig.dataView, sourceField: layerConfig.breakdown || layerConfig.seriesConfig.breakdownFields[0], labels: layerConfig.seriesConfig.labels, }); @@ -562,7 +563,7 @@ export class LensAttributes { layerId, formula, label: columnLabel ?? label, - dataView: layerConfig.indexPattern, + dataView: layerConfig.dataView, lensFormulaHelper: this.lensFormulaHelper!, }).main; } @@ -664,7 +665,7 @@ export class LensAttributes { showPercentileAnnotations, formula, } = metricOption; - const fieldMeta = layerConfig.indexPattern.getFieldByName(fieldName!); + const fieldMeta = layerConfig.dataView.getFieldByName(fieldName!); return { formula, palette, @@ -679,7 +680,7 @@ export class LensAttributes { layerConfig.showPercentileAnnotations ?? showPercentileAnnotations, }; } else { - const fieldMeta = layerConfig.indexPattern.getFieldByName(sourceField); + const fieldMeta = layerConfig.dataView.getFieldByName(sourceField); return { fieldMeta, fieldName: sourceField }; } @@ -706,7 +707,7 @@ export class LensAttributes { label, layerId, columnFilter, - dataView: layerConfig.indexPattern, + dataView: layerConfig.dataView, lensFormulaHelper: this.lensFormulaHelper!, }).main, ]; @@ -767,7 +768,7 @@ export class LensAttributes { label: mainLabel, layerId, columnFilter, - dataView: layerConfig.indexPattern, + dataView: layerConfig.dataView, lensFormulaHelper: this.lensFormulaHelper!, }).supportingColumns; } @@ -780,7 +781,7 @@ export class LensAttributes { label: columnLabel, layerId, formula, - dataView: layerConfig.indexPattern, + dataView: layerConfig.dataView, lensFormulaHelper: this.lensFormulaHelper!, }).supportingColumns; } @@ -1005,7 +1006,7 @@ export class LensAttributes { ? this.getBreakdownColumn({ layerId, sourceField: breakdown!, - indexPattern: layerConfig.indexPattern, + indexPattern: layerConfig.dataView, labels: layerConfig.seriesConfig.labels, layerConfig, }) @@ -1098,10 +1099,9 @@ export class LensAttributes { /* if the fields format matches the field format of the first layer, use the default y axis (right) * if not, use the secondary y axis (left) */ axisMode: - layerConfig.indexPattern.fieldFormatMap[layerConfig.selectedMetricField]?.id === - this.layerConfigs[0].indexPattern.fieldFormatMap[ - this.layerConfigs[0].selectedMetricField - ]?.id + layerConfig.dataView.fieldFormatMap[layerConfig.selectedMetricField]?.id === + this.layerConfigs[0].dataView.fieldFormatMap[this.layerConfigs[0].selectedMetricField] + ?.id ? ('left' as YAxisMode) : ('right' as YAxisMode), }, @@ -1127,11 +1127,7 @@ export class LensAttributes { return [...dataLayers, ...referenceLineLayers]; } - addThresholdLayer( - fieldName: string, - layerId: string, - { seriesConfig, indexPattern }: LayerConfig - ) { + addThresholdLayer(fieldName: string, layerId: string, { seriesConfig, dataView }: LayerConfig) { const referenceLineLayerId = `${layerId}-reference-lines`; const referenceLineColumns = this.getThresholdColumns( @@ -1148,7 +1144,7 @@ export class LensAttributes { const layerState = this.getThresholdLayer(fieldName, referenceLineLayerId, seriesConfig); - this.seriesReferenceLines[referenceLineLayerId] = { layerData, layerState, indexPattern }; + this.seriesReferenceLines[referenceLineLayerId] = { layerData, layerState, dataView }; } getThresholdLayer( @@ -1191,41 +1187,62 @@ export class LensAttributes { getReferences() { const uniqueIndexPatternsIds = Array.from( - new Set([...this.layerConfigs.map(({ indexPattern }) => indexPattern.id)]) + new Set([...this.layerConfigs.map(({ dataView }) => dataView.id!)]) ); + const adHocDataViews: Record<string, DataViewSpec> = {}; + const referenceLineIndexReferences = Object.entries(this.seriesReferenceLines).map( - ([id, { indexPattern }]) => ({ - id: indexPattern.id!, - name: getLayerReferenceName(id), - type: 'index-pattern', - }) + ([id, { dataView }]) => { + adHocDataViews[dataView.id!] = dataView.toSpec(false); + return { + id: dataView.id!, + name: getLayerReferenceName(id), + type: 'index-pattern', + }; + } ); - return [ - ...uniqueIndexPatternsIds.map((patternId) => ({ - id: patternId!, + const internalReferences = [ + ...uniqueIndexPatternsIds.map((dataViewId) => ({ + id: dataViewId, name: 'indexpattern-datasource-current-indexpattern', type: 'index-pattern', })), - ...this.layerConfigs.map(({ indexPattern }, index) => ({ - id: indexPattern.id!, - name: getLayerReferenceName(`layer${index}`), - type: 'index-pattern', - })), + ...this.layerConfigs.map(({ dataView }, index) => { + adHocDataViews[dataView.id!] = dataView.toSpec(false); + + return { + id: dataView.id!, + name: getLayerReferenceName(`layer${index}`), + type: 'index-pattern', + }; + }), ...referenceLineIndexReferences, ]; + + Object.entries(this.seriesReferenceLines).map(([id, { dataView }]) => ({ + id: dataView.id!, + name: getLayerReferenceName(id), + type: 'index-pattern', + })); + + return { internalReferences, adHocDataViews }; } getJSON(lastRefresh?: number): TypedLensByValueInput['attributes'] { const query = this.globalFilter || this.layerConfigs[0].seriesConfig.query; + const { internalReferences, adHocDataViews } = this.getReferences(); + return { title: 'Prefilled from exploratory view app', description: lastRefresh ? `Last refreshed at ${new Date(lastRefresh).toISOString()}` : '', visualizationType: 'lnsXY', - references: this.getReferences(), + references: [], state: { + internalReferences, + adHocDataViews, datasourceStates: { formBased: { layers: this.layers, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.test.ts index d6c5bfea5f1d6..cec2617feacf0 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.test.ts @@ -16,7 +16,7 @@ import { TRANSACTION_DURATION } from '../constants/elasticsearch_fieldnames'; import { lensPluginMock } from '@kbn/lens-plugin/public/mocks'; import { FormulaPublicApi } from '@kbn/lens-plugin/public'; import { DataTypes } from '../constants'; -import { sampleMetricFormulaAttribute } from './sample_formula_metric_attribute'; +import { sampleMetricFormulaAttribute } from '../test_data/test_formula_metric_attribute'; describe('SingleMetricAttributes', () => { mockAppDataView(); @@ -35,7 +35,7 @@ describe('SingleMetricAttributes', () => { const layerConfig: LayerConfig = { seriesConfig: reportViewConfig, operationType: 'median', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: {}, time: { from: 'now-15m', to: 'now' }, color: 'green', @@ -60,19 +60,21 @@ describe('SingleMetricAttributes', () => { const jsonAttr = lnsAttr.getJSON(); expect(jsonAttr).toEqual({ description: 'undefined', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - ], + references: [], state: { + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + ], datasourceStates: { formBased: { layers: { @@ -122,19 +124,21 @@ describe('SingleMetricAttributes', () => { const jsonAttr = lnsAttr.getJSON(); expect(jsonAttr).toEqual({ description: 'undefined', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - ], + references: [], state: { + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + ], datasourceStates: { formBased: { layers: { @@ -188,7 +192,7 @@ describe('SingleMetricAttributes', () => { const layerConfigFormula: LayerConfig = { seriesConfig: reportViewConfigFormula, operationType: 'median', - indexPattern: mockDataView, + dataView: mockDataView, reportDefinitions: {}, time: { from: 'now-15m', to: 'now' }, color: 'green', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.ts index 9a1f5498dc17e..1a7fe32d6c40a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/single_metric_attributes.ts @@ -15,7 +15,7 @@ import { import type { DataView } from '@kbn/data-views-plugin/common'; import { Query } from '@kbn/es-query'; -import { FORMULA_COLUMN } from '../constants'; +import { FORMULA_COLUMN, RECORDS_FIELD } from '../constants'; import { ColumnFilter, MetricOption } from '../../types'; import { SeriesConfig } from '../../../../..'; import { @@ -48,7 +48,7 @@ export class SingleMetricLensAttributes extends LensAttributes { } getSingleMetricLayer() { - const { seriesConfig, selectedMetricField, operationType, indexPattern } = this.layerConfigs[0]; + const { seriesConfig, selectedMetricField, operationType, dataView } = this.layerConfigs[0]; const metricOption = parseCustomFieldName(seriesConfig, selectedMetricField); @@ -69,7 +69,7 @@ export class SingleMetricLensAttributes extends LensAttributes { return this.getFormulaLayer({ formula, label: columnLabel, - dataView: indexPattern, + dataView, format, filter: columnFilter, }); @@ -105,7 +105,7 @@ export class SingleMetricLensAttributes extends LensAttributes { [this.columnId]: { ...buildNumberColumn(sourceField), label: columnLabel ?? '', - operationType: sourceField === 'Records' ? 'count' : operationType || 'median', + operationType: sourceField === RECORDS_FIELD ? 'count' : operationType || 'median', filter: columnFilter, }, }, @@ -197,12 +197,16 @@ export class SingleMetricLensAttributes extends LensAttributes { const visualization = this.getMetricState(); + const { internalReferences, adHocDataViews } = this.getReferences(); + return { title: 'Prefilled from exploratory view app', description: String(refresh), visualizationType: 'lnsLegacyMetric', - references: this.getReferences(), + references: [], state: { + internalReferences, + adHocDataViews, visualization, datasourceStates: { formBased: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.test.ts index e8b5c4b9abd4b..f7d415d05d551 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.test.ts @@ -30,7 +30,7 @@ describe('Core web vital config test', function () { color: 'green', name: 'test-series', breakdown: USER_AGENT_OS, - indexPattern: mockDataView, + dataView: mockDataView, time: { from: 'now-15m', to: 'now' }, reportDefinitions: { [SERVICE_NAME]: ['elastic-co'] }, selectedMetricField: LCP_FIELD, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/single_metric_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/single_metric_config.ts index c67857ae7c0a4..56129ffd86da8 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/single_metric_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/single_metric_config.ts @@ -6,12 +6,14 @@ */ import { i18n } from '@kbn/i18n'; +import { LegacyMetricState } from '@kbn/lens-plugin/common'; +import { euiPaletteForStatus } from '@elastic/eui'; import { SYNTHETICS_STEP_DURATION, SYNTHETICS_STEP_NAME, } from '../constants/field_names/synthetics'; import { ConfigProps, SeriesConfig } from '../../types'; -import { FieldLabels, FORMULA_COLUMN } from '../constants'; +import { FieldLabels, FORMULA_COLUMN, RECORDS_FIELD } from '../constants'; import { buildExistsFilter } from '../utils'; export function getSyntheticsSingleMetricConfig({ dataView }: ConfigProps): SeriesConfig { @@ -93,35 +95,54 @@ export function getSyntheticsSingleMetricConfig({ dataView }: ConfigProps): Seri }, { id: 'monitor_errors', - field: 'state.id', label: i18n.translate('xpack.observability.expView.errors', { defaultMessage: 'Errors', }), metricStateOptions: { titlePosition: 'bottom', colorMode: 'Labels', - palette: { - name: 'custom', - type: 'palette', - params: { - steps: 3, - name: 'custom', - reverse: false, - rangeType: 'number', - rangeMin: 0, - progression: 'fixed', - stops: [{ color: '#E7664C', stop: 100 }], - colorStops: [{ color: '#E7664C', stop: 0 }], - continuity: 'above', - maxSteps: 5, - }, - }, + palette: getColorPalette('danger'), }, columnType: FORMULA_COLUMN, formula: 'unique_count(state.id, kql=\'monitor.status: "down"\')', format: 'number', }, + { + id: 'monitor_failed_tests', + label: i18n.translate('xpack.observability.expView.failedTests', { + defaultMessage: 'Failed tests', + }), + metricStateOptions: { + titlePosition: 'bottom', + }, + field: RECORDS_FIELD, + format: 'number', + columnFilter: { language: 'kuery', query: 'summary.down > 0' }, + }, ], labels: FieldLabels, }; } + +const getColorPalette = (color: 'danger' | 'warning' | 'success'): LegacyMetricState['palette'] => { + const statusPalette = euiPaletteForStatus(5); + + // TODO: add more colors + + return { + name: 'custom', + type: 'palette', + params: { + steps: 3, + name: 'custom', + reverse: false, + rangeType: 'number', + rangeMin: 0, + progression: 'fixed', + stops: [{ color: statusPalette[3], stop: 100 }], + colorStops: [{ color: statusPalette[3], stop: 0 }], + continuity: 'above', + maxSteps: 5, + }, + }; +}; 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 1af87c385d31e..d4985c4ed5173 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 @@ -5,23 +5,27 @@ * 2.0. */ +import { mockDataView } from '../../rtl_helpers'; + export const testMobileKPIAttr = { title: 'Prefilled from exploratory view app', description: '', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - ], + references: [], visualizationType: 'lnsXY', state: { + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + ], datasourceStates: { formBased: { layers: { 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 4661775b3a83f..d9188537947c0 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 @@ -4,28 +4,31 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { mockDataView } from '../../rtl_helpers'; import { RECORDS_FIELD } from '../constants'; export const sampleAttribute = { description: '', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0-reference-lines', - type: 'index-pattern', - }, - ], + references: [], state: { + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0-reference-lines', + type: 'index-pattern', + }, + ], + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, datasourceStates: { formBased: { layers: { 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 15e462c10be28..d87517e761342 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 @@ -4,23 +4,26 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { mockDataView } from '../../rtl_helpers'; import { RECORDS_FIELD } from '../constants'; export const sampleAttributeCoreWebVital = { description: '', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - ], + references: [], state: { + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + ], + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, datasourceStates: { formBased: { layers: { 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 6482795198898..b22bedc073931 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 @@ -4,23 +4,26 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { mockDataView } from '../../rtl_helpers'; import { RECORDS_FIELD } from '../constants'; export const sampleAttributeKpi = { description: '', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - ], + references: [], state: { + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + ], + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, datasourceStates: { formBased: { layers: { 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 873e4a6269de6..dfa15ae71b1f0 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 @@ -4,28 +4,31 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { mockDataView } from '../../rtl_helpers'; import { RECORDS_FIELD } from '../constants'; export const sampleAttributeWithReferenceLines = { description: '', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0-reference-lines', - type: 'index-pattern', - }, - ], + references: [], state: { + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0-reference-lines', + type: 'index-pattern', + }, + ], + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, datasourceStates: { formBased: { layers: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/sample_formula_metric_attribute.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/test_formula_metric_attribute.ts similarity index 92% rename from x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/sample_formula_metric_attribute.ts rename to x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/test_formula_metric_attribute.ts index 6894838d705e8..1a3ef129fa94f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes/sample_formula_metric_attribute.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/test_formula_metric_attribute.ts @@ -5,21 +5,25 @@ * 2.0. */ +import { mockDataView } from '../../rtl_helpers'; + export const sampleMetricFormulaAttribute = { description: 'undefined', - references: [ - { - id: 'apm-*', - name: 'indexpattern-datasource-current-indexpattern', - type: 'index-pattern', - }, - { - id: 'apm-*', - name: 'indexpattern-datasource-layer-layer0', - type: 'index-pattern', - }, - ], + references: [], state: { + adHocDataViews: { [mockDataView.title]: mockDataView.toSpec(false) }, + internalReferences: [ + { + id: 'apm-*', + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'apm-*', + name: 'indexpattern-datasource-layer-layer0', + type: 'index-pattern', + }, + ], datasourceStates: { formBased: { layers: { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/contexts/exploratory_view_config.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/contexts/exploratory_view_config.tsx index 8986705426936..c024971198510 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/contexts/exploratory_view_config.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/contexts/exploratory_view_config.tsx @@ -18,7 +18,6 @@ interface ExploratoryViewContextValue { reportType: ReportViewType | typeof SELECT_REPORT_TYPE; label: string; }>; - dataViews: Record<string, string>; reportConfigMap: ReportConfigMap; asPanel?: boolean; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; @@ -27,15 +26,14 @@ interface ExploratoryViewContextValue { setIsEditMode?: React.Dispatch<React.SetStateAction<boolean>>; } -export const ExploratoryViewContext = createContext<ExploratoryViewContextValue>({ - dataViews: {}, -} as ExploratoryViewContextValue); +export const ExploratoryViewContext = createContext<ExploratoryViewContextValue>( + {} as ExploratoryViewContextValue +); export function ExploratoryViewContextProvider({ children, reportTypes, dataTypes, - dataViews, reportConfigMap, setHeaderActionMenu, asPanel = true, @@ -47,7 +45,6 @@ export function ExploratoryViewContextProvider({ asPanel, reportTypes, dataTypes, - dataViews, reportConfigMap, setHeaderActionMenu, theme$, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx index dad9d5cef3f70..f74ea50157241 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx @@ -54,7 +54,7 @@ export function getExploratoryViewEmbeddable( setLoading(true); try { - const obsvIndexP = new ObservabilityDataViews(dataViews); + const obsvIndexP = new ObservabilityDataViews(dataViews, true); const indPattern = await obsvIndexP.getDataView( dataType, dataTypesIndexPatterns?.[dataType] diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_data_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_data_view.tsx index 3904329f0a5c7..d5092aa67d846 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_data_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_data_view.tsx @@ -12,10 +12,10 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import { DataViewInsufficientAccessError } from '@kbn/data-views-plugin/common'; import { AppDataType } from '../types'; import { ObservabilityPublicPluginsStart } from '../../../../plugin'; -import { ObservabilityDataViews } from '../../../../utils/observability_data_views'; -import { getDataHandler } from '../../../../data_handler'; -import { useExploratoryView } from '../contexts/exploratory_view_config'; -import { getApmDataViewTitle } from '../utils/utils'; +import { + getDataTypeIndices, + ObservabilityDataViews, +} from '../../../../utils/observability_data_views'; export interface DataViewContext { loading: boolean; @@ -46,48 +46,18 @@ export function DataViewContextProvider({ children }: ProviderProps) { services: { dataViews: dataViewsService }, } = useKibana<ObservabilityPublicPluginsStart>(); - const { dataViews: dataViewsList } = useExploratoryView(); - const loadDataView: DataViewContext['loadDataView'] = useCallback( async ({ dataType }) => { if (typeof hasAppData[dataType] === 'undefined' && !loading[dataType]) { setLoading((prevState) => ({ ...prevState, [dataType]: true })); try { - let hasDataT = false; - let indices: string | undefined = ''; - if (dataViewsList[dataType]) { - indices = dataViewsList[dataType]; - hasDataT = true; - } - switch (dataType) { - case 'ux': - case 'synthetics': - const resultUx = await getDataHandler(dataType)?.hasData(); - hasDataT = Boolean(resultUx?.hasData); - indices = resultUx?.indices; - break; - case 'infra_metrics': - const resultMetrics = await getDataHandler(dataType)?.hasData(); - hasDataT = Boolean(resultMetrics?.hasData); - indices = resultMetrics?.indices; - break; - case 'infra_logs': - const resultLogs = await getDataHandler(dataType)?.hasData(); - hasDataT = Boolean(resultLogs?.hasData); - indices = resultLogs?.indices; - break; - case 'apm': - case 'mobile': - const resultApm = await getDataHandler('apm')!.hasData(); - hasDataT = Boolean(resultApm?.hasData); - indices = getApmDataViewTitle(resultApm?.indices); - break; - } - setHasAppData((prevState) => ({ ...prevState, [dataType]: hasDataT })); + const { indices, hasData } = await getDataTypeIndices(dataType); + + setHasAppData((prevState) => ({ ...prevState, [dataType]: hasData })); - if (hasDataT && indices) { - const obsvDataV = new ObservabilityDataViews(dataViewsService); + if (hasData && indices) { + const obsvDataV = new ObservabilityDataViews(dataViewsService, true); const dataV = await obsvDataV.getDataView(dataType, indices); setDataViews((prevState) => ({ ...prevState, [dataType]: dataV })); @@ -104,7 +74,7 @@ export function DataViewContextProvider({ children }: ProviderProps) { } } }, - [dataViewsService, hasAppData, dataViewsList, loading] + [dataViewsService, hasAppData, loading] ); return ( diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.test.tsx index 623c5dd3e083b..1d5de56f9f2a7 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.test.tsx @@ -71,7 +71,6 @@ describe('useExpViewTimeRange', function () { <ExploratoryViewContextProvider reportTypes={reportTypesList} dataTypes={dataTypes} - dataViews={{}} reportConfigMap={obsvReportConfigMap} setHeaderActionMenu={jest.fn()} theme$={themeServiceMock.createTheme$()} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts index 1b0f4de4fa291..1f1997d394846 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts @@ -74,7 +74,7 @@ export function getLayerConfigs( layerConfigs.push({ filters, - indexPattern: dataView, + dataView, seriesConfig, time: series.time, name: series.name, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/obsv_exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/obsv_exploratory_view.tsx index 443d96f855b76..14d5101a561fb 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/obsv_exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/obsv_exploratory_view.tsx @@ -118,7 +118,6 @@ export function ObservabilityExploratoryView() { <ExploratoryViewContextProvider reportTypes={reportTypesList} dataTypes={dataTypes} - dataViews={{}} reportConfigMap={obsvReportConfigMap} setHeaderActionMenu={appMountParameters.setHeaderActionMenu} theme$={appMountParameters.theme$} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx index 8e0ac0d3505f5..e4969eb5e439e 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx @@ -207,7 +207,6 @@ export function render<ExtraCore>( <ExploratoryViewContextProvider reportTypes={reportTypesList} dataTypes={dataTypes} - dataViews={{}} reportConfigMap={obsvReportConfigMap} setHeaderActionMenu={jest.fn()} theme$={themeServiceMock.createTheme$()} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts index 075feba5467ec..dc195fc08c016 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts @@ -23,6 +23,7 @@ import { FieldFormatParams as BaseFieldFormatParams, SerializedFieldFormat, } from '@kbn/field-formats-plugin/common'; +import { TermsIndexPatternColumn } from '@kbn/lens-plugin/public'; import { FORMULA_COLUMN } from './configurations/constants'; export const ReportViewTypes = { @@ -167,3 +168,7 @@ export interface BuilderItem { } export type SupportedOperations = 'average' | 'median' | 'sum' | 'unique_count' | 'min' | 'max'; + +type TermColumnParams = TermsIndexPatternColumn['params']; + +export type TermColumnParamsOrderBy = TermColumnParams['orderBy']; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/utils.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/utils.ts index 65e763e148700..0edf6ff0c19e4 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/utils.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/utils.ts @@ -8,6 +8,9 @@ import { uniq } from 'lodash'; import { ApmIndicesConfig } from '../../../../../common/typings'; -export function getApmDataViewTitle(apmIndicesConfig: ApmIndicesConfig) { +export function getApmDataViewTitle(apmIndicesConfig?: ApmIndicesConfig) { + if (!apmIndicesConfig) { + return; + } return uniq([apmIndicesConfig.transaction, apmIndicesConfig.metric]).join(','); } diff --git a/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.test.ts b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.test.ts index e1d930d539842..fc71b76b27e64 100644 --- a/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.test.ts +++ b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.test.ts @@ -67,10 +67,11 @@ const fieldFormats = { }, }; -describe('ObservabilityIndexPatterns', function () { +describe('ObservabilityDataViews', function () { const { dataViews } = mockCore(); dataViews!.get = jest.fn().mockReturnValue({ title: 'index-*' }); dataViews!.createAndSave = jest.fn().mockReturnValue({ id: dataViewList.ux }); + dataViews!.create = jest.fn().mockReturnValue({ id: dataViewList.ux }); dataViews!.updateSavedObject = jest.fn(); it('should return index pattern for app', async function () { diff --git a/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.ts b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.ts index 8285e1d66e285..241e2ba021f3e 100644 --- a/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.ts +++ b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.ts @@ -14,6 +14,7 @@ import type { } from '@kbn/data-views-plugin/public'; import { RuntimeField } from '@kbn/data-views-plugin/public'; import { syntheticsRuntimeFields } from '../../components/shared/exploratory_view/configurations/synthetics/runtime_fields'; +import { getApmDataViewTitle } from '../../components/shared/exploratory_view/utils/utils'; import { rumFieldFormats } from '../../components/shared/exploratory_view/configurations/rum/field_formats'; import { syntheticsFieldFormats } from '../../components/shared/exploratory_view/configurations/synthetics/field_formats'; import { @@ -76,6 +77,22 @@ const getAppDataViewId = (app: AppDataType, indices: string) => { return `${dataViewList?.[app] ?? app}_${postfix}`; }; +export async function getDataTypeIndices(dataType: AppDataType) { + switch (dataType) { + case 'mobile': + case 'ux': + case 'apm': + const resultApm = await getDataHandler('apm')?.hasData(); + return { + hasData: Boolean(resultApm?.hasData), + indices: getApmDataViewTitle(resultApm?.indices), + }; + default: + const resultUx = await getDataHandler(dataType)?.hasData(); + return { hasData: Boolean(resultUx?.hasData), indices: resultUx?.indices as string }; + } +} + export function isParamsSame(param1: IFieldFormat['_params'], param2?: FieldFormatParams) { const isSame = param1?.inputFormat === param2?.inputFormat && @@ -91,18 +108,27 @@ export function isParamsSame(param1: IFieldFormat['_params'], param2?: FieldForm } export class ObservabilityDataViews { - dataViews?: DataViewsPublicPluginStart; + dataViews: DataViewsPublicPluginStart; + adHocDataViews: boolean = false; - constructor(dataViews: DataViewsPublicPluginStart) { + constructor(dataViews: DataViewsPublicPluginStart, adHocDataViews?: boolean) { this.dataViews = dataViews; + this.adHocDataViews = adHocDataViews ?? false; } async createDataView(app: AppDataType, indices: string) { - if (!this.dataViews) { - throw new Error('data is not defined'); - } + const appIndicesPattern = getAppIndicesWithPattern(app, indices); + return await this.dataViews.create({ + title: appIndicesPattern, + id: getAppDataViewId(app, indices), + timeFieldName: '@timestamp', + fieldFormats: this.getFieldFormats(app), + }); + } + async createAndSavedDataView(app: AppDataType, indices: string) { const appIndicesPattern = getAppIndicesWithPattern(app, indices); + return await this.dataViews.createAndSave({ title: appIndicesPattern, id: getAppDataViewId(app, indices), @@ -147,26 +173,10 @@ export class ObservabilityDataViews { return fieldFormatMap; } - async getDataTypeIndices(dataType: AppDataType) { - switch (dataType) { - case 'ux': - case 'synthetics': - const resultUx = await getDataHandler(dataType)?.hasData(); - return resultUx?.indices; - case 'apm': - case 'mobile': - const resultApm = await getDataHandler('apm')?.hasData(); - return resultApm?.indices.transaction; - } - } - async getDataView(app: AppDataType, indices?: string): Promise<DataView | undefined> { - if (!this.dataViews) { - throw new Error('data is not defined'); - } let appIndices = indices; if (!appIndices) { - appIndices = await this.getDataTypeIndices(app); + appIndices = (await getDataTypeIndices(app)).indices; } if (appIndices) { @@ -174,11 +184,16 @@ export class ObservabilityDataViews { const dataViewId = getAppDataViewId(app, appIndices); const dataViewTitle = getAppIndicesWithPattern(app, appIndices); // we will get the data view by id + + if (this.adHocDataViews) { + return await this.createDataView(app, appIndices); + } + const dataView = await this.dataViews?.get(dataViewId); // and make sure title matches, otherwise, we will need to create it if (dataView.title !== dataViewTitle) { - return await this.createDataView(app, appIndices); + return await this.createAndSavedDataView(app, appIndices); } // this is intentional a non blocking call, so no await clause @@ -186,7 +201,7 @@ export class ObservabilityDataViews { return dataView; } catch (e: unknown) { if (e instanceof SavedObjectNotFound) { - return await this.createDataView(app, appIndices); + return await this.createAndSavedDataView(app, appIndices); } } } diff --git a/x-pack/plugins/observability/server/errors/errors.ts b/x-pack/plugins/observability/server/errors/errors.ts index 8f04cc58bc4da..b32d0e2b5be51 100644 --- a/x-pack/plugins/observability/server/errors/errors.ts +++ b/x-pack/plugins/observability/server/errors/errors.ts @@ -18,3 +18,4 @@ export class SLONotFound extends ObservabilityError {} export class InternalQueryError extends ObservabilityError {} export class NotSupportedError extends ObservabilityError {} export class IllegalArgumentError extends ObservabilityError {} +export class InvalidTransformError extends ObservabilityError {} diff --git a/x-pack/plugins/observability/server/routes/slo/route.ts b/x-pack/plugins/observability/server/routes/slo/route.ts index 58b8a3f346044..21b3d46fe9b62 100644 --- a/x-pack/plugins/observability/server/routes/slo/route.ts +++ b/x-pack/plugins/observability/server/routes/slo/route.ts @@ -18,6 +18,7 @@ import { import { ApmTransactionDurationTransformGenerator, ApmTransactionErrorRateTransformGenerator, + KQLCustomTransformGenerator, TransformGenerator, } from '../../services/slo/transform_generators'; import { IndicatorTypes } from '../../types/models'; @@ -32,6 +33,7 @@ import { createObservabilityServerRoute } from '../create_observability_server_r const transformGenerators: Record<IndicatorTypes, TransformGenerator> = { 'slo.apm.transaction_duration': new ApmTransactionDurationTransformGenerator(), 'slo.apm.transaction_error_rate': new ApmTransactionErrorRateTransformGenerator(), + 'slo.kql.custom': new KQLCustomTransformGenerator(), }; const createSLORoute = createObservabilityServerRoute({ 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 a6d46b0689bb2..4c4139c0e9120 100644 --- a/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts +++ b/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts @@ -13,6 +13,7 @@ import { APMTransactionDurationIndicator, APMTransactionErrorRateIndicator, Indicator, + KQLCustomIndicator, SLO, } from '../../../types/models'; import { CreateSLOParams } from '../../../types/rest_specs'; @@ -45,6 +46,19 @@ export const createAPMTransactionDurationIndicator = ( }, }); +export const createKQLCustomIndicator = ( + params: Partial<KQLCustomIndicator['params']> = {} +): Indicator => ({ + type: 'slo.kql.custom', + params: { + index: 'my-index*', + query_filter: 'labels.groupId: group-3', + numerator: 'latency < 300', + denominator: '', + ...params, + }, +}); + const defaultSLO: Omit<SLO, 'id' | 'revision' | 'created_at' | 'updated_at'> = { name: 'irrelevant', description: 'irrelevant', diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap new file mode 100644 index 0000000000000..4fac897473239 --- /dev/null +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap @@ -0,0 +1,196 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`KQL Custom Transform Generator aggregates using the denominator kql 1`] = ` +Object { + "filter": Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "http.status_code", + }, + }, + ], + }, + }, +} +`; + +exports[`KQL Custom Transform Generator aggregates using the numerator kql 1`] = ` +Object { + "filter": Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "range": Object { + "latency": Object { + "lt": "400", + }, + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "http.status_code": "2xx", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "http.status_code": "3xx", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "http.status_code": "4xx", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, +} +`; + +exports[`KQL Custom Transform Generator filters the source using the kql query 1`] = ` +Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-4", + }, + }, + ], + }, +} +`; + +exports[`KQL Custom Transform Generator returns the correct transform params with every specified indicator params 1`] = ` +Object { + "_meta": Object { + "version": 1, + }, + "dest": Object { + "index": "slo-observability.sli-v1", + "pipeline": "slo-observability.sli.monthly", + }, + "frequency": "1m", + "pivot": Object { + "aggregations": Object { + "slo.denominator": Object { + "filter": Object { + "match_all": Object {}, + }, + }, + "slo.numerator": Object { + "filter": Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "range": Object { + "latency": Object { + "lt": "300", + }, + }, + }, + ], + }, + }, + }, + }, + "group_by": Object { + "@timestamp": Object { + "date_histogram": Object { + "calendar_interval": "1m", + "field": "@timestamp", + }, + }, + "slo.id": Object { + "terms": Object { + "field": "slo.id", + }, + }, + "slo.revision": Object { + "terms": Object { + "field": "slo.revision", + }, + }, + }, + }, + "settings": Object { + "deduce_mappings": false, + }, + "source": Object { + "index": "my-index*", + "query": Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-3", + }, + }, + ], + }, + }, + "runtime_mappings": Object { + "slo.id": Object { + "script": Object { + "source": Any<String>, + }, + "type": "keyword", + }, + "slo.revision": Object { + "script": Object { + "source": "emit(1)", + }, + "type": "long", + }, + }, + }, + "sync": Object { + "time": Object { + "delay": "60s", + "field": "@timestamp", + }, + }, + "transform_id": Any<String>, +} +`; diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts index 05ef2ac431a83..68848c7f1aa3f 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_duration.ts @@ -10,6 +10,7 @@ import { MappingRuntimeFieldType, TransformPutTransformRequest, } from '@elastic/elasticsearch/lib/api/types'; +import { InvalidTransformError } from '../../../errors'; import { ALL_VALUE, apmTransactionDurationIndicatorSchema } from '../../../types/schema'; import { SLO_DESTINATION_INDEX_NAME, @@ -25,7 +26,7 @@ const APM_SOURCE_INDEX = 'metrics-apm*'; export class ApmTransactionDurationTransformGenerator implements TransformGenerator { public getTransformParams(slo: SLO): TransformPutTransformRequest { if (!apmTransactionDurationIndicatorSchema.is(slo.indicator)) { - throw new Error(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); + throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); } return getSLOTransformTemplate( diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts index 3e69a4e371342..41ab541cdb4b6 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/apm_transaction_error_rate.ts @@ -10,6 +10,7 @@ import { MappingRuntimeFieldType, TransformPutTransformRequest, } from '@elastic/elasticsearch/lib/api/types'; +import { InvalidTransformError } from '../../../errors'; import { ALL_VALUE, apmTransactionErrorRateIndicatorSchema } from '../../../types/schema'; import { getSLOTransformTemplate } from '../../../assets/transform_templates/slo_transform_template'; import { TransformGenerator } from '.'; @@ -27,7 +28,7 @@ const DEFAULT_GOOD_STATUS_CODES = ['2xx', '3xx', '4xx']; export class ApmTransactionErrorRateTransformGenerator implements TransformGenerator { public getTransformParams(slo: SLO): TransformPutTransformRequest { if (!apmTransactionErrorRateIndicatorSchema.is(slo.indicator)) { - throw new Error(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); + throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); } return getSLOTransformTemplate( diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/index.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/index.ts index 6f0484c2044ad..08d6032a6eafa 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/index.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/index.ts @@ -8,3 +8,4 @@ export * from './transform_generator'; export * from './apm_transaction_error_rate'; export * from './apm_transaction_duration'; +export * from './kql_custom'; diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.test.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.test.ts new file mode 100644 index 0000000000000..46870fc8c7004 --- /dev/null +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createKQLCustomIndicator, createSLO } from '../fixtures/slo'; +import { KQLCustomTransformGenerator } from './kql_custom'; + +const generator = new KQLCustomTransformGenerator(); + +describe('KQL Custom Transform Generator', () => { + describe('validation', () => { + it('throws when the KQL numerator is invalid', () => { + const anSLO = createSLO({ + indicator: createKQLCustomIndicator({ numerator: '{ kql.query: invalid' }), + }); + expect(() => generator.getTransformParams(anSLO)).toThrow(/Invalid KQL/); + }); + it('throws when the KQL denominator is invalid', () => { + const anSLO = createSLO({ + indicator: createKQLCustomIndicator({ denominator: '{ kql.query: invalid' }), + }); + expect(() => generator.getTransformParams(anSLO)).toThrow(/Invalid KQL/); + }); + it('throws when the KQL query_filter is invalid', () => { + const anSLO = createSLO({ + indicator: createKQLCustomIndicator({ query_filter: '{ kql.query: invalid' }), + }); + expect(() => generator.getTransformParams(anSLO)).toThrow(/Invalid KQL/); + }); + }); + + it('returns the correct transform params with every specified indicator params', async () => { + const anSLO = createSLO({ indicator: createKQLCustomIndicator() }); + const transform = generator.getTransformParams(anSLO); + + expect(transform).toMatchSnapshot({ + transform_id: expect.any(String), + source: { runtime_mappings: { 'slo.id': { script: { source: expect.any(String) } } } }, + }); + expect(transform.transform_id).toEqual(`slo-${anSLO.id}-${anSLO.revision}`); + expect(transform.source.runtime_mappings!['slo.id']).toMatchObject({ + script: { source: `emit('${anSLO.id}')` }, + }); + expect(transform.source.runtime_mappings!['slo.revision']).toMatchObject({ + script: { source: `emit(${anSLO.revision})` }, + }); + }); + + it('filters the source using the kql query', async () => { + const anSLO = createSLO({ + indicator: createKQLCustomIndicator({ query_filter: 'labels.groupId: group-4' }), + }); + const transform = generator.getTransformParams(anSLO); + + expect(transform.source.query).toMatchSnapshot(); + }); + + it('uses the provided index', async () => { + const anSLO = createSLO({ + indicator: createKQLCustomIndicator({ index: 'my-own-index*' }), + }); + const transform = generator.getTransformParams(anSLO); + + expect(transform.source.index).toBe('my-own-index*'); + }); + + it('aggregates using the numerator kql', async () => { + const anSLO = createSLO({ + indicator: createKQLCustomIndicator({ + numerator: + 'latency < 400 and (http.status_code: 2xx or http.status_code: 3xx or http.status_code: 4xx)', + }), + }); + const transform = generator.getTransformParams(anSLO); + + expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot(); + }); + + it('aggregates using the denominator kql', async () => { + const anSLO = createSLO({ + indicator: createKQLCustomIndicator({ + denominator: 'http.status_code: *', + }), + }); + const transform = generator.getTransformParams(anSLO); + + expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts new file mode 100644 index 0000000000000..b444a196960d3 --- /dev/null +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + AggregationsCalendarInterval, + MappingRuntimeFieldType, + TransformPutTransformRequest, +} from '@elastic/elasticsearch/lib/api/types'; +import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; + +import { InvalidTransformError } from '../../../errors'; +import { kqlCustomIndicatorSchema } from '../../../types/schema'; +import { getSLOTransformTemplate } from '../../../assets/transform_templates/slo_transform_template'; +import { TransformGenerator } from '.'; +import { + SLO_DESTINATION_INDEX_NAME, + SLO_INGEST_PIPELINE_NAME, + getSLOTransformId, +} from '../../../assets/constants'; +import { KQLCustomIndicator, SLO } from '../../../types/models'; + +export class KQLCustomTransformGenerator implements TransformGenerator { + public getTransformParams(slo: SLO): TransformPutTransformRequest { + if (!kqlCustomIndicatorSchema.is(slo.indicator)) { + throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`); + } + + return getSLOTransformTemplate( + this.buildTransformId(slo), + this.buildSource(slo, slo.indicator), + this.buildDestination(), + this.buildGroupBy(), + this.buildAggregations(slo, slo.indicator) + ); + } + + private buildTransformId(slo: SLO): string { + return getSLOTransformId(slo.id, slo.revision); + } + + private buildSource(slo: SLO, indicator: KQLCustomIndicator) { + const filter = getElastichsearchQueryOrThrow(indicator.params.query_filter); + return { + index: indicator.params.index, + runtime_mappings: { + 'slo.id': { + type: 'keyword' as MappingRuntimeFieldType, + script: { + source: `emit('${slo.id}')`, + }, + }, + 'slo.revision': { + type: 'long' as MappingRuntimeFieldType, + script: { + source: `emit(${slo.revision})`, + }, + }, + }, + query: filter, + }; + } + + private buildDestination() { + return { + pipeline: SLO_INGEST_PIPELINE_NAME, + index: SLO_DESTINATION_INDEX_NAME, + }; + } + + private buildGroupBy() { + return { + 'slo.id': { + terms: { + field: 'slo.id', + }, + }, + 'slo.revision': { + terms: { + field: 'slo.revision', + }, + }, + '@timestamp': { + date_histogram: { + field: '@timestamp', + calendar_interval: '1m' as AggregationsCalendarInterval, + }, + }, + }; + } + + private buildAggregations(slo: SLO, indicator: KQLCustomIndicator) { + const numerator = getElastichsearchQueryOrThrow(indicator.params.numerator); + const denominator = getElastichsearchQueryOrThrow(indicator.params.denominator); + return { + 'slo.numerator': { + filter: numerator, + }, + 'slo.denominator': { + filter: denominator, + }, + }; + } +} + +function getElastichsearchQueryOrThrow(kuery: string) { + try { + return toElasticsearchQuery(fromKueryExpression(kuery)); + } catch (err) { + throw new InvalidTransformError(`Invalid KQL: ${kuery}`); + } +} diff --git a/x-pack/plugins/observability/server/types/models/indicators.ts b/x-pack/plugins/observability/server/types/models/indicators.ts index 51ed07bb657d6..ea02059a03ff4 100644 --- a/x-pack/plugins/observability/server/types/models/indicators.ts +++ b/x-pack/plugins/observability/server/types/models/indicators.ts @@ -12,10 +12,12 @@ import { indicatorDataSchema, indicatorSchema, indicatorTypesSchema, + kqlCustomIndicatorSchema, } from '../schema'; type APMTransactionErrorRateIndicator = t.TypeOf<typeof apmTransactionErrorRateIndicatorSchema>; type APMTransactionDurationIndicator = t.TypeOf<typeof apmTransactionDurationIndicatorSchema>; +type KQLCustomIndicator = t.TypeOf<typeof kqlCustomIndicatorSchema>; type Indicator = t.TypeOf<typeof indicatorSchema>; type IndicatorTypes = t.TypeOf<typeof indicatorTypesSchema>; type IndicatorData = t.TypeOf<typeof indicatorDataSchema>; @@ -25,5 +27,6 @@ export type { IndicatorTypes, APMTransactionErrorRateIndicator, APMTransactionDurationIndicator, + KQLCustomIndicator, IndicatorData, }; diff --git a/x-pack/plugins/observability/server/types/schema/indicators.ts b/x-pack/plugins/observability/server/types/schema/indicators.ts index 268ccdb570675..ab343e5b7b995 100644 --- a/x-pack/plugins/observability/server/types/schema/indicators.ts +++ b/x-pack/plugins/observability/server/types/schema/indicators.ts @@ -8,8 +8,7 @@ import * as t from 'io-ts'; import { allOrAnyString } from './common'; -const apmTransactionDurationIndicatorTypeSchema = t.literal<string>('slo.apm.transaction_duration'); - +const apmTransactionDurationIndicatorTypeSchema = t.literal('slo.apm.transaction_duration'); const apmTransactionDurationIndicatorSchema = t.type({ type: apmTransactionDurationIndicatorTypeSchema, params: t.type({ @@ -21,10 +20,7 @@ const apmTransactionDurationIndicatorSchema = t.type({ }), }); -const apmTransactionErrorRateIndicatorTypeSchema = t.literal<string>( - 'slo.apm.transaction_error_rate' -); - +const apmTransactionErrorRateIndicatorTypeSchema = t.literal('slo.apm.transaction_error_rate'); const apmTransactionErrorRateIndicatorSchema = t.type({ type: apmTransactionErrorRateIndicatorTypeSchema, params: t.intersection([ @@ -42,16 +38,29 @@ const apmTransactionErrorRateIndicatorSchema = t.type({ ]), }); +const kqlCustomIndicatorTypeSchema = t.literal('slo.kql.custom'); +const kqlCustomIndicatorSchema = t.type({ + type: kqlCustomIndicatorTypeSchema, + params: t.type({ + index: t.string, + query_filter: t.string, + numerator: t.string, + denominator: t.string, + }), +}); + const indicatorDataSchema = t.type({ good: t.number, total: t.number }); const indicatorTypesSchema = t.union([ apmTransactionDurationIndicatorTypeSchema, apmTransactionErrorRateIndicatorTypeSchema, + kqlCustomIndicatorTypeSchema, ]); const indicatorSchema = t.union([ apmTransactionDurationIndicatorSchema, apmTransactionErrorRateIndicatorSchema, + kqlCustomIndicatorSchema, ]); export { @@ -59,6 +68,8 @@ export { apmTransactionDurationIndicatorTypeSchema, apmTransactionErrorRateIndicatorSchema, apmTransactionErrorRateIndicatorTypeSchema, + kqlCustomIndicatorSchema, + kqlCustomIndicatorTypeSchema, indicatorSchema, indicatorTypesSchema, indicatorDataSchema, 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<ElasticsearchClient>; @@ -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/screenshotting/server/browsers/chromium/driver.ts b/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts index 3cecb89889071..590d8668e4874 100644 --- a/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts +++ b/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts @@ -60,8 +60,8 @@ interface WaitForSelectorOpts { timeout: number; } -interface EvaluateOpts { - fn: EvaluateFunc<any>; +interface EvaluateOpts<A extends unknown[]> { + fn: EvaluateFunc<A>; args: unknown[]; } @@ -127,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); @@ -293,10 +293,14 @@ export class HeadlessChromiumDriver { return undefined; } - evaluate({ fn, args = [] }: EvaluateOpts, meta: EvaluateMetaOpts, logger: Logger): Promise<any> { + evaluate<A extends unknown[], T = void>( + { fn, args = [] }: EvaluateOpts<A>, + meta: EvaluateMetaOpts, + logger: Logger + ): Promise<T> { logger.debug(`evaluate ${meta.context}`); - return this.page.evaluate(fn, ...args); + return this.page.evaluate(fn as EvaluateFunc<unknown[]>, ...args) as Promise<T>; } public async waitForSelector( @@ -317,16 +321,20 @@ export class HeadlessChromiumDriver { return response; } - public async waitFor({ + public async waitFor<T extends unknown[] = unknown[]>({ fn, args, timeout, }: { - fn: EvaluateFunc<any>; + fn: EvaluateFunc<T>; args: unknown[]; timeout: number; }): Promise<void> { - await this.page.waitForFunction(fn, { timeout, polling: WAIT_FOR_DELAY_MS }, ...args); + await this.page.waitForFunction( + fn as EvaluateFunc<unknown[]>, + { timeout, polling: WAIT_FOR_DELAY_MS }, + ...args + ); } /** 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<Element>(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<AttributesMap>((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<string[], number>( { 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<string[], string[]>( { 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<string[], string>( { fn: (durationAttribute) => { const durationElement = document.querySelector(`[${durationAttribute}]`); 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<string[]>( { 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<string[]>( { fn: async (selector) => { const visualizations: NodeListOf<Element> = 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<CompletedItemsCountParameters[]>({ fn: getCompletedItemsCount, args: [{ renderCompleteSelector, context: CONTEXT_WAITFORELEMENTSTOBEINDOM, count: toEqual }], timeout, 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/patch_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/patch_rules_bulk_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/urls.ts index 0472c62228c4d..449960916f239 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_bulk_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/urls.ts @@ -5,9 +5,7 @@ * 2.0. */ -import * as t from 'io-ts'; +import { DETECTION_ENGINE_RULES_URL as RULES } from '../../../constants'; -import { patchRulesSchema } from './patch_rules_schema'; - -export const patchRulesBulkSchema = t.array(patchRulesSchema); -export type PatchRulesBulkSchema = t.TypeOf<typeof patchRulesBulkSchema>; +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<typeof createRulesBulkSchema>; +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<AddPrepackagedRulesSchema> = {}; + const payload: Partial<PrebuiltRuleToInstall> = {}; - 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema> & { output_index: string } = { + const payload: Partial<PrebuiltRuleToInstall> & { 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<AddPrepackagedRulesSchema> = { + const payload: Partial<PrebuiltRuleToInstall> = { 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<AddPrepackagedRulesSchema, 'references'> & { references: number[] } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'references'> & { 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<AddPrepackagedRulesSchema, 'index'> & { index: number[] } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'index'> & { 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<AddPrepackagedRulesSchema, 'filters'> & { filters: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'filters'> & { 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<AddPrepackagedRulesSchema, 'language'> & { language: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'language'> & { 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<AddPrepackagedRulesSchema, 'tags'> & { tags: number[] } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'tags'> & { 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<AddPrepackagedRulesSchema, 'threat'> & { - threat: Array<Partial<Omit<AddPrepackagedRulesSchema['threat'], 'framework'>>>; + const payload: Omit<PrebuiltRuleToInstall, 'threat'> & { + threat: Array<Partial<Omit<PrebuiltRuleToInstall['threat'], 'framework'>>>; } = { - ...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<AddPrepackagedRulesSchema, 'threat'> & { - threat: Array<Partial<Omit<AddPrepackagedRulesSchema['threat'], 'tactic'>>>; + const payload: Omit<PrebuiltRuleToInstall, 'threat'> & { + threat: Array<Partial<Omit<PrebuiltRuleToInstall['threat'], 'tactic'>>>; } = { - ...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<AddPrepackagedRulesSchema, 'threat'> & { - threat: Array<Partial<Omit<AddPrepackagedRulesSchema['threat'], 'technique'>>>; + const payload: Omit<PrebuiltRuleToInstall, 'threat'> & { + threat: Array<Partial<Omit<PrebuiltRuleToInstall['threat'], 'technique'>>>; } = { - ...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<AddPrepackagedRulesSchema, 'false_positives'> & { + const payload: Omit<PrebuiltRuleToInstall, 'false_positives'> & { 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<AddPrepackagedRulesSchema, 'meta'> & { meta: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'meta'> & { 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<AddPrepackagedRulesSchema, 'severity'> & { severity: string } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'severity'> & { 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<AddPrepackagedRulesSchema['actions'], 'group'> = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall['actions'], 'group'> = { + ...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<AddPrepackagedRulesSchema['actions'], 'id'> = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall['actions'], 'id'> = { + ...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<AddPrepackagedRulesSchema['actions'], 'action_type_id'> = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall['actions'], 'action_type_id'> = { + ...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<AddPrepackagedRulesSchema['actions'], 'params'> = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall['actions'], 'params'> = { + ...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<AddPrepackagedRulesSchema['actions'], 'actions'> = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall['actions'], 'actions'> = { + ...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<AddPrepackagedRulesSchema, 'note'> & { note: {} } = { - ...getAddPrepackagedRulesSchemaMock(), + const payload: Omit<PrebuiltRuleToInstall, 'note'> & { 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<typeof PrebuiltRuleToInstall>; +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<typeof addPrepackagedRulesSchema>; 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<CreateRuleExceptionsRequestParams> = {}; + + 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<CreateRuleExceptionsRequestParams> = { + 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<CreateRuleExceptionSchema> & { madeUp: string } = { + const payload: Partial<CreateRuleExceptionsRequestBody> & { 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<typeof CreateRuleExceptionsRequestParams>; +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<typeof CreateRuleExceptionsRequestBody>; +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<CreateRuleExceptionsRequestBody>, + '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<PerformBulkActionSchema, 'action'> = { + const payload: Omit<PerformBulkActionRequestBody, 'action'> = { query: 'name: test', }; const message = retrieveValidationMessage(payload); @@ -48,7 +43,7 @@ describe('perform_bulk_action_schema', () => { }); test('invalid request: unknown action', () => { - const payload: Omit<PerformBulkActionSchema, 'action'> & { action: 'unknown' } = { + const payload: Omit<PerformBulkActionRequestBody, 'action'> & { 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<typeof ThrottleForBulkActions>; +export const ThrottleForBulkActions = t.union([ t.literal('rule'), TimeDuration({ allowedDurations: [ @@ -50,88 +55,81 @@ export const throttleForBulkActions = t.union([ ], }), ]); -export type ThrottleForBulkActions = t.TypeOf<typeof throttleForBulkActions>; -const bulkActionEditPayloadTags = t.type({ +type BulkActionEditPayloadTags = t.TypeOf<typeof BulkActionEditPayloadTags>; +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<typeof bulkActionEditPayloadTags>; - -const bulkActionEditPayloadIndexPatterns = t.intersection([ +type BulkActionEditPayloadIndexPatterns = t.TypeOf<typeof BulkActionEditPayloadIndexPatterns>; +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<typeof BulkActionEditPayloadTimeline>; +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<typeof bulkActionEditPayloadTimeline>; - /** * 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<typeof NormalizedRuleAction>; +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<typeof BulkActionEditPayloadRuleActions>; +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<typeof bulkActionEditPayloadRuleActions>; - -const bulkActionEditPayloadSchedule = t.type({ +type BulkActionEditPayloadSchedule = t.TypeOf<typeof BulkActionEditPayloadSchedule>; +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<typeof bulkActionEditPayloadSchedule>; - -export const bulkActionEditPayload = t.union([ - bulkActionEditPayloadTags, - bulkActionEditPayloadIndexPatterns, - bulkActionEditPayloadTimeline, - bulkActionEditPayloadRuleActions, - bulkActionEditPayloadSchedule, -]); -export type BulkActionEditPayload = t.TypeOf<typeof bulkActionEditPayload>; +export type BulkActionEditPayload = t.TypeOf<typeof BulkActionEditPayload>; +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<typeof PerformBulkActionRequestBody>; +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<typeof PerformBulkActionRequestQuery>; +export const PerformBulkActionRequestQuery = t.exact( t.partial({ dry_run: t.union([t.literal('true'), t.literal('false')]), }) ); - -export type PerformBulkActionSchema = t.TypeOf<typeof performBulkActionSchema>; 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<typeof BulkCreateRulesRequestBody>; +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<typeof BulkDeleteRulesRequestBody>; +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<Omit<PatchRulesSchema, 'note'> & { note?: object }> = [ + const payload: Array<Omit<PatchRuleRequestBody, 'note'> & { 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<typeof BulkPatchRulesRequestBody>; +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<typeof BulkUpdateRulesRequestBody>; +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<typeof BulkCrudRulesResponse>; +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<PatchRulesSchema, 'references'> & { references: number[] } = { + const payload: Omit<PatchRuleRequestBody, 'references'> & { 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<PatchRulesSchema, 'index'> & { index: number[] } = { + const payload: Omit<PatchRuleRequestBody, 'index'> & { 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<PatchRulesSchema, 'meta'> & { meta: string } = { + const payload: Omit<PatchRuleRequestBody, 'meta'> & { 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<PatchRulesSchema, 'filters'> & { filters: string } = { + const payload: Omit<PatchRuleRequestBody, 'filters'> & { 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<PatchRulesSchema['threat'], 'framework'> = [ + const threat: Omit<PatchRuleRequestBody['threat'], 'framework'> = [ { tactic: { id: 'fakeId', @@ -922,12 +922,12 @@ describe('patch_rules_schema', () => { ], }, ]; - const payload: Omit<PatchRulesSchema['threat'], 'framework'> = { + const payload: Omit<PatchRuleRequestBody['threat'], 'framework'> = { 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<PatchRulesSchema['threat'], 'tactic'> = [ + const threat: Omit<PatchRuleRequestBody['threat'], 'tactic'> = [ { framework: 'fake', technique: [ @@ -950,12 +950,12 @@ describe('patch_rules_schema', () => { }, ]; - const payload: Omit<PatchRulesSchema['threat'], 'tactic'> = { + const payload: Omit<PatchRuleRequestBody['threat'], 'tactic'> = { 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<PatchRulesSchema['threat'], 'technique'> = [ + const threat: Omit<PatchRuleRequestBody['threat'], 'technique'> = [ { framework: 'fake', tactic: { @@ -976,12 +976,12 @@ describe('patch_rules_schema', () => { }, ]; - const payload: Omit<PatchRulesSchema['threat'], 'technique'> = { + const payload: Omit<PatchRuleRequestBody['threat'], 'technique'> = { 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<PatchRulesSchema, 'severity'> & { severity: string } = { + const payload: Omit<PatchRuleRequestBody, 'severity'> & { 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<PatchRulesSchema, 'note'> & { note: object } = { + const payload: Omit<PatchRuleRequestBody, 'note'> & { 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<PatchRulesSchema['actions'], 'group'> = { + const payload: Omit<PatchRuleRequestBody['actions'], 'group'> = { ...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<PatchRulesSchema['actions'], 'id'> = { + const payload: Omit<PatchRuleRequestBody['actions'], 'id'> = { ...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<PatchRulesSchema['actions'], 'params'> = { + const payload: Omit<PatchRuleRequestBody['actions'], 'params'> = { ...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<PatchRulesSchema['actions'], 'actions'> = { + const payload: Omit<PatchRuleRequestBody['actions'], 'actions'> = { ...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<QueryRulesSchema> = {}; + const payload: Partial<QueryRuleByIds> = {}; - 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<typeof QueryRuleByIds>; +export const QueryRuleByIds = t.exact( t.partial({ - rule_id, - id, + rule_id: RuleSignatureId, + id: RuleObjectId, }) ); - -export type QueryRulesSchema = t.TypeOf<typeof queryRulesSchema>; -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<ExportRulesSchema> = null; + const payload: Partial<ExportRulesRequestBody> = 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<ExportRulesSchema, 'objects'> & { objects: [{ id: string }] } = { + const payload: Omit<ExportRulesRequestBody, 'objects'> & { 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<ExportRulesQuerySchema> = {}; + const payload: Partial<ExportRulesRequestQuery> = {}; - 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<ExportRulesQuerySchema, 'file_name'> & { file_name: number } = { + const payload: Omit<ExportRulesRequestQuery, 'file_name'> & { 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<ExportRulesQuerySchema, 'exclude_export_details'> & { + const payload: Omit<ExportRulesRequestQuery, 'exclude_export_details'> & { 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<typeof ExportRulesRequestBody>; +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<typeof ExportRulesRequestQuery>; +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<FindRulesSchema> & { madeUp: string } = { madeUp: 'invalid value' }; + const payload: Partial<FindRulesRequestQuery> & { 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<FindRulesSchema, 'fields'> & { fields: number } = { + const payload: Omit<FindRulesRequestQuery, 'fields'> & { 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<FindRulesSchema, 'filter'> & { filter: number } = { + const payload: Omit<FindRulesRequestQuery, 'filter'> & { 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<FindRulesSchema, 'sort_order'> & { sort_order: string } = { + const payload: Omit<FindRulesRequestQuery, 'sort_order'> & { 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<typeof FindRulesRequestQuery>; +export const FindRulesRequestQuery = t.exact( t.partial({ fields, filter: queryFilter, @@ -22,8 +25,7 @@ export const findRulesSchema = t.exact( }) ); -export type FindRulesSchema = t.TypeOf<typeof findRulesSchema>; -export type FindRulesSchemaDecoded = Omit<FindRulesSchema, 'per_page'> & { +export type FindRulesRequestQueryDecoded = Omit<FindRulesRequestQuery, 'per_page'> & { 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<ImportRulesRequestBody, 'file'> & { 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<typeof ImportRulesRequestBody>; +export const ImportRulesRequestBody = t.exact( t.type({ - id, + file: t.object, }) ); - -export type QueryRuleByIdSchema = t.TypeOf<typeof queryRuleByIdSchema>; -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<ImportRulesSchema, 'success'> & { success: string } = { + const payload: Omit<ImportRulesResponse, 'success'> & { 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<ImportRulesSchema, 'exceptions_success'> & { 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<ImportRulesResponse, 'exceptions_success'> & { + 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<ImportRulesSchema, 'errors'> & { + const payload: Omit<ImportRulesResponse, 'errors'> & { 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<typeof ImportRulesResponse>; +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<typeof importRulesSchema>; 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 = <Required extends t.Props, Optional extends t.Props>( 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<ImportRulesSchema> = {}; + const payload: Partial<RuleToImport> = {}; - 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema> = { + const payload: Partial<RuleToImport> = { 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<ImportRulesSchema, 'references'> & { references: number[] } = { + const payload: Omit<RuleToImport, 'references'> & { 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<ImportRulesSchema, 'index'> & { index: number[] } = { + const payload: Omit<RuleToImport, 'index'> & { 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<ImportRulesSchema, 'filters'> & { filters: string } = { + const payload: Omit<RuleToImport, 'filters'> & { 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<ImportRulesSchema, 'language'> & { language: string } = { + const payload: Omit<RuleToImport, 'language'> & { 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<ImportRulesSchema, 'tags'> & { tags: number[] } = { + const payload: Omit<RuleToImport, 'tags'> & { 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<ImportRulesSchema, 'threat'> & { - threat: Array<Partial<Omit<ImportRulesSchema['threat'], 'framework'>>>; + const payload: Omit<RuleToImport, 'threat'> & { + threat: Array<Partial<Omit<RuleToImport['threat'], 'framework'>>>; } = { ...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<ImportRulesSchema, 'threat'> & { - threat: Array<Partial<Omit<ImportRulesSchema['threat'], 'tactic'>>>; + const payload: Omit<RuleToImport, 'threat'> & { + threat: Array<Partial<Omit<RuleToImport['threat'], 'tactic'>>>; } = { ...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<ImportRulesSchema, 'threat'> & { - threat: Array<Partial<Omit<ImportRulesSchema['threat'], 'technique'>>>; + const payload: Omit<RuleToImport, 'threat'> & { + threat: Array<Partial<Omit<RuleToImport['threat'], 'technique'>>>; } = { ...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<ImportRulesSchema, 'false_positives'> & { false_positives: number[] } = { + const payload: Omit<RuleToImport, 'false_positives'> & { 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<ImportRulesSchema, 'immutable'> & { immutable: number } = { + const payload: Omit<RuleToImport, 'immutable'> & { 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<ImportRulesSchema, 'immutable'> & { immutable: number } = { + const payload: Omit<RuleToImport, 'immutable'> & { 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<ImportRulesSchema, 'meta'> & { meta: string } = { + const payload: Omit<RuleToImport, 'meta'> & { 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<ImportRulesPayloadSchema, 'file'> & { 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<ImportRulesSchema, 'severity'> & { severity: string } = { + const payload: Omit<RuleToImport, 'severity'> & { 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<ImportRulesSchema['actions'], 'group'> = { + const payload: Omit<RuleToImport['actions'], 'group'> = { ...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<ImportRulesSchema['actions'], 'id'> = { + const payload: Omit<RuleToImport['actions'], 'id'> = { ...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<ImportRulesSchema['actions'], 'action_type_id'> = { + const payload: Omit<RuleToImport['actions'], 'action_type_id'> = { ...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<ImportRulesSchema['actions'], 'params'> = { + const payload: Omit<RuleToImport['actions'], 'params'> = { ...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<ImportRulesSchema['actions'], 'actions'> = { + const payload: Omit<RuleToImport['actions'], 'actions'> = { ...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<ImportRulesSchema, 'note'> & { note: {} } = { + const payload: Omit<RuleToImport, 'note'> & { 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<ImportRulesSchema, 'data_view_id'> & { data_view_id: number } = { + const payload: Omit<RuleToImport, 'data_view_id'> & { 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<typeof RuleToImport>; +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<typeof importRulesSchema>; - -export const importRulesPayloadSchema = t.exact( - t.type({ - file: t.object, - }) -); - -export type ImportRulesPayloadSchema = t.TypeOf<typeof importRulesPayloadSchema>; 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 = <R extends t.Props, O extends t.Props, D extends t.Props>( + fields: RuleFields<R, O, D> +) => { + 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<P extends t.Props> = { + [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<t.Props>((acc, key) => { + acc[key] = t.union([optionalFields[key], t.undefined]); + return acc; + }, {}) as OrUndefined<Optional>; + 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<typeof RuleNameOverride>; +export const RuleNameOverride = t.string; // should be non-empty string? + +export type TimestampOverride = t.TypeOf<typeof TimestampOverride>; +export const TimestampOverride = t.string; // should be non-empty string? + +export type TimestampOverrideFallbackDisabled = t.TypeOf<typeof TimestampOverrideFallbackDisabled>; +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<typeof RuleObjectId>; +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<typeof RuleSignatureId>; +export const RuleSignatureId = t.string; // should be non-empty string? + +export type RuleName = t.TypeOf<typeof RuleName>; +export const RuleName = NonEmptyString; + +export type RuleDescription = t.TypeOf<typeof RuleDescription>; +export const RuleDescription = NonEmptyString; + +export type RuleVersion = t.TypeOf<typeof RuleVersion>; +export const RuleVersion = version; + +export type IsRuleImmutable = t.TypeOf<typeof IsRuleImmutable>; +export const IsRuleImmutable = t.boolean; + +export type IsRuleEnabled = t.TypeOf<typeof IsRuleEnabled>; +export const IsRuleEnabled = t.boolean; + +export type RuleTagArray = t.TypeOf<typeof RuleTagArray>; +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<typeof RuleMetadata>; +export const RuleMetadata = t.object; // should be a more specific type? + +export type RuleLicense = t.TypeOf<typeof RuleLicense>; +export const RuleLicense = t.string; // should be non-empty string? + +export type RuleAuthorArray = t.TypeOf<typeof RuleAuthorArray>; +export const RuleAuthorArray = t.array(t.string); // should be non-empty strings? + +export type RuleFalsePositiveArray = t.TypeOf<typeof RuleFalsePositiveArray>; +export const RuleFalsePositiveArray = t.array(t.string); // should be non-empty strings? + +export type RuleReferenceArray = t.TypeOf<typeof RuleReferenceArray>; +export const RuleReferenceArray = t.array(t.string); // should be non-empty strings? + +export type InvestigationGuide = t.TypeOf<typeof InvestigationGuide>; +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<typeof SetupGuide>; +export const SetupGuide = t.string; + +export type BuildingBlockType = t.TypeOf<typeof BuildingBlockType>; +export const BuildingBlockType = t.string; + +export type AlertsIndex = t.TypeOf<typeof AlertsIndex>; +export const AlertsIndex = t.string; + +export type AlertsIndexNamespace = t.TypeOf<typeof AlertsIndexNamespace>; +export const AlertsIndexNamespace = t.string; + +export type ExceptionListArray = t.TypeOf<typeof ExceptionListArray>; +export const ExceptionListArray = listArray; + +export type MaxSignals = t.TypeOf<typeof MaxSignals>; +export const MaxSignals = max_signals; + +export type ThreatArray = t.TypeOf<typeof ThreatArray>; +export const ThreatArray = t.array(threat); + +export type IndexPatternArray = t.TypeOf<typeof IndexPatternArray>; +export const IndexPatternArray = t.array(t.string); + +export type DataViewId = t.TypeOf<typeof DataViewId>; +export const DataViewId = t.string; + +export type RuleQuery = t.TypeOf<typeof RuleQuery>; +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<typeof RuleFilterArray>; // 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<typeof RelatedIntegrationArray>; 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<typeof RequiredFieldArray>; -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<typeof SetupGuide>; -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<typeof RequiredField>; +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<typeof RequiredFieldArray>; +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<typeof SavedObjectResolveOutcome>; +export const SavedObjectResolveOutcome = t.union([ + t.literal('exactMatch'), + t.literal('aliasMatch'), + t.literal('conflict'), +]); + +export type SavedObjectResolveAliasTargetId = t.TypeOf<typeof SavedObjectResolveAliasTargetId>; +export const SavedObjectResolveAliasTargetId = t.string; + +export type SavedObjectResolveAliasPurpose = t.TypeOf<typeof SavedObjectResolveAliasPurpose>; +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<typeof TimelineTemplateId>; +export const TimelineTemplateId = t.string; // should be non-empty string? + +export type TimelineTemplateTitle = t.TypeOf<typeof TimelineTemplateTitle>; +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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema> = { + const payload: Partial<RuleCreateProps> = { 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<CreateRulesSchema, 'references'> & { references: number[] } = { + const payload: Omit<RuleCreateProps, 'references'> & { 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<CreateRulesSchema, 'index'> & { index: number[] } = { + const payload: Omit<RuleCreateProps, 'index'> & { 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<CreateRulesSchema, 'data_view_id'> & { data_view_id: number } = { + const payload: Omit<RuleCreateProps, 'data_view_id'> & { 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<ThreatMatchResponseSchema> => { +export const getThreatMatchingSchemaPartialMock = (enabled = false): Partial<ThreatMatchRule> => { 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<FullResponseSchema, 'type'> & { type: string } = getRulesSchemaMock(); + const payload: Omit<RuleResponse, 'type'> & { 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<FullResponseSchema, 'exceptions_list'> & { + const payload: Omit<RuleResponse, 'exceptions_list'> & { 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<typeof BaseCreateProps>; +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<typeof SharedCreateProps>; +const SharedCreateProps = t.intersection([ + baseSchema.create, + t.exact(t.partial({ rule_id: RuleSignatureId })), +]); + +type SharedUpdateProps = t.TypeOf<typeof SharedUpdateProps>; +const SharedUpdateProps = t.intersection([ + baseSchema.create, + t.exact(t.partial({ rule_id: RuleSignatureId })), + t.exact(t.partial({ id: RuleObjectId })), +]); + +type SharedPatchProps = t.TypeOf<typeof SharedPatchProps>; +const SharedPatchProps = t.intersection([ + baseSchema.patch, + t.exact(t.partial({ rule_id: RuleSignatureId, id: RuleObjectId })), +]); + +export type SharedResponseProps = t.TypeOf<typeof SharedResponseProps>; +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<typeof EqlRule>; +export const EqlRule = t.intersection([SharedResponseProps, eqlSchema.response]); + +export type EqlRuleCreateProps = t.TypeOf<typeof EqlRuleCreateProps>; +export const EqlRuleCreateProps = t.intersection([SharedCreateProps, eqlSchema.create]); + +export type EqlRuleUpdateProps = t.TypeOf<typeof EqlRuleUpdateProps>; +export const EqlRuleUpdateProps = t.intersection([SharedUpdateProps, eqlSchema.create]); + +export type EqlRulePatchProps = t.TypeOf<typeof EqlRulePatchProps>; +export const EqlRulePatchProps = t.intersection([SharedPatchProps, eqlSchema.patch]); + +export type EqlPatchParams = t.TypeOf<typeof EqlPatchParams>; +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<typeof ThreatMatchRule>; +export const ThreatMatchRule = t.intersection([SharedResponseProps, threatMatchSchema.response]); + +export type ThreatMatchRuleCreateProps = t.TypeOf<typeof ThreatMatchRuleCreateProps>; +export const ThreatMatchRuleCreateProps = t.intersection([ + SharedCreateProps, + threatMatchSchema.create, +]); + +export type ThreatMatchRuleUpdateProps = t.TypeOf<typeof ThreatMatchRuleUpdateProps>; +export const ThreatMatchRuleUpdateProps = t.intersection([ + SharedUpdateProps, + threatMatchSchema.create, +]); + +export type ThreatMatchRulePatchProps = t.TypeOf<typeof ThreatMatchRulePatchProps>; +export const ThreatMatchRulePatchProps = t.intersection([ + SharedPatchProps, + threatMatchSchema.patch, +]); + +export type ThreatMatchPatchParams = t.TypeOf<typeof ThreatMatchPatchParams>; +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<typeof QueryRule>; +export const QueryRule = t.intersection([SharedResponseProps, querySchema.response]); + +export type QueryRuleCreateProps = t.TypeOf<typeof QueryRuleCreateProps>; +export const QueryRuleCreateProps = t.intersection([SharedCreateProps, querySchema.create]); + +export type QueryRuleUpdateProps = t.TypeOf<typeof QueryRuleUpdateProps>; +export const QueryRuleUpdateProps = t.intersection([SharedUpdateProps, querySchema.create]); + +export type QueryRulePatchProps = t.TypeOf<typeof QueryRulePatchProps>; +export const QueryRulePatchProps = t.intersection([SharedPatchProps, querySchema.patch]); + +export type QueryPatchParams = t.TypeOf<typeof QueryPatchParams>; +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<typeof SavedQueryRule>; +export const SavedQueryRule = t.intersection([SharedResponseProps, savedQuerySchema.response]); + +export type SavedQueryRuleCreateProps = t.TypeOf<typeof SavedQueryRuleCreateProps>; +export const SavedQueryRuleCreateProps = t.intersection([ + SharedCreateProps, + savedQuerySchema.create, +]); + +export type SavedQueryRuleUpdateProps = t.TypeOf<typeof SavedQueryRuleUpdateProps>; +export const SavedQueryRuleUpdateProps = t.intersection([ + SharedUpdateProps, + savedQuerySchema.create, +]); + +export type SavedQueryRulePatchProps = t.TypeOf<typeof SavedQueryRulePatchProps>; +export const SavedQueryRulePatchProps = t.intersection([SharedPatchProps, savedQuerySchema.patch]); + +export type SavedQueryPatchParams = t.TypeOf<typeof SavedQueryPatchParams>; +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<typeof ThresholdRule>; +export const ThresholdRule = t.intersection([SharedResponseProps, thresholdSchema.response]); + +export type ThresholdRuleCreateProps = t.TypeOf<typeof ThresholdRuleCreateProps>; +export const ThresholdRuleCreateProps = t.intersection([SharedCreateProps, thresholdSchema.create]); + +export type ThresholdRuleUpdateProps = t.TypeOf<typeof ThresholdRuleUpdateProps>; +export const ThresholdRuleUpdateProps = t.intersection([SharedUpdateProps, thresholdSchema.create]); + +export type ThresholdRulePatchProps = t.TypeOf<typeof ThresholdRulePatchProps>; +export const ThresholdRulePatchProps = t.intersection([SharedPatchProps, thresholdSchema.patch]); + +export type ThresholdPatchParams = t.TypeOf<typeof ThresholdPatchParams>; +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<typeof MachineLearningRule>; +export const MachineLearningRule = t.intersection([ + SharedResponseProps, + machineLearningSchema.response, +]); + +export type MachineLearningRuleCreateProps = t.TypeOf<typeof MachineLearningRuleCreateProps>; +export const MachineLearningRuleCreateProps = t.intersection([ + SharedCreateProps, + machineLearningSchema.create, +]); + +export type MachineLearningRuleUpdateProps = t.TypeOf<typeof MachineLearningRuleUpdateProps>; +export const MachineLearningRuleUpdateProps = t.intersection([ + SharedUpdateProps, + machineLearningSchema.create, +]); + +export type MachineLearningRulePatchProps = t.TypeOf<typeof MachineLearningRulePatchProps>; +export const MachineLearningRulePatchProps = t.intersection([ + SharedPatchProps, + machineLearningSchema.patch, +]); + +export type MachineLearningPatchParams = t.TypeOf<typeof MachineLearningPatchParams>; +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<typeof NewTermsRule>; +export const NewTermsRule = t.intersection([SharedResponseProps, newTermsSchema.response]); + +export type NewTermsRuleCreateProps = t.TypeOf<typeof NewTermsRuleCreateProps>; +export const NewTermsRuleCreateProps = t.intersection([SharedCreateProps, newTermsSchema.create]); + +export type NewTermsRuleUpdateProps = t.TypeOf<typeof NewTermsRuleUpdateProps>; +export const NewTermsRuleUpdateProps = t.intersection([SharedUpdateProps, newTermsSchema.create]); + +export type NewTermsRulePatchProps = t.TypeOf<typeof NewTermsRulePatchProps>; +export const NewTermsRulePatchProps = t.intersection([SharedPatchProps, newTermsSchema.patch]); + +export type NewTermsPatchParams = t.TypeOf<typeof NewTermsPatchParams>; +export const NewTermsPatchParams = newTermsSchema.patch; + +// ------------------------------------------------------------------------------------------------- +// Combined type specific schemas + +export type TypeSpecificCreateProps = t.TypeOf<typeof TypeSpecificCreateProps>; +export const TypeSpecificCreateProps = t.union([ + eqlSchema.create, + threatMatchSchema.create, + querySchema.create, + savedQuerySchema.create, + thresholdSchema.create, + machineLearningSchema.create, + newTermsSchema.create, +]); + +export type TypeSpecificPatchProps = t.TypeOf<typeof TypeSpecificPatchProps>; +export const TypeSpecificPatchProps = t.union([ + eqlSchema.patch, + threatMatchSchema.patch, + querySchema.patch, + savedQuerySchema.patch, + thresholdSchema.patch, + machineLearningSchema.patch, + newTermsSchema.patch, +]); + +export type TypeSpecificResponse = t.TypeOf<typeof TypeSpecificResponse>; +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<typeof RuleCreateProps>; +export const RuleCreateProps = t.intersection([SharedCreateProps, TypeSpecificCreateProps]); + +export type RuleUpdateProps = t.TypeOf<typeof RuleUpdateProps>; +export const RuleUpdateProps = t.intersection([TypeSpecificCreateProps, SharedUpdateProps]); + +export type RulePatchProps = t.TypeOf<typeof RulePatchProps>; +export const RulePatchProps = t.intersection([TypeSpecificPatchProps, SharedPatchProps]); + +export type RuleResponse = t.TypeOf<typeof RuleResponse>; +export const RuleResponse = t.intersection([SharedResponseProps, TypeSpecificResponse]); + +// ------------------------------------------------------------------------------------------------- +// Rule preview schemas + +// TODO: Move to the rule_preview subdomain + +export type PreviewRulesSchema = t.TypeOf<typeof previewRulesSchema>; +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<typeof EventCategoryOverride>; +export const EventCategoryOverride = t.string; // should be non-empty string? + +export type TimestampField = t.TypeOf<typeof TimestampField>; +export const TimestampField = t.string; // should be non-empty string? + +export type TiebreakerField = t.TypeOf<typeof TiebreakerField>; +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<typeof NewTermsFields>; +export const NewTermsFields = LimitedSizeArray({ codec: t.string, minSize: 1, maxSize: 1 }); + +export type HistoryWindowStart = t.TypeOf<typeof HistoryWindowStart>; +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<typeof Threshold>; +export const Threshold = t.intersection([ + thresholdField, + t.exact( + t.partial({ + cardinality: t.array(thresholdCardinalityField), + }) + ), +]); + +export type ThresholdNormalized = t.TypeOf<typeof ThresholdNormalized>; +export const ThresholdNormalized = t.intersection([ + thresholdFieldNormalized, + t.exact( + t.partial({ + cardinality: t.array(thresholdCardinalityField), + }) + ), +]); + +export type ThresholdWithCardinality = t.TypeOf<typeof ThresholdWithCardinality>; +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<typeof author>; - -export const building_block_type = t.string; -export type BuildingBlockType = t.TypeOf<typeof building_block_type>; - -export const buildingBlockTypeOrUndefined = t.union([building_block_type, t.undefined]); - -export const description = NonEmptyString; -export type Description = t.TypeOf<typeof description>; - -// 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<typeof outcome>; - -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<typeof enabled>; -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<typeof file_name>; @@ -63,112 +16,13 @@ export type FileName = t.TypeOf<typeof file_name>; export const exclude_export_details = t.boolean; export type ExcludeExportDetails = t.TypeOf<typeof exclude_export_details>; -export const namespace = t.string; -export type Namespace = t.TypeOf<typeof namespace>; - -/** - * 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<typeof filters>; // Filters are not easily type-able yet - -export const filtersOrUndefined = t.union([filters, t.undefined]); -export type FiltersOrUndefined = t.TypeOf<typeof filtersOrUndefined>; - -export const immutable = t.boolean; -export type Immutable = t.TypeOf<typeof immutable>; - -// 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<typeof rule_id>; - -export const ruleIdOrUndefined = t.union([rule_id, t.undefined]); -export type RuleIdOrUndefined = t.TypeOf<typeof ruleIdOrUndefined>; - -export const id = UUID; -export type Id = t.TypeOf<typeof id>; - -export const idOrUndefined = t.union([id, t.undefined]); -export type IdOrUndefined = t.TypeOf<typeof idOrUndefined>; - -export const index = t.array(t.string); -export type Index = t.TypeOf<typeof index>; - -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<typeof indexOrUndefined>; - -export const interval = t.string; -export type Interval = t.TypeOf<typeof interval>; - -export const query = t.string; -export type Query = t.TypeOf<typeof query>; - -export const queryOrUndefined = t.union([query, t.undefined]); -export type QueryOrUndefined = t.TypeOf<typeof queryOrUndefined>; - -export const license = t.string; -export type License = t.TypeOf<typeof license>; - -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<typeof savedIdOrUndefined>; -export const timeline_id = t.string; -export type TimelineId = t.TypeOf<typeof timeline_id>; - -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<typeof timestamp_override>; - -export const timestampOverrideOrUndefined = t.union([timestamp_override, t.undefined]); -export type TimestampOverrideOrUndefined = t.TypeOf<typeof timestampOverrideOrUndefined>; - 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<typeof meta>; -export const metaOrUndefined = t.union([meta, t.undefined]); -export type MetaOrUndefined = t.TypeOf<typeof metaOrUndefined>; - -export const name = NonEmptyString; -export type Name = t.TypeOf<typeof name>; - -export const rule_name_override = t.string; -export type RuleNameOverride = t.TypeOf<typeof rule_name_override>; - -export const ruleNameOverrideOrUndefined = t.union([rule_name_override, t.undefined]); -export type RuleNameOverrideOrUndefined = t.TypeOf<typeof ruleNameOverrideOrUndefined>; - export const status = t.keyof({ open: null, closed: null, @@ -179,122 +33,34 @@ export type Status = t.TypeOf<typeof status>; 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<typeof to>; - export const queryFilter = t.string; export type QueryFilter = t.TypeOf<typeof queryFilter>; export const queryFilterOrUndefined = t.union([queryFilter, t.undefined]); export type QueryFilterOrUndefined = t.TypeOf<typeof queryFilterOrUndefined>; -export const references = t.array(t.string); -export type References = t.TypeOf<typeof references>; - export const signal_ids = t.array(t.string); export type SignalIds = t.TypeOf<typeof signal_ids>; // 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<typeof tags>; - export const fields = t.array(t.string); export type Fields = t.TypeOf<typeof fields>; export const fieldsOrUndefined = t.union([fields, t.undefined]); export type FieldsOrUndefined = t.TypeOf<typeof fieldsOrUndefined>; -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<typeof threshold>; - -export const thresholdNormalized = t.intersection([ - thresholdFieldNormalized, - t.exact( - t.partial({ - cardinality: t.array(thresholdCardinalityField), - }) - ), -]); -export type ThresholdNormalized = t.TypeOf<typeof thresholdNormalized>; - -export const thresholdWithCardinality = t.intersection([ - thresholdFieldNormalized, - t.exact( - t.type({ - cardinality: t.array(thresholdCardinalityField), - }) - ), -]); -export type ThresholdWithCardinality = t.TypeOf<typeof thresholdWithCardinality>; - -// 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<typeof newTermsFields>; - -export const historyWindowStart = NonEmptyString; -export type HistoryWindowStart = t.TypeOf<typeof historyWindowStart>; - 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<typeof note>; - -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<typeof createRuleExceptionsSchema>; - -// This type is used after a decode since some things are defaults after a decode. -export type CreateRuleExceptionSchemaDecoded = Omit< - RequiredKeepUndefined<t.TypeOf<typeof createRuleExceptionsSchema>>, - '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<typeof signalsReindexOptions>; 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<typeof exportRulesSchema>; -export type ExportRulesSchemaDecoded = ExportRulesSchema; - -export const exportRulesQuerySchema = t.exact( - t.partial({ file_name: DefaultExportFileName, exclude_export_details: DefaultStringBooleanFalse }) -); - -export type ExportRulesQuerySchema = t.TypeOf<typeof exportRulesQuerySchema>; - -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<typeof patchRulesSchema>; - -const thresholdPatchSchema = t.intersection([thresholdPatchParams, sharedPatchSchema]); -export type ThresholdPatchSchema = t.TypeOf<typeof thresholdPatchSchema>; 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<QueryRuleByIdSchema> = {}; - - 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<QueryRuleByIdSchema> = { - 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<typeof queryRulesBulkSchema>; - -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<P extends t.Props> = { - [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<t.Props>((acc, key) => { - acc[key] = t.union([optionalFields[key], t.undefined]); - return acc; - }, {}) as OrUndefined<Optional>; - return t.intersection([ - t.exact(t.type(requiredFields)), - t.exact(t.type(optionalWithUndefined)), - t.exact(t.type(defaultableFields)), - ]); -}; - -export const buildAPISchemas = <R extends t.Props, O extends t.Props, D extends t.Props>( - params: APIParams<R, O, D> -) => { - 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<typeof sharedCreateSchema>; - -export const sharedUpdateSchema = t.intersection([ - baseCreateParams, - t.exact(t.partial({ rule_id })), - t.exact(t.partial({ id })), -]); -export type SharedUpdateSchema = t.TypeOf<typeof sharedUpdateSchema>; - -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<typeof createTypeSpecific>; - -// Convenience types for building specific types of rules -type CreateSchema<T> = SharedCreateSchema & T; -export type EqlCreateSchema = CreateSchema<t.TypeOf<typeof eqlCreateParams>>; -export type ThreatMatchCreateSchema = CreateSchema<t.TypeOf<typeof threatMatchCreateParams>>; -export type QueryCreateSchema = CreateSchema<t.TypeOf<typeof queryCreateParams>>; -export type SavedQueryCreateSchema = CreateSchema<t.TypeOf<typeof savedQueryCreateParams>>; -export type ThresholdCreateSchema = CreateSchema<t.TypeOf<typeof thresholdCreateParams>>; -export type MachineLearningCreateSchema = CreateSchema< - t.TypeOf<typeof machineLearningCreateParams> ->; -export type NewTermsCreateSchema = CreateSchema<t.TypeOf<typeof newTermsCreateParams>>; - -export const createRulesSchema = t.intersection([sharedCreateSchema, createTypeSpecific]); -export type CreateRulesSchema = t.TypeOf<typeof createRulesSchema>; -export const previewRulesSchema = t.intersection([ - sharedCreateSchema, - createTypeSpecific, - t.type({ invocationCount: t.number, timeframeEnd: t.string }), -]); -export type PreviewRulesSchema = t.TypeOf<typeof previewRulesSchema>; - -type UpdateSchema<T> = SharedUpdateSchema & T; -export type QueryUpdateSchema = UpdateSchema<t.TypeOf<typeof queryCreateParams>>; -export type MachineLearningUpdateSchema = UpdateSchema< - t.TypeOf<typeof machineLearningCreateParams> ->; -export type NewTermsUpdateSchema = UpdateSchema<t.TypeOf<typeof newTermsCreateParams>>; - -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<typeof eqlPatchParams>; -export type ThreatMatchPatchParams = t.TypeOf<typeof threatMatchPatchParams>; -export type QueryPatchParams = t.TypeOf<typeof queryPatchParams>; -export type SavedQueryPatchParams = t.TypeOf<typeof savedQueryPatchParams>; -export type ThresholdPatchParams = t.TypeOf<typeof thresholdPatchParams>; -export type MachineLearningPatchParams = t.TypeOf<typeof machineLearningPatchParams>; -export type NewTermsPatchParams = t.TypeOf<typeof newTermsPatchParams>; - -const responseTypeSpecific = t.union([ - eqlResponseParams, - threatMatchResponseParams, - queryResponseParams, - savedQueryResponseParams, - thresholdResponseParams, - machineLearningResponseParams, - newTermsResponseParams, -]); -export type ResponseTypeSpecific = t.TypeOf<typeof responseTypeSpecific>; - -export const updateRulesSchema = t.intersection([createTypeSpecific, sharedUpdateSchema]); -export type UpdateRulesSchema = t.TypeOf<typeof updateRulesSchema>; - -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<typeof sharedResponseSchema>; -export const fullResponseSchema = t.intersection([sharedResponseSchema, responseTypeSpecific]); -export type FullResponseSchema = t.TypeOf<typeof fullResponseSchema>; - -// Convenience types for type specific responses -type ResponseSchema<T> = SharedResponseSchema & T; -export type EqlResponseSchema = ResponseSchema<t.TypeOf<typeof eqlResponseParams>>; -export type ThreatMatchResponseSchema = ResponseSchema<t.TypeOf<typeof threatMatchResponseParams>>; -export type QueryResponseSchema = ResponseSchema<t.TypeOf<typeof queryResponseParams>>; -export type SavedQueryResponseSchema = ResponseSchema<t.TypeOf<typeof savedQueryResponseParams>>; -export type ThresholdResponseSchema = ResponseSchema<t.TypeOf<typeof thresholdResponseParams>>; -export type MachineLearningResponseSchema = ResponseSchema< - t.TypeOf<typeof machineLearningResponseParams> ->; -export type NewTermsResponseSchema = ResponseSchema<t.TypeOf<typeof newTermsResponseParams>>; - -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<typeof rulesBulkSchema>; 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<ExceptionListItemSchema | CreateExceptionListItemSchema> 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<string, number> = { + 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 d173798dcf87c..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 @@ -17,6 +17,7 @@ import type { 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 @@ -91,7 +92,7 @@ export class FleetAgentGenerator extends BaseDataGenerator<Agent> { componentStatus === 'failed' ? { error: { - code: 123, + code: ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR, message: 'Unable to connect to Elasticsearch', }, } 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<typeof EndpointActionGetFileSchema.body>; + +/** 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<typeof SingleTimelineRe export const ResolvedTimelineSavedObjectToReturnObjectRuntimeType = runtimeTypes.intersection([ runtimeTypes.type({ timeline: TimelineSavedToReturnObjectRuntimeType, - outcome: savedObjectResolveOutcome, + outcome: SavedObjectResolveOutcome, }), runtimeTypes.partial({ - alias_target_id: runtimeTypes.string, - alias_purpose: savedObjectResolveAliasPurpose, + alias_target_id: SavedObjectResolveAliasTargetId, + alias_purpose: SavedObjectResolveAliasPurpose, }), ]); diff --git a/x-pack/plugins/security_solution/common/types/timeline/store.ts b/x-pack/plugins/security_solution/common/types/timeline/store.ts index af7662122b5d3..047c8d20e15b7 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/store.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/store.ts @@ -61,6 +61,7 @@ export interface TimelinePersistInput { timelineType?: TimelineTypeLiteral; templateTimelineId?: string | null; templateTimelineVersion?: number | null; + title?: string; } /** Invoked when a column is sorted */ diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/prebuilt_rules.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/prebuilt_rules.cy.ts index c9f5e57fb2285..943a3e5e236fa 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/prebuilt_rules.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/prebuilt_rules.cy.ts @@ -8,7 +8,7 @@ import { COLLAPSED_ACTION_BTN, ELASTIC_RULES_BTN, - RELOAD_PREBUILT_RULES_BTN, + LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN, RULES_EMPTY_PROMPT, RULES_MONITORING_TABLE, RULES_ROW, @@ -111,12 +111,15 @@ describe('Prebuilt rules', () => { '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/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<FullResponseSchema> -): string => { +export const expectedExportedRule = (ruleResponse: Cypress.Response<RuleResponse>): 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<FullResponseSchema> = { + const rule: Partial<RuleResponse> = { id, updated_at: updatedAt, updated_by: updatedBy, 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/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/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<PrePackagedRulesStatusResponse>({ 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/rule_details.ts b/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts index bbfadc337f5e2..3d4f25d248e6a 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts @@ -136,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<EventsQueryTabBodyComponentProps> = ({ + additionalFilters, deleteQuery, endDate, filterQuery, indexNames, - externalAlertPageFilters = [], - pageFilters = [], setQuery, startDate, tableId, @@ -110,6 +108,7 @@ const EventsQueryTabBodyComponent: React.FC<EventsQueryTabBodyComponentProps> = } : c ), + title: i18n.EVENTS_GRAPH_TITLE, }) ); }, [dispatch, showExternalAlerts, tGridEnabled, tableId]); @@ -122,7 +121,7 @@ const EventsQueryTabBodyComponent: React.FC<EventsQueryTabBodyComponentProps> = }; }, [deleteQuery]); - const additionalFilters = useMemo( + const toggleExternalAlertsCheckbox = useMemo( () => ( <EuiCheckbox id="showExternalAlertsCheckbox" @@ -146,11 +145,8 @@ const EventsQueryTabBodyComponent: React.FC<EventsQueryTabBodyComponentProps> = ); 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<EventsQueryTabBodyComponentProps> = /> )} <StatefulEventsViewer - additionalFilters={additionalFilters} + additionalFilters={toggleExternalAlertsCheckbox} defaultCellActions={defaultCellActions} start={startDate} end={endDate} diff --git a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx index 822d4b7cc794d..a291265bc234d 100644 --- a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx @@ -23,7 +23,7 @@ import React, { useCallback, useState } from 'react'; import type { ImportDataResponse, ImportDataProps, -} from '../../../detections/containers/detection_engine/rules'; +} from '../../../detection_engine/rule_management/logic'; import { useAppToasts } from '../../hooks/use_app_toasts'; import * as i18n from './translations'; import { showToasterMessage } from './utils'; @@ -48,6 +48,7 @@ interface ImportDataModalProps { /** * Modal component for importing Rules from a json file */ +// TODO split into two: timelines and rules export const ImportDataModalComponent = ({ checkBoxLabel, closeModal, diff --git a/x-pack/plugins/security_solution/public/common/components/import_data_modal/utils.ts b/x-pack/plugins/security_solution/public/common/components/import_data_modal/utils.ts index d6158dfe97ff6..8211c01a7bffa 100644 --- a/x-pack/plugins/security_solution/public/common/components/import_data_modal/utils.ts +++ b/x-pack/plugins/security_solution/public/common/components/import_data_modal/utils.ts @@ -14,7 +14,7 @@ import type { ImportResponseError, ImportRulesResponseError, ExceptionsImportError, -} from '../../../detections/containers/detection_engine/rules'; +} from '../../../detection_engine/rule_management/logic'; export const formatError = ( i18nFailedDetailedMessage: (message: string) => 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<AnomaliesCount[]>(formatResultData([], [])); - const refetch = useRef<inputsModel.Refetch>(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$<number>(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<MlSummaryJob[][], MlSummaryJob[], MlSummaryJob[], MlSummaryJob | undefined>( - filter<MlSummaryJob>(({ id }) => matchJobId(id, notableJobId)), - orderBy<MlSummaryJob>('latestTimestampSortValue', 'desc'), + pipe<SecurityJob[][], SecurityJob[], SecurityJob[], SecurityJob | undefined>( + filter<SecurityJob>(({ id }) => matchJobId(id, notableJobId)), + orderBy<SecurityJob>('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<string[]>( - (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<string[]>((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<string[]>( (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<CombinedJobWithStats[]>([]); 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 }) => ( + <TestProviders store={store}>{children}</TestProviders> +); + +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<SecurityJob[]>([]); const [loading, setLoading] = useState(true); const mlCapabilities = useMlCapabilities(); const [securitySolutionDefaultIndex] = useUiSetting$<string[]>(DEFAULT_INDEX_KEY); const http = useHttp(); const { addError } = useAppToasts(); - + const refetch = useRef<inputsModel.Refetch>(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(() => { <MLJobsAwaitingNodeWarning jobIds={installedJobsIds} /> <JobsTable - isLoading={isLoadingSecurityJobs || isLoading} + isLoading={isLoadingSecurityJobs || isLoadingEnableDataFeed} jobs={filteredJobs} onJobStateChange={handleJobStateChange} /> @@ -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<Action>, - dispatchToaster: Dispatch<ActionToaster> -) => { - 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/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<Pick<Filter, 'meta' | 'query'>> = { query: { @@ -102,6 +104,17 @@ const SessionsViewComponent: React.FC<SessionsComponentsProps> = ({ 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 ( <div data-test-subj={TEST_ID}> <StatefulEventsViewer diff --git a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts index ea35892f3a2f9..15e12212bb998 100644 --- a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts @@ -7,6 +7,10 @@ import { i18n } from '@kbn/i18n'; +export const SESSIONS_TITLE = i18n.translate('xpack.securitySolution.sessionsView.sessionsTitle', { + defaultMessage: 'Sessions', +}); + export const TOTAL_COUNT_OF_SESSIONS = i18n.translate( 'xpack.securitySolution.sessionsView.totalCountOfSessions', { diff --git a/x-pack/plugins/security_solution/public/common/components/top_risk_score_contributors/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_risk_score_contributors/index.tsx index 7f59912829438..eaf8f9f35cc66 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_risk_score_contributors/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_risk_score_contributors/index.tsx @@ -16,7 +16,7 @@ import * as i18n from './translations'; import type { RuleRisk } from '../../../../common/search_strategy'; -import { RuleLink } from '../../../detections/pages/detection_engine/rules/all/use_columns'; +import { RuleLink } from '../../../detection_engine/rule_management_ui/components/rules_table/use_columns'; export interface TopRiskScoreContributorsProps { loading: boolean; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/authentication.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/authentication.test.ts.snap index f683d2828bae3..84d29e3e7fd9d 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/authentication.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/authentication.test.ts.snap @@ -169,17 +169,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/external_alert.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/external_alert.test.ts.snap index 425f545129ee6..d53499bd57c8a 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/external_alert.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/__snapshots__/external_alert.test.ts.snap @@ -149,17 +149,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/event.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/event.test.ts.snap index 129a82aa1692c..b5a707a8bc4bd 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/event.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/event.test.ts.snap @@ -118,17 +118,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_area.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_area.test.ts.snap index b9165ea5c38a8..c8de37bfbd678 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_area.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_area.test.ts.snap @@ -97,17 +97,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_metric.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_metric.test.ts.snap index ea37bec0d1976..e4328cb0178e2 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_metric.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_host_metric.test.ts.snap @@ -85,17 +85,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_area.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_area.test.ts.snap index f45cd86c70ed2..18d0e8f86d936 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_area.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_area.test.ts.snap @@ -131,17 +131,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_bar.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_bar.test.ts.snap index 0a66d46f9a7db..ea60bad9c8efd 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_bar.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_bar.test.ts.snap @@ -144,17 +144,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_destination_metric.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_destination_metric.test.ts.snap index 3ca56d9f020b2..48eff6c978975 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_destination_metric.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_destination_metric.test.ts.snap @@ -85,17 +85,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_source_metric.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_source_metric.test.ts.snap index 2972842a6f419..31f9e00156dd1 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_source_metric.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/hosts/__snapshots__/kpi_unique_ips_source_metric.test.ts.snap @@ -85,17 +85,11 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "host.name", - }, - }, - ], + "exists": Object { + "field": "host.name", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/dns_top_domains.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/dns_top_domains.test.ts.snap index 392d68b512b41..975d82eff3955 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/dns_top_domains.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/dns_top_domains.test.ts.snap @@ -124,36 +124,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "source.ip", + }, + }, Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_dns_queries.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_dns_queries.test.ts.snap index 173a1229e1282..34bc6f13f8004 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_dns_queries.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_dns_queries.test.ts.snap @@ -111,36 +111,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "source.ip", + }, + }, + Object { + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_network_events.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_network_events.test.ts.snap index c9b0441a25a4b..b29761bbf8a74 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_network_events.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_network_events.test.ts.snap @@ -116,36 +116,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "source.ip", + }, + }, Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_tls_handshakes.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_tls_handshakes.test.ts.snap index 532d81001ab06..b8ed38aa918c4 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_tls_handshakes.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_tls_handshakes.test.ts.snap @@ -135,36 +135,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "source.ip", + }, + }, + Object { + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_flow_ids.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_flow_ids.test.ts.snap index 60a52f4f5b4a9..06daf745e0345 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_flow_ids.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_flow_ids.test.ts.snap @@ -99,36 +99,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "source.ip", + }, + }, + Object { + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_area.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_area.test.ts.snap index 11e3f62d0cd4c..51e91c05bd975 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_area.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_area.test.ts.snap @@ -121,36 +121,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "source.ip", + }, + }, Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_bar.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_bar.test.ts.snap index 2a702bb87f3fd..1d842f74d89b5 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_bar.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_bar.test.ts.snap @@ -134,36 +134,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "source.ip", + }, + }, + Object { + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_destination_metric.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_destination_metric.test.ts.snap index 9f205c5c23c07..60eea0dd437a8 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_destination_metric.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_destination_metric.test.ts.snap @@ -72,36 +72,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "source.ip", + }, + }, Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_source_metric.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_source_metric.test.ts.snap index b7e25a6ceb8f4..ee5bea71f89fd 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_source_metric.test.ts.snap +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/network/__snapshots__/kpi_unique_private_ips_source_metric.test.ts.snap @@ -72,36 +72,16 @@ Object { }, "query": Object { "bool": Object { - "filter": Array [ + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "source.ip", + }, + }, Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "source.ip", - }, - }, - ], - }, - }, - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "exists": Object { - "field": "destination.ip", - }, - }, - ], - }, - }, - ], + "exists": Object { + "field": "destination.ip", }, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx index 2cb8710aac45c..ec547ab44eba5 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx @@ -16,7 +16,7 @@ import { useRouteSpy } from '../../utils/route/use_route_spy'; import type { LensAttributes, GetLensAttributes } from './types'; import { getHostDetailsPageFilter, - filterNetworkExternalAlertData, + sourceOrDestinationIpExistsFilter, hostNameExistsFilter, getIndexFilters, } from './utils'; @@ -46,7 +46,7 @@ export const useLensAttributes = ({ } if (pageName === SecurityPageName.network && tabName === NetworkRouteType.events) { - return filterNetworkExternalAlertData; + return sourceOrDestinationIpExistsFilter; } return []; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts index c66a608ecd989..9fe0a83a45d76 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts @@ -34,20 +34,14 @@ export const hostNameExistsFilter: Filter[] = [ { query: { bool: { - filter: [ + should: [ { - bool: { - should: [ - { - exists: { - field: 'host.name', - }, - }, - ], - minimum_should_match: 1, + exists: { + field: 'host.name', }, }, ], + minimum_should_match: 1, }, }, meta: { @@ -97,43 +91,23 @@ export const getNetworkDetailsPageFilter = (ipAddress?: string): Filter[] => ] : []; -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<IFleetIntegrationsApiClient> = { + fetchInstalledIntegrations: jest + .fn<Promise<GetInstalledIntegrationsResponse>, [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/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/index.ts b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/index.ts new file mode 100644 index 0000000000000..ebfcff4941a99 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/fleet_integrations/api/__mocks__/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_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<GetInstalledIntegrationsResponse> => { + const { packages, signal } = args; + + return http().fetch<GetInstalledIntegrationsResponse>(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<GetInstalledIntegrationsResponse>; +} + +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<CreateRulesSchema>( + const result = formatRule<RuleCreateProps>( mockDefineStepRuleWithoutSavedId, mockAbout, mockSchedule, @@ -969,14 +969,9 @@ describe('helpers', () => { }); test('returns rule without id if ruleId does not exist', () => { - const result = formatRule<CreateRulesSchema>( - mockDefine, - mockAbout, - mockSchedule, - mockActions - ); + const result = formatRule<RuleCreateProps>(mockDefine, mockAbout, mockSchedule, mockActions); - expect(result).not.toHaveProperty<CreateRulesSchema>('id'); + expect(result).not.toHaveProperty<RuleCreateProps>('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 = <T>( 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<CreateRulesSchema>( + ...formatRule<RuleCreateProps>( 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> => 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<CreateRulesSchema>( + const createdRule = await createRule( + formatRule<RuleCreateProps>( 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> => 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<UpdateRulesSchema>( + await updateRule({ + ...formatRule<RuleUpdateProps>( 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 2989b77ec28de..5e7bf4a7019a7 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<DetectionEngineComponentProps> = ({ 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<Status>(FILTER_OPEN); const [dataViewOptions, setDataViewOptions] = useState<{ [x: string]: DataViewListItem }>({}); @@ -584,45 +583,6 @@ const RuleDetailsPageComponent: React.FC<DetectionEngineComponentProps> = ({ 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 ( - <EuiToolTip position="top" content={ruleI18n.EDIT_RULE_SETTINGS_TOOLTIP}> - <LinkButton - onClick={goToEditRule} - iconType="controlsHorizontal" - isDisabled={true} - href={formatUrl(getEditRuleUrl(ruleId ?? ''))} - > - {ruleI18n.EDIT_RULE_SETTINGS} - </LinkButton> - </EuiToolTip> - ); - } - return ( - <LinkButton - data-test-subj="editRuleSettingsLink" - onClick={goToEditRule} - iconType="controlsHorizontal" - isDisabled={!isExistingRule || !userHasPermissions(canUserCRUD)} - href={formatUrl(getEditRuleUrl(ruleId ?? ''))} - > - {ruleI18n.EDIT_RULE_SETTINGS} - </LinkButton> - ); - }, [isExistingRule, canUserCRUD, formatUrl, goToEditRule, hasActionsPrivileges, ruleId]); - const onShowBuildingBlockAlertsChangedCallback = useCallback( (newShowBuildingBlockAlerts: boolean) => { setShowBuildingBlockAlerts(newShowBuildingBlockAlerts); @@ -719,7 +679,12 @@ const RuleDetailsPageComponent: React.FC<DetectionEngineComponentProps> = ({ <EuiFlexItem grow={false}> <EuiToolTip position="top" - content={getToolTipContent(rule, hasMlPermissions, hasActionsPrivileges)} + content={explainLackOfPermission( + rule, + hasMlPermissions, + hasActionsPrivileges, + canUserCRUD + )} > <EuiFlexGroup> <RuleSwitch @@ -727,8 +692,8 @@ const RuleDetailsPageComponent: React.FC<DetectionEngineComponentProps> = ({ isDisabled={ !isExistingRule || !canEditRuleWithActions(rule, hasActionsPrivileges) || - !userHasPermissions(canUserCRUD) || - (!hasMlPermissions && !rule?.enabled) + !hasUserCRUDPermission(canUserCRUD) || + (isMlRule(rule?.type) && !hasMlPermissions) } enabled={isExistingRule && (rule?.enabled ?? false)} onChange={handleOnChangeEnabledRule} @@ -740,11 +705,26 @@ const RuleDetailsPageComponent: React.FC<DetectionEngineComponentProps> = ({ <EuiFlexItem grow={false}> <EuiFlexGroup alignItems="center" gutterSize="s" responsive={false}> - <EuiFlexItem grow={false}>{editRule}</EuiFlexItem> + <EuiFlexItem grow={false}> + <EditRuleSettingButtonLink + ruleId={ruleId} + disabled={ + !isExistingRule || + !hasUserCRUDPermission(canUserCRUD) || + (isMlRule(rule?.type) && !hasMlPermissions) + } + disabledReason={explainLackOfPermission( + rule, + hasMlPermissions, + hasActionsPrivileges, + canUserCRUD + )} + /> + </EuiFlexItem> <EuiFlexItem grow={false}> <RuleActionsOverflow rule={rule} - userHasPermissions={isExistingRule && userHasPermissions(canUserCRUD)} + userHasPermissions={isExistingRule && hasUserCRUDPermission(canUserCRUD)} canDuplicateRuleWithActions={canEditRuleWithActions( rule, hasActionsPrivileges diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/rule_details_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/rule_details_context.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/rule_details_context.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/rule_details_context.tsx index 58b34eb4a2bee..92de2e337dcad 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/rule_details_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/rule_details_context.tsx @@ -8,13 +8,13 @@ import type { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { DurationRange } from '@elastic/eui/src/components/date_picker/types'; import React, { createContext, useContext, useMemo, useState } from 'react'; -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'; -import { invariant } from '../../../../../../common/utils/invariant'; -import { useKibana } from '../../../../../common/lib/kibana'; +} from '../../../../../common/detection_engine/rule_monitoring'; +import { invariant } from '../../../../../common/utils/invariant'; +import { useKibana } from '../../../../common/lib/kibana'; import { RuleDetailTabs } from '.'; export interface ExecutionLogTableState { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/translations.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx index 0613f08b7f572..d422c7c5ce6bf 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx @@ -23,7 +23,7 @@ import { useCreateOrUpdateException } from '../../logic/use_create_update_except import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data'; import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index'; import * as helpers from '../../utils/helpers'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../rule_management/logic/types'; import * as i18n from './translations'; import { TestProviders } from '../../../../common/mock'; @@ -31,15 +31,14 @@ import { TestProviders } from '../../../../common/mock'; import { getRulesEqlSchemaMock, getRulesSchemaMock, -} from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; +} from '../../../../../common/detection_engine/rule_schema/mocks'; import type { AlertData } from '../../utils/types'; -import { useFindRules } from '../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'; +import { useFindRules } from '../../../rule_management/logic/use_find_rules'; import { useFindExceptionListReferences } from '../../logic/use_find_references'; jest.mock('../../../../detections/containers/detection_engine/alerts/use_signal_index'); jest.mock('../../../../common/lib/kibana'); jest.mock('../../../../common/containers/source'); -jest.mock('../../../../detections/containers/detection_engine/rules'); jest.mock('../../logic/use_create_update_exception'); jest.mock('../../logic/use_exception_flyout_data'); jest.mock('../../logic/use_find_references'); @@ -47,9 +46,9 @@ jest.mock('@kbn/securitysolution-hook-utils', () => ({ ...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('../../../../detections/pages/detection_engine/rules/all/rules_table/use_find_rules'); +jest.mock('../../../rule_management/logic/use_find_rules'); const mockGetExceptionBuilderComponentLazy = getExceptionBuilderComponentLazy as jest.Mock< ReturnType<typeof getExceptionBuilderComponentLazy> 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 6d190913e358d..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 @@ -24,16 +24,18 @@ import { EuiCallOut, EuiText, } from '@elastic/eui'; + +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 { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import type { Status } from '../../../../../common/detection_engine/schemas/common/schemas'; import * as i18n from './translations'; +import { ExceptionItemComments } from '../item_comments'; import { defaultEndpointExceptionItems, retrieveAlertOsTypes, @@ -44,14 +46,13 @@ 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 '../../../../detections/containers/detection_engine/rules/types'; +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'; -import { ExceptionItemComments } from '../item_comments'; const SectionHeader = styled(EuiTitle)` ${() => css` 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 index 3e5f8afd19626..c36c842930b0f 100644 --- 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 @@ -12,7 +12,7 @@ import type { ExceptionsBuilderReturnExceptionItem, } from '@kbn/securitysolution-list-utils'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../rule_management/logic/types'; export interface State { exceptionItemMeta: { name: string }; 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 index 909d8e8580472..7aa686ed43cdf 100644 --- 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 @@ -22,7 +22,7 @@ import type { ExceptionsBuilderReturnExceptionItem } from '@kbn/securitysolution import * as i18n from './translations'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../rule_management/logic/types'; import { useCreateOrUpdateException } from '../../logic/use_create_update_exception'; import { useAddRuleDefaultException } from '../../logic/use_add_rule_exception'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.test.tsx index 6f42a4627135a..dc6a0ea238310 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/all_exception_items_table/index.test.tsx @@ -13,8 +13,8 @@ import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionsViewer } from '.'; import { useKibana } from '../../../../common/lib/kibana'; import { TestProviders } from '../../../../common/mock'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; -import { mockRule } from '../../../../detections/pages/detection_engine/rules/all/__mocks__/mock'; +import type { Rule } from '../../../rule_management/logic/types'; +import { mockRule } from '../../../rule_management_ui/components/rules_table/__mocks__/mock'; import { useFindExceptionListReferences } from '../../logic/use_find_references'; import * as i18n from './translations'; 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 6de23a76981b8..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 @@ -38,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; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx index c313d8cc2aeeb..09ed03130ef08 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx @@ -19,13 +19,14 @@ import { useFetchIndex } from '../../../../common/containers/source'; import { createStubIndexPattern, stubIndexPattern } from '@kbn/data-plugin/common/stubs'; import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; +import type { Rule } from '../../../rule_management/logic/types'; import type { EntriesArray } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { getRulesEqlSchemaMock, getRulesSchemaMock, -} from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; +} from '../../../../../common/detection_engine/rule_schema/mocks'; + import { getMockTheme } from '../../../../common/lib/kibana/kibana_react.mock'; import { getExceptionBuilderComponentLazy } from '@kbn/lists-plugin/public'; import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; @@ -44,14 +45,13 @@ const mockTheme = getMockTheme({ }); jest.mock('../../../../common/lib/kibana'); -jest.mock('../../../../detections/containers/detection_engine/rules'); jest.mock('../../logic/use_create_update_exception'); jest.mock('../../logic/use_exception_flyout_data'); jest.mock('../../../../common/containers/source'); jest.mock('../../logic/use_find_references'); jest.mock('../../logic/use_fetch_or_create_rule_exception_list'); jest.mock('../../../../detections/containers/detection_engine/alerts/use_signal_index'); -jest.mock('../../../../detections/containers/detection_engine/rules/use_rule_async'); +jest.mock('../../../rule_management/logic/use_rule'); jest.mock('@kbn/lists-plugin/public'); const mockGetExceptionBuilderComponentLazy = getExceptionBuilderComponentLazy as jest.Mock< 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 d6dbc402a92e6..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,6 +5,7 @@ * 2.0. */ +import { isEmpty } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useReducer } from 'react'; import styled, { css } from 'styled-components'; import { @@ -30,28 +31,31 @@ import { exceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { isEmpty } from 'lodash/fp'; import type { ExceptionsBuilderReturnExceptionItem } from '@kbn/securitysolution-list-utils'; -import * as i18n from './translations'; -import { ExceptionsFlyoutMeta } from '../flyout_components/item_meta_form'; -import { createExceptionItemsReducer } from './reducer'; -import { ExceptionsLinkedToLists } from '../flyout_components/linked_to_list'; -import { ExceptionsLinkedToRule } from '../flyout_components/linked_to_rule'; -import type { Rule } from '../../../../detections/containers/detection_engine/rules/types'; -import { ExceptionItemsFlyoutAlertsActions } from '../flyout_components/alerts_actions'; -import { ExceptionsConditions } from '../flyout_components/item_conditions'; + import { isEqlRule, isNewTermsRule, isThresholdRule, } from '../../../../../common/detection_engine/utils'; -import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data'; + +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 { entrichExceptionItemsForUpdate } from '../flyout_components/utils'; -import { useEditExceptionItems } from './use_edit_exception'; +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 { list: ExceptionListSchema; 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( <ErrorCallout http={mockKibanaHttpService} @@ -153,8 +151,8 @@ describe('ErrorCallout', () => { /> ); - 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 = ({ <EuiButtonEmpty data-test-subj="errorCalloutCancelButton" color="danger" - isDisabled={isDissasociatingList} + isDisabled={isDisassociatingList} onClick={onCancel} > {i18n.CANCEL} </EuiButtonEmpty> {canDisplay404Actions && ( <EuiButton - data-test-subj="errorCalloutDissasociateButton" - isLoading={isDissasociatingList} - onClick={handleDissasociateList} + data-test-subj="errorCalloutDisassociateButton" + isLoading={isDisassociatingList} + onClick={handleDisassociateList} color="danger" > {i18n.CLEAR_EXCEPTIONS_LABEL} 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 233e11b0709eb..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 @@ -16,7 +16,7 @@ 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 { 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 8005264636bfa..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 @@ -25,9 +25,9 @@ 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)` 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<ExceptionsAddToRulesComponent initiallySelectedRules, onRuleSelectionChange, }) => { - 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 4869c80c172a2..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'; 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/logic/use_add_rule_exception.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_add_rule_exception.tsx index 7cf4ff2d8417d..c25ffda8ece14 100644 --- 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 @@ -11,8 +11,8 @@ import type { } from '@kbn/securitysolution-io-ts-list-types'; import { useEffect, useRef, useState } from 'react'; -import { addRuleExceptions } from '../../../detections/containers/detection_engine/rules/api'; -import type { Rule } from '../../../detections/containers/detection_engine/rules/types'; +import { addRuleExceptions } from '../../rule_management/api/api'; +import type { Rule } from '../../rule_management/logic/types'; /** * Adds exception items to rules default exception list 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 index 5dc960cb96e2c..a6dce444527d0 100644 --- 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 @@ -16,7 +16,7 @@ import { buildAlertsFilter, } 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 type { IndexPatternArray } from '../../../../common/detection_engine/rule_schema'; import { prepareExceptionItemsForBulkClose } from '../utils/helpers'; import * as i18nCommon from '../../../common/translations'; import * as i18n from './translations'; @@ -35,7 +35,7 @@ export type AddOrUpdateExceptionItemsFunc = ( ruleStaticIds: string[], exceptionItems: ExceptionListItemSchema[], alertIdToClose?: string, - bulkCloseIndex?: Index + bulkCloseIndex?: IndexPatternArray ) => Promise<void>; export type ReturnUseCloseAlertsFromExceptions = [boolean, AddOrUpdateExceptionItemsFunc | null]; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx index 57cfda994d37c..cec9be976592e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx @@ -8,7 +8,7 @@ import { useEffect, useState, useMemo } from 'react'; import type { DataViewBase } from '@kbn/es-query'; -import type { Rule } from '../../../detections/containers/detection_engine/rules/types'; +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'; 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/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<void>; @@ -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<FullResponseSchema> => +export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise<RuleResponse> => Promise.resolve(getRulesSchemaMock()); -export const createRule = async ({ rule, signal }: CreateRulesProps): Promise<FullResponseSchema> => +export const createRule = async ({ rule, signal }: CreateRulesProps): Promise<RuleResponse> => Promise.resolve(getRulesSchemaMock()); export const patchRule = async ({ ruleProperties, signal, -}: PatchRuleProps): Promise<FullResponseSchema> => Promise.resolve(getRulesSchemaMock()); +}: PatchRuleProps): Promise<RuleResponse> => Promise.resolve(getRulesSchemaMock()); export const getPrePackagedRulesStatus = async ({ signal, @@ -62,30 +60,4 @@ export const fetchRules = async (_: FetchRulesProps): Promise<FetchRulesResponse export const fetchTags = async ({ signal }: { signal: AbortSignal }): Promise<string[]> => Promise.resolve(['elastic', 'love', 'quality', 'code']); -// do not delete -export const fetchInstalledIntegrations = async ({ - packages, - signal, -}: { - packages?: string[]; - signal?: AbortSignal; -}): Promise<GetInstalledIntegrationsResponse> => { - 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 69% 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 e2c1e0d31cd57..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,64 +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<FullResponseSchema> => - KibanaServices.get().http.fetch<FullResponseSchema>(DETECTION_ENGINE_RULES_URL, { +export const createRule = async ({ rule, signal }: CreateRulesProps): Promise<RuleResponse> => + KibanaServices.get().http.fetch<RuleResponse>(DETECTION_ENGINE_RULES_URL, { method: 'POST', body: JSON.stringify(rule), signal, @@ -72,13 +73,13 @@ export const createRule = async ({ rule, signal }: CreateRulesProps): Promise<Fu /** * Update provided Rule using PUT * - * @param rule UpdateRulesSchema to be updated + * @param rule RuleUpdateProps to be updated * @param signal to cancel request * * @throws An error if response is not OK */ -export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise<FullResponseSchema> => - KibanaServices.get().http.fetch<FullResponseSchema>(DETECTION_ENGINE_RULES_URL, { +export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise<RuleResponse> => + KibanaServices.get().http.fetch<RuleResponse>(DETECTION_ENGINE_RULES_URL, { method: 'PUT', body: JSON.stringify(rule), signal, @@ -98,8 +99,8 @@ export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise<Fu export const patchRule = async ({ ruleProperties, signal, -}: PatchRuleProps): Promise<FullResponseSchema> => - KibanaServices.get().http.fetch<FullResponseSchema>(DETECTION_ENGINE_RULES_URL, { +}: PatchRuleProps): Promise<RuleResponse> => + KibanaServices.get().http.fetch<RuleResponse>(DETECTION_ENGINE_RULES_URL, { method: 'PATCH', body: JSON.stringify(ruleProperties), signal, @@ -108,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 @@ -177,28 +178,49 @@ export const fetchRules = async ({ * @throws An error if response is not OK */ export const fetchRuleById = async ({ id, signal }: FetchRuleProps): Promise<Rule> => - 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<Rule> => - http.fetch<Rule>(DETECTION_ENGINE_RULES_URL, { + KibanaServices.get().http.fetch<Rule>(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<BulkAction, BulkAction.export>; + query?: string; + ids?: string[]; + edit?: BulkActionEditPayload[]; + isDryRun?: boolean; +} + /** * Perform bulk action with rules selected by a filter query * @@ -210,48 +232,75 @@ export const pureFetchRuleById = async ({ * * @throws An error if response is not OK */ -export const performBulkAction = async <Action extends BulkAction>({ +export const performBulkAction = async ({ action, query, edit, ids, isDryRun, -}: BulkActionProps<Action>): Promise<BulkActionResponseMap<Action>> => - KibanaServices.get().http.fetch<BulkActionResponseMap<Action>>( - 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<BulkActionResponse> => + KibanaServices.get().http.fetch<BulkActionResponse>(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<BulkExportResponse> => + KibanaServices.get().http.fetch<BulkExportResponse>(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<CreatePrepackagedRulesResponse> => { 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', }); @@ -320,6 +369,8 @@ export const exportRules = async ({ }); }; +export type FetchTagsResponse = string[]; + /** * Fetch all unique Tags used by Rules * @@ -327,8 +378,8 @@ export const exportRules = async ({ * * @throws An error if response is not OK */ -export const fetchTags = async ({ signal }: { signal: AbortSignal }): Promise<string[]> => - KibanaServices.get().http.fetch<string[]>(DETECTION_ENGINE_TAGS_URL, { +export const fetchTags = async ({ signal }: { signal?: AbortSignal }): Promise<FetchTagsResponse> => + KibanaServices.get().http.fetch<FetchTagsResponse>(DETECTION_ENGINE_TAGS_URL, { method: 'GET', signal, }); @@ -345,39 +396,10 @@ export const getPrePackagedRulesStatus = async ({ }: { signal: AbortSignal | undefined; }): Promise<PrePackagedRulesStatusResponse> => - KibanaServices.get().http.fetch<PrePackagedRulesStatusResponse>( - 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<GetInstalledIntegrationsResponse> => - KibanaServices.get().http.fetch<GetInstalledIntegrationsResponse>( - DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL, - { - method: 'GET', - query: { - packages: packages?.sort()?.join(','), - }, - signal, - } - ); + KibanaServices.get().http.fetch<PrePackagedRulesStatusResponse>(PREBUILT_RULES_STATUS_URL, { + method: 'GET', + signal, + }); /** * Fetch info on what exceptions lists are referenced by what rules 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 = <TData>(result: Partial<UseQueryResult<TData>>) => ({ + 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<PrePackagedRulesStatusResponse>({ + 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<BulkActionResponse, Error, BulkActionProps> +) => { + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); + const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); + const updateRulesCache = useUpdateRulesCache(); + + return useMutation<BulkActionResponse, Error, BulkActionProps>( + (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<BulkExportResponse, Error, BulkExportProps> +) => { + return useMutation<BulkExportResponse, Error, BulkExportProps>( + (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<CreatePrepackagedRulesResponse> +) => { + 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<RuleResponse, Error, RuleCreateProps> +) => { + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + const invalidateFetchPrePackagedRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); + + return useMutation<RuleResponse, Error, RuleCreateProps>( + (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<PrePackagedRulesStatusResponse> +) => { + return useQuery<PrePackagedRulesStatusResponse>( + [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<Rule>) => { + return useQuery<Rule>( + [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<FetchTagsResponse>) => { + return useQuery<FetchTagsResponse>( + [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<RuleResponse, Error, RuleUpdateProps> +) => { + const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); + + return useMutation<RuleResponse, Error, RuleUpdateProps>( + (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<void> +) => { + 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<BulkAction, BulkAction.export>; + 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 extends BulkAction> { - 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<Action extends BulkAction> = { - [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<Func | null>(null); + const disassociateList = useRef<Func | null>(null); useEffect(() => { let isSubscribed = true; const abortCtrl = new AbortController(); - const dissasociateListFromRule = + const disassociateListFromRule = (id: string) => async (exceptionLists: List[]): Promise<void> => { 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<RulesQueryData, Error, RulesQueryData, [...string[], FindRulesQueryArgs]> +) => { + 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<AlertHit, undefined>({ @@ -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 <TagsForm {...props} editAction={editAction} tags={tags} />; + return <TagsForm {...props} editAction={editAction} />; case BulkActionEditType.set_timeline: return <TimelineTemplateForm {...props} />; 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<BulkActionEditPayload | null>; - 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<BulkActionForConfirmation>(); const [dryRunResult, setDryRunResult] = useState<DryRunResult>(); @@ -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<BulkActionEditPayload | null>(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 ( + <> + <RulesTableToolbar activeTab={activeTab} onTabChange={setActiveTab} /> + <EuiSpacer /> + <RulesTables selectedTab={activeTab} /> + </> + ); +}); + +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<typeof useFindRules>['refetch']; + reFetchRules: ReturnType<typeof useFindRulesInMemory>['refetch']; setFilterOptions: (newFilter: Partial<FilterOptions>) => void; setIsAllSelected: React.Dispatch<React.SetStateAction<boolean>>; 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( <TestProviders> <RulesTableUtilityBar canBulkEdit - onRefresh={jest.fn()} - pagination={{ - page: 1, - perPage: 10, - total: 21, - }} - numberSelectedItems={1} onGetBulkItemsPopoverContent={jest.fn()} - isAutoRefreshOn={true} - onRefreshSwitch={jest.fn()} onToggleSelectAll={jest.fn()} /> </TestProviders> @@ -43,45 +45,12 @@ describe('RulesTableUtilityBar', () => { ); }); - it('renders correct pagination label according to pagination data', () => { - const wrapper = mount( - <TestProviders> - <RulesTableUtilityBar - canBulkEdit - onRefresh={jest.fn()} - pagination={{ - page: 1, - perPage: 10, - total: 21, - }} - numberSelectedItems={1} - onGetBulkItemsPopoverContent={jest.fn()} - isAutoRefreshOn={true} - onRefreshSwitch={jest.fn()} - onToggleSelectAll={jest.fn()} - /> - </TestProviders> - ); - 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( <TestProviders> <RulesTableUtilityBar canBulkEdit - onRefresh={jest.fn()} - pagination={{ - page: 1, - perPage: 10, - total: 21, - }} - numberSelectedItems={1} onGetBulkItemsPopoverContent={jest.fn()} - isAutoRefreshOn={true} - onRefreshSwitch={jest.fn()} onToggleSelectAll={jest.fn()} /> </TestProviders> @@ -95,16 +64,7 @@ describe('RulesTableUtilityBar', () => { <TestProviders> <RulesTableUtilityBar canBulkEdit={false} - onRefresh={jest.fn()} - pagination={{ - page: 1, - perPage: 10, - total: 21, - }} - numberSelectedItems={1} onGetBulkItemsPopoverContent={jest.fn()} - isAutoRefreshOn={true} - onRefreshSwitch={jest.fn()} onToggleSelectAll={jest.fn()} /> </TestProviders> @@ -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( <TestProviders> <RulesTableUtilityBar canBulkEdit - onRefresh={mockRefresh} - pagination={{ - page: 1, - perPage: 10, - total: 21, - }} - numberSelectedItems={1} onGetBulkItemsPopoverContent={jest.fn()} - isAutoRefreshOn={true} - onRefreshSwitch={jest.fn()} onToggleSelectAll={jest.fn()} /> </TestProviders> @@ -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( <TestProviders> <RulesTableUtilityBar canBulkEdit - onRefresh={jest.fn()} - pagination={{ - page: 1, - perPage: 10, - total: 21, - }} - numberSelectedItems={0} onGetBulkItemsPopoverContent={jest.fn()} - isAutoRefreshOn={true} - onRefreshSwitch={mockSwitch} onToggleSelectAll={jest.fn()} /> </TestProviders> @@ -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( <TestProviders> <RulesTableUtilityBar canBulkEdit - onRefresh={jest.fn()} - pagination={{ - page: 1, - perPage: 10, - total: 21, - }} - numberSelectedItems={1} onGetBulkItemsPopoverContent={jest.fn()} - isAutoRefreshOn={true} - onRefreshSwitch={mockSwitch} onToggleSelectAll={jest.fn()} /> </TestProviders> @@ -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<RulesTableUtilityBarProps>( - ({ - 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<RulesTableUtilityBarProps>( 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<RulesTableUtilityBarProps>( <EuiSwitch key="allRulesAutoRefreshSwitch" label={i18n.REFRESH_RULE_POPOVER_DESCRIPTION} - checked={isAutoRefreshOn ?? false} + checked={isRefreshOn ?? false} onChange={handleAutoRefreshSwitch(closePopover)} compressed disabled={isAnyRuleSelected} @@ -122,7 +118,7 @@ export const RulesTableUtilityBar = React.memo<RulesTableUtilityBarProps>( ]} /> ), - [isAutoRefreshOn, handleAutoRefreshSwitch, isAnyRuleSelected] + [isRefreshOn, handleAutoRefreshSwitch, isAnyRuleSelected] ); return ( @@ -136,7 +132,7 @@ export const RulesTableUtilityBar = React.memo<RulesTableUtilityBarProps>( <> <UtilityBarGroup data-test-subj="tableBulkActions"> <UtilityBarText dataTestSubj="selectedRules"> - {i18n.SELECTED_RULES(numberSelectedItems)} + {i18n.SELECTED_RULES(selectedRulesCount)} </UtilityBarText> {canBulkEdit && ( @@ -170,7 +166,7 @@ export const RulesTableUtilityBar = React.memo<RulesTableUtilityBarProps>( dataTestSubj="refreshRulesAction" iconSide="left" iconType="refresh" - onClick={onRefresh} + onClick={handleRefreshRules} > {i18n.REFRESH} </UtilityBarAction> 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 = ( + <EuiEmptyPrompt title={<h3>{i18n.NO_RULES}</h3>} 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<RulesTableProps>(({ selectedTab }) => { + const [{ canUserCRUD }] = useUserData(); + const hasPermissions = hasUserCRUDPermission(canUserCRUD); + + const tableRef = useRef<EuiBasicTable>(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 && ( + <EuiProgress + data-test-subj="loadingRulesInfoProgress" + size="xs" + position="absolute" + color="accent" + /> + )} + {shouldShowLoadingOverlay && ( + <Loader data-test-subj="loadingPanelAllRulesTable" overlay size="xl" /> + )} + {shouldShowRulesTable && <RulesTableFilters />} + {isTableEmpty && <PrePackagedRulesPrompt />} + {isLoading && ( + <EuiLoadingContent data-test-subj="initialLoadingPanelAllRulesTable" lines={10} /> + )} + {isDeleteConfirmationVisible && ( + <EuiConfirmModal + title={i18n.DELETE_CONFIRMATION_TITLE} + onCancel={handleDeletionCancel} + onConfirm={handleDeletionConfirm} + confirmButtonText={i18n.DELETE_CONFIRMATION_CONFIRM} + cancelButtonText={i18n.DELETE_CONFIRMATION_CANCEL} + buttonColor="danger" + defaultFocusedButton="confirm" + data-test-subj="allRulesDeleteConfirmationModal" + > + <p>{i18n.DELETE_CONFIRMATION_BODY}</p> + </EuiConfirmModal> + )} + {isBulkActionConfirmationVisible && bulkAction && ( + <BulkActionDryRunConfirmation + bulkAction={bulkAction} + result={bulkActionsDryRunResult} + onCancel={cancelBulkActionConfirmation} + onConfirm={approveBulkActionConfirmation} + /> + )} + {isBulkEditFlyoutVisible && bulkEditActionType !== undefined && ( + <BulkEditFlyout + rulesCount={bulkActionsDryRunResult?.succeededRulesCount ?? 0} + editAction={bulkEditActionType} + onClose={handleBulkEditFormCancel} + onConfirm={handleBulkEditFormConfirm} + /> + )} + {shouldShowRulesTable && ( + <> + <RulesTableUtilityBar + canBulkEdit={hasPermissions} + onGetBulkItemsPopoverContent={getBulkItemsPopoverContent} + onToggleSelectAll={toggleSelectAll} + isBulkActionInProgress={isBulkActionsDryRunLoading || loadingRulesAction != null} + /> + <EuiBasicTable + itemId="id" + items={rules} + isSelectable={hasPermissions} + noItemsMessage={NO_ITEMS_MESSAGE} + onChange={tableOnChangeCallback} + pagination={paginationMemo} + ref={tableRef} + selection={hasPermissions ? euiBasicTableSelectionProps : undefined} + sorting={{ + sort: { + // EuiBasicTable has incorrect `sort.field` types which accept only `keyof Item` and reject fields in dot notation + field: sortingOptions.field as keyof Rule, + direction: sortingOptions.order, + }, + }} + {...tableProps} + /> + </> + )} + </> + ); +}); + +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 76% 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..d0e6c0198ad70 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<Rule> | EuiTableActionsColumnType<Rule>; 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,15 +67,20 @@ const useEnabledColumn = ({ hasPermissions }: ColumnsProps): TableColumn => { render: (_, rule: Rule) => ( <EuiToolTip position="top" - content={getToolTipContent(rule, hasMlPermissions, hasActionsPrivileges)} + content={explainLackOfPermission( + rule, + hasMlPermissions, + hasActionsPrivileges, + hasCRUDPermissions + )} > <RuleSwitch id={rule.id} enabled={rule.enabled} isDisabled={ !canEditRuleWithActions(rule, hasActionsPrivileges) || - !hasPermissions || - (isMlRule(rule.type) && !hasMlPermissions && !rule.enabled) + !hasCRUDPermissions || + (isMlRule(rule.type) && !hasMlPermissions) } isLoading={loadingIds.includes(rule.id)} /> @@ -85,7 +89,7 @@ const useEnabledColumn = ({ hasPermissions }: ColumnsProps): TableColumn => { width: '95px', sortable: true, }), - [hasActionsPrivileges, hasMlPermissions, hasPermissions, loadingIds] + [hasActionsPrivileges, hasMlPermissions, hasCRUDPermissions, loadingIds] ); }; @@ -162,42 +166,14 @@ const INTEGRATIONS_COLUMN: TableColumn = { }; const useActionsColumn = (): EuiTableActionsColumnType<Rule> => { - 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$<boolean>(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$<boolean>(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<DefaultItemAction<Rule>> => { + 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 ? ( + <EuiToolTip position="left" content={i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES}> + <>{i18n.EDIT_RULE_SETTINGS}</> + </EuiToolTip> + ) : ( + 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 ? ( + <EuiToolTip position="left" content={i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES}> + <>{i18n.DUPLICATE_RULE}</> + </EuiToolTip> + ) : ( + 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 ( + <> + <NeedAdminForUpdateRulesCallOut /> + <MissingPrivilegesCallOut /> + <MlJobCompatibilityCallout /> + <ValueListsFlyout showFlyout={isValueListFlyoutVisible} onClose={hideValueListFlyout} /> + <ImportDataModal + checkBoxLabel={i18n.OVERWRITE_WITH_SAME_NAME} + closeModal={hideImportModal} + description={i18n.SELECT_RULE} + errorMessage={i18n.IMPORT_FAILED} + failedDetailed={i18n.IMPORT_FAILED_DETAILED} + importComplete={invalidateFindRulesQuery} + importData={importRules} + successMessage={i18n.SUCCESSFULLY_IMPORTED_RULES} + showModal={isImportModalVisible} + submitBtnText={i18n.IMPORT_RULE_BTN_TITLE} + subtitle={i18n.INITIAL_PROMPT_TEXT} + title={i18n.IMPORT_RULE} + showExceptionsCheckBox + showCheckBox + /> + + <RulesTableContextProvider> + <SecuritySolutionPageWrapper> + <HeaderPage title={i18n.PAGE_TITLE}> + <EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}> + <EuiFlexItem grow={false}> + <LoadPrePackagedRules> + {(renderProps) => <LoadPrePackagedRulesButton {...renderProps} />} + </LoadPrePackagedRules> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiToolTip position="top" content={i18n.UPLOAD_VALUE_LISTS_TOOLTIP}> + <EuiButton + data-test-subj="open-value-lists-modal-button" + iconType="importAction" + isDisabled={!canWriteListsIndex || !canUserCRUD || loading} + onClick={showValueListFlyout} + > + {i18n.IMPORT_VALUE_LISTS} + </EuiButton> + </EuiToolTip> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiButton + data-test-subj="rules-import-modal-button" + iconType="importAction" + isDisabled={!hasUserCRUDPermission(canUserCRUD) || loading} + onClick={showImportModal} + > + {i18n.IMPORT_RULE} + </EuiButton> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <SecuritySolutionLinkButton + data-test-subj="create-new-rule" + fill + iconType="plusInCircle" + isDisabled={!hasUserCRUDPermission(canUserCRUD) || loading} + deepLinkId={SecurityPageName.rulesCreate} + > + {i18n.ADD_NEW_RULE} + </SecuritySolutionLinkButton> + </EuiFlexItem> + </EuiFlexGroup> + </HeaderPage> + {(prePackagedRuleStatus === 'ruleNeedUpdate' || + prePackagedTimelineStatus === 'timelineNeedUpdate') && ( + <UpdatePrePackagedRulesCallOut data-test-subj="update-callout-button" /> + )} + <AllRules data-test-subj="all-rules" /> + </SecuritySolutionPageWrapper> + </RulesTableContextProvider> + + <SpyRoute pageName={SecurityPageName.rules} /> + </> + ); +}; + +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<AlertsTableComponentProps> = ({ 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 03141dfb02f57..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 @@ -42,7 +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 '../../../containers/detection_engine/rules/types'; +import type { Rule } from '../../../../detection_engine/rule_management/logic/types'; interface AlertContextMenuProps { ariaLabel?: string; 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<MlJobSelectProps> = ({ 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<PrePackagedRulesPromptProps> = ({ - 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 ( <EmptyPrompt @@ -88,23 +33,26 @@ const PrePackagedRulesPromptComponent: React.FC<PrePackagedRulesPromptProps> = ( body={<p>{i18n.PRE_BUILT_MSG}</p>} actions={ <EuiFlexGroup justifyContent="center"> - <EuiFlexItem grow={false}>{loadPrebuiltRulesAndTemplatesButton}</EuiFlexItem> + <EuiFlexItem grow={false}> + <LoadPrePackagedRules> + {(renderProps) => ( + <LoadPrePackagedRulesButton + fill + data-test-subj="load-prebuilt-rules" + {...renderProps} + /> + )} + </LoadPrePackagedRules> + </EuiFlexItem> <EuiFlexItem grow={false}> <SecuritySolutionLinkButton - isDisabled={!userHasPermissions} + isDisabled={!hasPermissions} iconType="plusInCircle" deepLinkId={SecurityPageName.rulesCreate} > {i18n.CREATE_RULE_ACTION} </SecuritySolutionLinkButton> </EuiFlexItem> - {isUpgradeModalVisible && ( - <MlJobUpgradeModal - jobs={legacyJobsInstalled} - onCancel={() => setIsUpgradeModalVisible(false)} - onConfirm={mlJobUpgradeModalConfirm} - /> - )} </EuiFlexGroup> } /> 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<void>; +} + +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 && ( + <MlJobUpgradeModal + jobs={legacyJobsInstalled} + onCancel={() => 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<void>; +} + +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 ( + <EuiButton + fill={fill} + iconType="indexOpen" + isLoading={isLoading} + isDisabled={isDisabled} + onClick={onClick} + data-test-subj={dataTestSubj} + > + {getLoadRulesOrTimelinesButtonTitle(prePackagedAssetsStatus, prePackagedTimelineStatus)} + </EuiButton> + ); + } + + const showUpdateButton = + prePackagedAssetsStatus === 'someRuleUninstall' || + prePackagedTimelineStatus === 'someTimelineUninstall'; + + if (showUpdateButton) { + return ( + <EuiButton + fill={fill} + iconType="plusInCircle" + isLoading={isLoading} + isDisabled={isDisabled} + onClick={onClick} + data-test-subj={dataTestSubj} + > + {getMissingRulesOrTimelinesButtonTitle( + prePackagedRulesStatus?.rules_not_installed ?? 0, + prePackagedRulesStatus?.timelines_not_installed ?? 0 + )} + </EuiButton> + ); + } + + 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( - <UpdatePrePackagedRulesCallOut - loading={false} - numberOfUpdatedRules={0} - numberOfUpdatedTimelines={0} - updateRules={jest.fn()} - /> - ); - - expect(wrapper.find('EuiCallOut')).toHaveLength(1); - }); - it('renders callOutMessage correctly: numberOfUpdatedRules > 0 and numberOfUpdatedTimelines = 0', () => { - const wrapper = shallow( - <UpdatePrePackagedRulesCallOut - loading={false} - numberOfUpdatedRules={1} - numberOfUpdatedTimelines={0} - updateRules={jest.fn()} - /> + (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(<UpdatePrePackagedRulesCallOut />, { 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( - <UpdatePrePackagedRulesCallOut - loading={false} - numberOfUpdatedRules={1} - numberOfUpdatedTimelines={0} - updateRules={jest.fn()} - /> + (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(<UpdatePrePackagedRulesCallOut />, { 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( - <UpdatePrePackagedRulesCallOut - loading={false} - numberOfUpdatedRules={0} - numberOfUpdatedTimelines={1} - updateRules={jest.fn()} - /> + (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(<UpdatePrePackagedRulesCallOut />, { 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( - <UpdatePrePackagedRulesCallOut - loading={false} - numberOfUpdatedRules={0} - numberOfUpdatedTimelines={1} - updateRules={jest.fn()} - /> + (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(<UpdatePrePackagedRulesCallOut />, { 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( - <UpdatePrePackagedRulesCallOut - loading={false} - numberOfUpdatedRules={1} - numberOfUpdatedTimelines={1} - updateRules={jest.fn()} - /> + (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(<UpdatePrePackagedRulesCallOut />, { 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( - <UpdatePrePackagedRulesCallOut - loading={false} - numberOfUpdatedRules={1} - numberOfUpdatedTimelines={1} - updateRules={jest.fn()} - /> + (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(<UpdatePrePackagedRulesCallOut />, { 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<UpdatePrePackagedRulesCallOutProps> = ({ - 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 ( <EuiCallOut title={i18n.UPDATE_PREPACKAGED_RULES_TITLE} data-test-subj="update-callout"> @@ -60,14 +51,13 @@ const UpdatePrePackagedRulesCallOutComponent: React.FC<UpdatePrePackagedRulesCal {i18n.RELEASE_NOTES_HELP} </EuiLink> </p> - <EuiButton - onClick={updateRules} - size="s" - isLoading={loading} - data-test-subj="update-callout-button" - > - {prepackagedRulesOrTimelines?.buttonTitle} - </EuiButton> + <LoadPrePackagedRules> + {(renderProps) => ( + <EuiButton size="s" data-test-subj="update-callout-button" {...renderProps}> + {prepackagedRulesOrTimelines?.buttonTitle} + </EuiButton> + )} + </LoadPrePackagedRules> </EuiCallOut> ); }; 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`] = ` -<Fragment> - <EuiPopover - anchorPosition="leftCenter" - button={ - <EuiToolTip - content="All actions" - delay="regular" - display="inlineBlock" - position="top" - > - <Styled(EuiButtonIcon) - aria-label="All actions" - data-test-subj="rules-details-popover-button-icon" - iconType="boxesHorizontal" - isDisabled={false} - onClick={[Function]} - /> - </EuiToolTip> - } - closePopover={[Function]} - data-test-subj="rules-details-popover" - display="inline-block" - hasArrow={true} - id="ruleActionsOverflow" - isOpen={false} - ownFocus={true} - panelPaddingSize="none" - repositionOnScroll={true} - > - <EuiContextMenuPanel - data-test-subj="rules-details-menu-panel" - items={ - Array [ - <EuiContextMenuItem - data-test-subj="rules-details-duplicate-rule" - disabled={false} - icon="copy" - onClick={[Function]} - > - <EuiToolTip - delay="regular" - display="inlineBlock" - position="left" - > - <React.Fragment> - Duplicate rule - </React.Fragment> - </EuiToolTip> - </EuiContextMenuItem>, - <EuiContextMenuItem - data-test-subj="rules-details-export-rule" - disabled={false} - icon="exportAction" - onClick={[Function]} - > - Export rule - </EuiContextMenuItem>, - <EuiContextMenuItem - data-test-subj="rules-details-delete-rule" - disabled={false} - icon="trash" - onClick={[Function]} - > - Delete rule - </EuiContextMenuItem>, - ] - } - /> - </EuiPopover> -</Fragment> -`; 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( - <RuleActionsOverflow - rule={mockRule('id')} - userHasPermissions - canDuplicateRuleWithActions={true} - /> - ); - 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions canDuplicateRuleWithActions={true} - /> + />, + { 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( - <RuleActionsOverflow rule={null} userHasPermissions canDuplicateRuleWithActions={true} /> + test('menu is empty when no rule is passed to the component', () => { + const { getByTestId } = render( + <RuleActionsOverflow rule={null} userHasPermissions canDuplicateRuleWithActions={true} />, + { 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( - <RuleActionsOverflow rule={null} userHasPermissions canDuplicateRuleWithActions={true} /> - ); - 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( - <RuleActionsOverflow - rule={mockRule('id')} - userHasPermissions - canDuplicateRuleWithActions={true} - /> - ); - 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions={false} canDuplicateRuleWithActions={true} - /> + />, + { 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( - <RuleActionsOverflow - rule={rule} - userHasPermissions={false} - canDuplicateRuleWithActions={true} - /> - ); - 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( - <RuleActionsOverflow - rule={mockRule('id')} - userHasPermissions - canDuplicateRuleWithActions={true} - /> - ); - 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions canDuplicateRuleWithActions={true} - /> + />, + { 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions canDuplicateRuleWithActions={true} - /> + />, + { 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( - <RuleActionsOverflow rule={rule} userHasPermissions canDuplicateRuleWithActions={true} /> + const executeBulkAction = jest.fn(); + useExecuteBulkActionMock.mockReturnValue({ executeBulkAction }); + + const { getByTestId } = render( + <RuleActionsOverflow + rule={mockRule('id')} + userHasPermissions + canDuplicateRuleWithActions={true} + />, + { 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( - <RuleActionsOverflow rule={rule} userHasPermissions canDuplicateRuleWithActions={true} /> - ); - 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions canDuplicateRuleWithActions={true} - /> + />, + { 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( - <RuleActionsOverflow - rule={rule} - userHasPermissions={false} - canDuplicateRuleWithActions={true} - /> - ); - 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions canDuplicateRuleWithActions={true} - /> + />, + { 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( - <RuleActionsOverflow rule={rule} userHasPermissions canDuplicateRuleWithActions={true} /> - ); - 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( - <RuleActionsOverflow - rule={rule} - userHasPermissions={false} - canDuplicateRuleWithActions={true} - /> - ); - 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions canDuplicateRuleWithActions={true} - /> + />, + { 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( <RuleActionsOverflow rule={mockRule('id')} userHasPermissions canDuplicateRuleWithActions={true} - /> - ); - 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( - <RuleActionsOverflow rule={rule} userHasPermissions canDuplicateRuleWithActions={true} /> + const { getByTestId } = render( + <RuleActionsOverflow rule={rule} userHasPermissions canDuplicateRuleWithActions={true} />, + { 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 = ({ > <EuiToolTip position="left" - content={getToolTipContent(rule, true, canDuplicateRuleWithActions)} + content={ + !canEditRuleWithActions(rule, canDuplicateRuleWithActions) + ? i18nActions.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined + } > <>{i18nActions.DUPLICATE_RULE}</> </EuiToolTip> @@ -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<CreateRulesSchema | null>(null); + const [rule, setRule] = useState<RuleCreateProps | null>(null); const [response, setResponse] = useState<PreviewResponse>(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/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 2b280786e2905..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 @@ -13,14 +13,17 @@ 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, + index: IndexPatternArray, lists: ExceptionListItemSchema[], excludeExceptions: boolean = true ): Promise<ESBoolQuery> => { 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<unknown, ReturnCreateRule>(() => 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<void, ReturnCreateRule>( - () => 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<void, ReturnCreateRule>( - () => 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<CreateRulesSchema | null>]; - -export const useCreateRule = (): ReturnCreateRule => { - const [rule, setRule] = useState<CreateRulesSchema | null>(null); - const [ruleId, setRuleId] = useState<string | null>(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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<unknown, ReturnPrePackagedRulesAndTimelines>( - () => - 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<PrePackagedRulesStatusResponse>; - -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' ? ( - <EuiButton - fill={fill} - iconType="indexOpen" - isLoading={loadingCreatePrePackagedRules} - isDisabled={isDisabled} - onClick={onClick} - data-test-subj={dataTestSubj} - > - {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} - </EuiButton> - ) : 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' ? ( - <EuiButton - fill={fill} - iconType="plusInCircle" - isLoading={loadingCreatePrePackagedRules} - isDisabled={isDisabled} - onClick={onClick} - data-test-subj="reloadPrebuiltRulesBtn" - > - {getMissingRulesOrTimelinesButtonTitle( - prePackagedRulesStatus?.rulesNotInstalled ?? 0, - prePackagedRulesStatus?.timelinesNotInstalled ?? 0 - )} - </EuiButton> - ) : 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<PrePackagedRulesStatusResponse>( - [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<string, ReturnRule>(() => - useRule('myOwnRuleID') - ); - await waitForNextUpdate(); - expect(result.current).toEqual([true, null]); - }); - }); - - test('fetch rule', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnRule>(() => - 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<string, ReturnRule>((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<Rule | null>(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<Rule>) => - 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<void, ReturnTags>(() => useTags()); - await waitForNextUpdate(); - expect(result.current).toEqual([true, [], result.current[2]]); - }); - }); - - test('fetch tags', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<void, ReturnTags>(() => 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<string[]>([]); - 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<unknown, ReturnUpdateRule>(() => 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<void, ReturnUpdateRule>( - () => 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<void, ReturnUpdateRule>( - () => 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<UpdateRulesSchema | null>]; - -export const useUpdateRule = (): ReturnUpdateRule => { - const [rule, setRule] = useState<UpdateRulesSchema | null>(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<void> -) => { - 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<BulkAction, BulkAction.export>; -} -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<Blob | null>; -export async function executeRulesBulkAction( - args: RulesBulkActionArgs -): Promise<BulkActionResponse | null>; -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<typeof useKibana>; - -describe('AllRules', () => { - beforeEach(() => { - useKibanaMock().services.application.capabilities = { - navLinks: {}, - management: {}, - catalogue: {}, - actions: { show: true }, - }; - }); - - afterEach(() => { - jest.clearAllTimers(); - jest.clearAllMocks(); - }); - - it('renders correctly', () => { - const wrapper = shallow( - <AllRules - createPrePackagedRules={jest.fn()} - hasPermissions - loadingCreatePrePackagedRules={false} - rulesCustomInstalled={0} - rulesInstalled={0} - rulesNotInstalled={0} - rulesNotUpdated={0} - /> - ); - - expect(wrapper.find('RulesTables')).toHaveLength(1); - }); - - describe('tabs', () => { - it('renders all rules tab by default', async () => { - const wrapper = mount( - <TestProviders> - <AllRules - createPrePackagedRules={jest.fn()} - hasPermissions - loadingCreatePrePackagedRules={false} - rulesCustomInstalled={1} - rulesInstalled={0} - rulesNotInstalled={0} - rulesNotUpdated={0} - /> - </TestProviders> - ); - - 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( - <TestProviders> - <AllRules - createPrePackagedRules={jest.fn()} - hasPermissions - loadingCreatePrePackagedRules={false} - rulesCustomInstalled={1} - rulesInstalled={0} - rulesNotInstalled={0} - rulesNotUpdated={0} - /> - </TestProviders> - ); - - 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<AllRulesProps>( - ({ - createPrePackagedRules, - hasPermissions, - loadingCreatePrePackagedRules, - rulesCustomInstalled, - rulesInstalled, - rulesNotInstalled, - rulesNotUpdated, - }) => { - const [activeTab, setActiveTab] = useState(AllRulesTabs.rules); - - return ( - <> - <RulesTableToolbar activeTab={activeTab} onTabChange={setActiveTab} /> - <EuiSpacer /> - <RulesTables - createPrePackagedRules={createPrePackagedRules} - hasPermissions={hasPermissions} - loadingCreatePrePackagedRules={loadingCreatePrePackagedRules} - rulesCustomInstalled={rulesCustomInstalled} - rulesInstalled={rulesInstalled} - rulesNotInstalled={rulesNotInstalled} - rulesNotUpdated={rulesNotUpdated} - selectedTab={activeTab} - /> - </> - ); - } -); - -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<void>; - -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<typeof useStartTransaction>['startTransaction']; -}): Array<DefaultItemAction<Rule>> => [ - { - type: 'icon', - 'data-test-subj': 'editRuleAction', - description: i18n.EDIT_RULE_SETTINGS, - name: !actionsPrivileges ? ( - <EuiToolTip position="left" content={i18n.EDIT_RULE_SETTINGS_TOOLTIP}> - <>{i18n.EDIT_RULE_SETTINGS}</> - </EuiToolTip> - ) : ( - 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 ? ( - <EuiToolTip position="left" content={i18n.EDIT_RULE_SETTINGS_TOOLTIP}> - <>{i18n.DUPLICATE_RULE}</> - </EuiToolTip> - ) : ( - 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(<RulesTableFilters allTags={[]} />, { 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( - <RulesTableFilters rulesCustomInstalled={10} rulesInstalled={9} allTags={[]} />, - { 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 = ( - <EuiEmptyPrompt title={<h3>{i18n.NO_RULES}</h3>} 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<RulesTableProps>( - ({ - createPrePackagedRules, - hasPermissions, - loadingCreatePrePackagedRules, - rulesCustomInstalled, - rulesInstalled, - rulesNotInstalled, - rulesNotUpdated, - selectedTab, - }) => { - const { startTransaction } = useStartTransaction(); - const tableRef = useRef<EuiBasicTable>(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 && ( - <EuiProgress - data-test-subj="loadingRulesInfoProgress" - size="xs" - position="absolute" - color="accent" - /> - )} - {shouldShowLoadingOverlay && ( - <Loader data-test-subj="loadingPanelAllRulesTable" overlay size="xl" /> - )} - {shouldShowRulesTable && ( - <RulesTableFilters - rulesCustomInstalled={rulesCustomInstalled} - rulesInstalled={rulesInstalled} - allTags={allTags} - /> - )} - {shouldShowPrepackagedRulesPrompt && ( - <PrePackagedRulesPrompt - createPrePackagedRules={handleCreatePrePackagedRules} - loading={loadingCreatePrePackagedRules} - userHasPermissions={hasPermissions} - /> - )} - {isLoading && ( - <EuiLoadingContent data-test-subj="initialLoadingPanelAllRulesTable" lines={10} /> - )} - {isDeleteConfirmationVisible && ( - <EuiConfirmModal - title={i18n.DELETE_CONFIRMATION_TITLE} - onCancel={handleDeletionCancel} - onConfirm={handleDeletionConfirm} - confirmButtonText={i18n.DELETE_CONFIRMATION_CONFIRM} - cancelButtonText={i18n.DELETE_CONFIRMATION_CANCEL} - buttonColor="danger" - defaultFocusedButton="confirm" - data-test-subj="allRulesDeleteConfirmationModal" - > - <p>{i18n.DELETE_CONFIRMATION_BODY}</p> - </EuiConfirmModal> - )} - {isBulkActionConfirmationVisible && bulkAction && ( - <BulkActionDryRunConfirmation - bulkAction={bulkAction} - result={bulkActionsDryRunResult} - onCancel={cancelBulkActionConfirmation} - onConfirm={approveBulkActionConfirmation} - /> - )} - {isBulkEditFlyoutVisible && bulkEditActionType !== undefined && ( - <BulkEditFlyout - rulesCount={bulkActionsDryRunResult?.succeededRulesCount ?? 0} - editAction={bulkEditActionType} - onClose={handleBulkEditFormCancel} - onConfirm={handleBulkEditFormConfirm} - tags={allTags} - /> - )} - {shouldShowRulesTable && ( - <> - <RulesTableUtilityBar - canBulkEdit={hasPermissions} - pagination={pagination} - numberSelectedItems={selectedItemsCount} - onGetBulkItemsPopoverContent={getBulkItemsPopoverContent} - onRefresh={handleRefreshRules} - isAutoRefreshOn={isRefreshOn} - onRefreshSwitch={handleAutoRefreshSwitch} - isAllSelected={isAllSelected} - onToggleSelectAll={toggleSelectAll} - isBulkActionInProgress={isBulkActionsDryRunLoading || loadingRulesAction != null} - hasDisabledActions={loadingRulesAction != null} - /> - <EuiBasicTable - itemId="id" - items={rules} - isSelectable={hasPermissions} - noItemsMessage={NO_ITEMS_MESSAGE} - onChange={tableOnChangeCallback} - pagination={paginationMemo} - ref={tableRef} - selection={hasPermissions ? euiBasicTableSelectionProps : undefined} - sorting={{ - sort: { - // EuiBasicTable has incorrect `sort.field` types which accept only `keyof Item` and reject fields in dot notation - field: sortingOptions.field as keyof Rule, - direction: sortingOptions.order, - }, - }} - {...tableProps} - /> - </> - )} - </> - ); - } -); - -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 ( + <EuiToolTip position="top" content={disabledReason}> + <SecuritySolutionLinkButton + data-test-subj="editRuleSettingsLink" + onClick={goToEditRule} + iconType="controlsHorizontal" + isDisabled={disabled} + deepLinkId={SecurityPageName.rules} + path={getEditRuleUrl(ruleId)} + > + {ruleI18n.EDIT_RULE_SETTINGS} + </SecuritySolutionLinkButton> + </EuiToolTip> + ); +} 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<ReturnType<typeof useAppToastsMock.create>>; - - 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(<EditRulePage />, { 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 ( - <> - <NeedAdminForUpdateRulesCallOut /> - <MissingPrivilegesCallOut /> - <MlJobCompatibilityCallout /> - {isUpgradeModalVisible && ( - <MlJobUpgradeModal - jobs={legacyJobsInstalled} - onCancel={() => setIsUpgradeModalVisible(false)} - onConfirm={mlJobUpgradeModalConfirm} - /> - )} - <ValueListsFlyout showFlyout={isValueListFlyoutVisible} onClose={hideValueListFlyout} /> - <ImportDataModal - checkBoxLabel={i18n.OVERWRITE_WITH_SAME_NAME} - closeModal={hideImportModal} - description={i18n.SELECT_RULE} - errorMessage={i18n.IMPORT_FAILED} - failedDetailed={i18n.IMPORT_FAILED_DETAILED} - importComplete={invalidateRules} - importData={importRules} - successMessage={i18n.SUCCESSFULLY_IMPORTED_RULES} - showModal={isImportModalVisible} - submitBtnText={i18n.IMPORT_RULE_BTN_TITLE} - subtitle={i18n.INITIAL_PROMPT_TEXT} - title={i18n.IMPORT_RULE} - showExceptionsCheckBox - showCheckBox - /> - - <RulesTableContextProvider> - <SecuritySolutionPageWrapper> - <HeaderPage title={i18n.PAGE_TITLE}> - <EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}> - {loadPrebuiltRulesAndTemplatesButton && ( - <EuiFlexItem grow={false}>{loadPrebuiltRulesAndTemplatesButton}</EuiFlexItem> - )} - {reloadPrebuiltRulesAndTemplatesButton && ( - <EuiFlexItem grow={false}>{reloadPrebuiltRulesAndTemplatesButton}</EuiFlexItem> - )} - <EuiFlexItem grow={false}> - <EuiToolTip position="top" content={i18n.UPLOAD_VALUE_LISTS_TOOLTIP}> - <EuiButton - data-test-subj="open-value-lists-modal-button" - iconType="importAction" - isDisabled={!canWriteListsIndex || !canUserCRUD || loading} - onClick={showValueListFlyout} - > - {i18n.IMPORT_VALUE_LISTS} - </EuiButton> - </EuiToolTip> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiButton - data-test-subj="rules-import-modal-button" - iconType="importAction" - isDisabled={!userHasPermissions(canUserCRUD) || loading} - onClick={showImportModal} - > - {i18n.IMPORT_RULE} - </EuiButton> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <SecuritySolutionLinkButton - data-test-subj="create-new-rule" - fill - iconType="plusInCircle" - isDisabled={!userHasPermissions(canUserCRUD) || loading} - deepLinkId={SecurityPageName.rulesCreate} - > - {i18n.ADD_NEW_RULE} - </SecuritySolutionLinkButton> - </EuiFlexItem> - </EuiFlexGroup> - </HeaderPage> - {(prePackagedRuleStatus === 'ruleNeedUpdate' || - prePackagedTimelineStatus === 'timelineNeedUpdate') && ( - <UpdatePrePackagedRulesCallOut - data-test-subj="update-callout-button" - loading={loadingCreatePrePackagedRules} - numberOfUpdatedRules={rulesNotUpdated ?? 0} - numberOfUpdatedTimelines={timelinesNotUpdated ?? 0} - updateRules={showMlJobUpgradeModal} - /> - )} - <AllRules - createPrePackagedRules={createPrePackagedRules} - data-test-subj="all-rules" - loadingCreatePrePackagedRules={loadingCreatePrePackagedRules} - hasPermissions={userHasPermissions(canUserCRUD)} - rulesCustomInstalled={rulesCustomInstalled} - rulesInstalled={rulesInstalled} - rulesNotInstalled={rulesNotInstalled} - rulesNotUpdated={rulesNotUpdated} - /> - </SecuritySolutionPageWrapper> - </RulesTableContextProvider> - - <SpyRoute pageName={SecurityPageName.rules} /> - </> - ); -}; - -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<string, Partial<HostDetailsTabsProps>> = { - 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<HostDetailsTabsProps>( filterQuery, indexNames, indexPattern, - pageFilters = [], hostDetailsPagePath, + hostDetailsFilter, }) => { const { from, to, isInitializing, deleteQuery, setQuery } = useGlobalTime(); @@ -52,11 +51,6 @@ export const HostDetailsTabs = React.memo<HostDetailsTabsProps>( hostName: detailName, }; - const externalAlertPageFilters = useMemo( - () => [...hostNameExistsFilter, ...pageFilters], - [pageFilters] - ); - return ( <Switch> <Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.authentications})`}> @@ -71,10 +65,9 @@ export const HostDetailsTabs = React.memo<HostDetailsTabsProps>( <Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.events})`}> <EventsQueryTabBody - {...tabProps} - pageFilters={pageFilters} + additionalFilters={hostDetailsFilter} tableId={TableId.hostsPageEvents} - externalAlertPageFilters={externalAlertPageFilters} + {...tabProps} /> </Route> <Route path={`${hostDetailsPagePath}/:tabName(${HostsTableType.risk})`}> 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<HostDetailsProps> = ({ 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<HostDetailsProps> = ({ 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<HostDetailsProps> = ({ 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<KeyHostDetailsNavTab, NavTab>; 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<UpdateDateRange>( ({ 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 = () => { /> <HostsKpiComponent - filterQuery={filterQuery} + filterQuery={globalFilterQuery} indexNames={selectedPatterns} from={from} setQuery={setQuery} to={to} - skip={isInitializing || !filterQuery} + skip={isInitializing || !!kqlError} updateDateRange={updateDateRange} /> @@ -218,13 +227,12 @@ const HostsComponent = () => { <HostsTabs deleteQuery={deleteQuery} to={to} - filterQuery={tabsFilterQuery || ''} + filterQuery={tabsFilterQuery} isInitializing={isInitializing} indexNames={selectedPatterns} setQuery={setQuery} from={from} type={hostsModel.HostsType.page} - pageFilters={tabsFilters} /> </SecuritySolutionPageWrapper> </StyledFullHeightContainer> 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<HostsTabsProps>( - ({ - deleteQuery, - filterQuery, - pageFilters = [], - from, - indexNames, - isInitializing, - setQuery, - to, - type, - }) => { +export const HostsTabs = React.memo<HostsTabsProps>( + ({ deleteQuery, filterQuery, from, indexNames, isInitializing, setQuery, to, type }) => { const tabProps = { deleteQuery, endDate: to, @@ -48,10 +38,6 @@ export const HostsTabs = memo<HostsTabsProps>( type, }; - const externalAlertPageFilters = useMemo( - () => [...hostNameExistsFilter, ...pageFilters], - [pageFilters] - ); return ( <Switch> <Route path={`${HOSTS_PATH}/:tabName(${HostsTableType.hosts})`}> @@ -68,10 +54,9 @@ export const HostsTabs = memo<HostsTabsProps>( </Route> <Route path={`${HOSTS_PATH}/:tabName(${HostsTableType.events})`}> <EventsQueryTabBody - {...tabProps} - pageFilters={pageFilters} + additionalFilters={hostNameExistsFilter} tableId={TableId.hostsPageEvents} - externalAlertPageFilters={externalAlertPageFilters} + {...tabProps} /> </Route> <Route path={`${HOSTS_PATH}/:tabName(${HostsTableType.sessions})`}> 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<ResponseActionGetFileRequestBody>({ + const { result, actionDetails } = useConsoleActionSubmitter<ResponseActionGetFileRequestBody>({ 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 ( + <ResultComponent + showAs="success" + data-test-subj="getFileSuccess" + title={i18n.translate( + 'xpack.securitySolution.endpointResponseActions.getFileAction.successTitle', + { defaultMessage: 'File retrieved from the host.' } + )} + > + <ResponseActionFileDownloadLink action={actionDetails} /> + </ResultComponent> + ); + } + + 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 <ResultComponent showAs="pending" data-test-subj={getTestId('pending')} />; + return ( + <ResultComponent showAs="pending" data-test-subj={getTestId('pending')}> + {pendingMessage} + </ResultComponent> + ); } const apiError = actionRequestError || actionDetailsError; @@ -246,7 +259,7 @@ export const useConsoleActionSubmitter = < return ( <ResultComponent showAs="failure" data-test-subj={getTestId('apiFailure')}> <FormattedMessage - id="xpack.securitySolution.endpointResponseActions.killProcess.performApiErrorMessage" + id="xpack.securitySolution.endpointResponseActions.actionSubmitter.apiErrorDetails" defaultMessage="The following error was encountered:" /> <FormattedError error={apiError} data-test-subj={getTestId('apiErrorDetails')} /> @@ -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<ReturnType<AppContextTestRender['render']>>; @@ -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<CSSProperties>({ + fontFamily: 'inherit', +}); + +const DEFAULT_BUTTON_TITLE = i18n.translate( + 'xpack.securitySolution.responseActionFileDownloadLink.downloadButtonLabel', + { defaultMessage: 'Click here to download' } +); + +export interface ResponseActionFileDownloadLinkProps { + action: MaybeImmutable<ActionDetails>; + 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<ResponseActionFileDownloadLinkProps>( + ({ action, buttonTitle = DEFAULT_BUTTON_TITLE, 'data-test-subj': dataTestSubj }) => { + const getTestId = useTestIdGenerator(dataTestSubj); + const { canWriteFileOperations } = useUserPrivileges().endpointPrivileges; + + if (!canWriteFileOperations) { + return null; + } + + return ( + <> + <EuiButtonEmpty + href={getHostActionFileDownloadUrl(action)} + iconType="download" + data-test-subj={getTestId('downloadButton')} + flush="left" + style={STYLE_INHERIT_FONT_FAMILY} + download + > + <EuiText size="s">{buttonTitle}</EuiText> + </EuiButtonEmpty> + <EuiText + size="s" + className="eui-displayInline" + data-test-subj={getTestId('passcodeMessage')} + > + <FormattedMessage + id="xpack.securitySolution.responseActionFileDownloadLink.passcodeInfo" + defaultMessage="(ZIP file passcode: {passcode})" + values={{ + passcode: 'elastic', + }} + /> + </EuiText> + </> + ); + } +); +ResponseActionFileDownloadLink.displayName = 'ResponseActionFileDownloadLink'; 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<ActionDetails>, + 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<NetworkDetailTabsProps>( - ({ 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 ( <Switch> <Route @@ -116,9 +111,9 @@ export const NetworkDetailsTabs = React.memo<NetworkDetailTabsProps>( path={`${NETWORK_DETAILS_PAGE_PATH}/:flowTarget/:tabName(${NetworkDetailsRouteType.events})`} > <EventsQueryTabBody - pageFilters={networkDetailsPageFilters} - tableId={TableId.networkPageEvents} + additionalFilters={networkDetailsFilter} {...commonProps} + tableId={TableId.networkPageEvents} /> </Route> </Switch> 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} /> </SecuritySolutionPageWrapper> </> 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<NetworkRoutesProps>( </Route> <Route path={`${NETWORK_PATH}/:tabName(${NetworkRouteType.events})`}> <EventsQueryTabBody - pageFilters={filterNetworkExternalAlertData} + additionalFilters={sourceOrDestinationIpExistsFilter} tableId={TableId.networkPageEvents} {...tabProps} /> 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<NetworkComponentProps>( ); 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<NetworkComponentProps>( 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<UpdateDateRange>( ({ x }) => { @@ -143,8 +141,9 @@ const NetworkComponent = React.memo<NetworkComponentProps>( 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<NetworkComponentProps>( > <EmbeddedMap query={query} - filters={filters} + filters={globalFilters} startDate={from} endDate={to} setQuery={setQuery} diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/columns.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/columns.tsx index cc727efa5188e..465072743d1d5 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/columns.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/anomalies/columns.tsx @@ -7,22 +7,25 @@ import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import type { EuiBasicTableColumn } from '@elastic/eui'; -import { EuiLink } from '@elastic/eui'; -import { ML_PAGES, useMlHref } from '@kbn/ml-plugin/public'; +import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; import { useDispatch } from 'react-redux'; + import * as i18n from './translations'; import type { AnomaliesCount } from '../../../../common/components/ml/anomaly/use_anomalies_search'; -import { - AnomalyJobStatus, - AnomalyEntity, -} from '../../../../common/components/ml/anomaly/use_anomalies_search'; -import { useKibana } from '../../../../common/lib/kibana'; +import { AnomalyEntity } from '../../../../common/components/ml/anomaly/use_anomalies_search'; + import { LinkAnchor, SecuritySolutionLinkAnchor } from '../../../../common/components/links'; import { SecurityPageName } from '../../../../app/types'; import { usersActions } from '../../../../users/store'; import { hostsActions } from '../../../../hosts/store'; import { HostsType } from '../../../../hosts/store/model'; import { UsersType } from '../../../../users/store/model'; +import type { SecurityJob } from '../../../../common/components/ml_popover/types'; +import { + isJobFailed, + isJobStarted, + isJobLoading, +} from '../../../../../common/machine_learning/helpers'; type AnomaliesColumns = Array<EuiBasicTableColumn<AnomaliesCount>>; @@ -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<void> +): 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 <MediumShadeText>{name}</MediumShadeText>; @@ -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 <AnomaliesTabLink count={count} jobId={jobId} entity={entity} />; + render: (count, { entity, job }) => { + if (!job) return ''; + + if (count > 0 || isJobStarted(job.jobState, job.datafeedState)) { + return <AnomaliesTabLink count={count} jobId={job.id} entity={entity} />; + } else if (isJobFailed(job.jobState, job.datafeedState)) { + return i18n.JOB_STATUS_FAILED; + } else if (job.isCompatible) { + return <EnableJob job={job} isLoading={loading} onJobStateChange={onJobStateChange} />; } else { - if (status === AnomalyJobStatus.disabled && jobId) { - return <EnableJobLink jobId={jobId} />; - } - - if (status === AnomalyJobStatus.uninstalled) { - return ( - <EuiLink external target={'_blank'} href={INSTALL_JOBS_DOC}> - {i18n.JOB_STATUS_UNINSTALLED} - </EuiLink> - ); - } - - return <MediumShadeText>{I18N_JOB_STATUS[status]}</MediumShadeText>; + return <EuiIcon aria-label="Warning" size="s" type="alert" color="warning" />; } }, }, ], - [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<void>; +}) => { + const handleChange = useCallback(() => onJobStateChange(job), [job, onJobStateChange]); - return ( - <LinkAnchor data-test-subj="jobs-table-link" href={jobUrl} onClick={onClick}> + return isLoading || isJobLoading(job.jobState, job.datafeedState) ? ( + <EuiLoadingSpinner size="m" data-test-subj="job-switch-loader" /> + ) : ( + <LinkAnchor onClick={handleChange} data-test-subj="enable-job"> {i18n.RUN_JOB} </LinkAnchor> ); 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<number>(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 ( <EuiPanel hasBorder data-test-subj={ENTITY_ANALYTICS_ANOMALIES_PANEL}> <HeaderSection title={i18n.ANOMALIES_TITLE} titleSize="s" - subtitle={<LastUpdatedAt isUpdating={isLoading} updatedAt={updatedAt} />} + subtitle={<LastUpdatedAt isUpdating={isSearchLoading} updatedAt={updatedAt} />} toggleStatus={toggleStatus} toggleQuery={setToggleStatus} > @@ -124,12 +149,13 @@ export const EntityAnalyticsAnomalies = () => { </EuiFlexItem> </EuiFlexGroup> </HeaderSection> + <MLJobsAwaitingNodeWarning jobIds={installedJobsIds} /> {toggleStatus && ( <EuiInMemoryTable responsive={false} items={data} columns={columns} - loading={isLoading} + loading={isSearchLoading} id={TABLE_QUERY_ID} sorting={TABLE_SORTING} /> 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<GlobalTimeArgs, 'from' | 'to' | 'setQuery'> { @@ -57,7 +57,7 @@ const EventCountsComponent: React.FC<Props> = ({ 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/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<UsersDetailsTabsProps>( @@ -32,7 +31,7 @@ export const UsersDetailsTabs = React.memo<UsersDetailsTabsProps>( to, type, detailName, - pageFilters = [], + userDetailFilter, }) => { const tabProps = { deleteQuery, @@ -46,11 +45,6 @@ export const UsersDetailsTabs = React.memo<UsersDetailsTabsProps>( userName: detailName, }; - const externalAlertPageFilters = useMemo( - () => [...userNameExistsFilter, ...pageFilters], - [pageFilters] - ); - return ( <Switch> <Route path={`${usersDetailsPagePath}/:tabName(${UsersTableType.authentications})`}> @@ -61,10 +55,9 @@ export const UsersDetailsTabs = React.memo<UsersDetailsTabsProps>( </Route> <Route path={`${usersDetailsPagePath}/:tabName(${UsersTableType.events})`}> <EventsQueryTabBody - {...tabProps} - pageFilters={pageFilters} + additionalFilters={userDetailFilter} tableId={TableId.usersPageEvents} - externalAlertPageFilters={externalAlertPageFilters} + {...tabProps} /> </Route> <Route path={`${usersDetailsPagePath}/:tabName(${UsersTableType.risk})`}> 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<UsersDetailsProps> = ({ ); 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<UsersDetailsProps> = ({ 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<UsersDetailsProps> = ({ 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<Record<KeyUsersDetailsNavTab, NavTab>>; 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 = () => { /> <UsersKpiComponent - filterQuery={filterQuery} + filterQuery={globalFiltersQuery} indexNames={selectedPatterns} from={from} setQuery={setQuery} to={to} - skip={isInitializing || !filterQuery} + skip={isInitializing || !!kqlError} updateDateRange={updateDateRange} /> @@ -210,14 +217,13 @@ const UsersComponent = () => { <UsersTabs deleteQuery={deleteQuery} - filterQuery={tabsFilterQuery || ''} + filterQuery={tabsFilterQuery} from={from} indexNames={selectedPatterns} isInitializing={isInitializing} setQuery={setQuery} to={to} type={usersModel.UsersType.page} - pageFilters={tabsFilters} /> </SecuritySolutionPageWrapper> </StyledFullHeightContainer> 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<UsersTabsProps>( - ({ - 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<UsersTabsProps>( </Route> <Route path={`${USERS_PATH}/:tabName(${UsersTableType.events})`}> <EventsQueryTabBody - {...tabProps} - pageFilters={pageFilters} + additionalFilters={userNameExistsFilter} tableId={TableId.usersPageEvents} + {...tabProps} /> </Route> </Switch> diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts index 8a1aa4050d07b..8daeae3a28767 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/endpoint_response_actions.ts @@ -8,6 +8,8 @@ import type { KbnClient } from '@kbn/test'; import type { Client } from '@elastic/elasticsearch'; import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; +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'; @@ -182,7 +184,7 @@ export const sendEndpointActionResponse = async ( // Index the file's metadata const fileMeta = await esClient.index<UploadedFile>({ index: FILE_STORAGE_METADATA_INDEX, - id: `${action.id}.${action.hosts[0]}`, + id: getFileDownloadId(action, action.agents[0]), body: { file: { created: new Date().toISOString(), @@ -200,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/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<P = any, Q = any, B = any> { + routerMock: ReturnType<typeof httpServiceMock.createRouter>; + scopedEsClusterClientMock: ReturnType<typeof elasticsearchServiceMock.createScopedClusterClient>; + savedObjectClientMock: ReturnType<typeof savedObjectsClientMock.create>; + endpointAppContextMock: EndpointAppContext; + httpResponseMock: ReturnType<typeof httpServerMock.createResponseFactory>; + httpHandlerContextMock: ReturnType<typeof requestContextMock.convertContext>; + getEsClientMock: (type?: 'internalUser' | 'currentUser') => ElasticsearchClientMock; + createRequestMock: (options?: RequestFixtureOptions<P, Q, B>) => KibanaRequest<P, Q, B>; + /** Retrieves the handler that was registered with the `router` for a given `method` and `path` */ + getRegisteredRouteHandler: ( + method: keyof Pick<IRouter, 'get' | 'put' | 'post' | 'patch' | 'delete'>, + path: string + ) => RequestHandler; +} + +/** + * Returns all of the setup needed to test an HTTP api handler + */ +export const createHttpApiTestSetupMock = <P = any, Q = any, B = any>(): 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<unknown, unknown, unknown, 'get'>, 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<P, Q, B> = {}): KibanaRequest<P, Q, B> => { + return httpServerMock.createKibanaRequest<P, Q, B>(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<EndpointActionFileDownloadParams>['createRequestMock'] + >; + let httpHandlerContextMock: HttpApiTestSetupMock<EndpointActionFileDownloadParams>['httpHandlerContextMock']; + let httpResponseMock: HttpApiTestSetupMock<EndpointActionFileDownloadParams>['httpResponseMock']; + + beforeEach(() => { + apiTestSetup = createHttpApiTestSetupMock<EndpointActionFileDownloadParams>(); + + ({ 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<typeof getActionFileDownloadRouteHandler>; + let esClientMock: ReturnType<HttpApiTestSetupMock['getEsClientMock']>; + 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/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<typeof createFileClientMock>; + + 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<AddPrepackagedRulesSchema[]> => { + getLatestPrebuiltRules: async (): Promise<PrebuiltRuleToInstall[]> => { 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<PrePackagedRulesAndTimelinesSchema | null> => { +): Promise<InstallPrebuiltRulesAndTimelinesResponse | null> => { 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<Map<string, PrebuiltRuleToInstall>> => + 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<PrebuiltRuleToInstall[]> => { + 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<AddPrepackagedRulesSchema[]> => { - 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<Map<string, AddPrepackagedRulesSchema>> => - 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<string, AddPrepackagedRulesSchema>, + latestPrebuiltRules: Map<string, PrebuiltRuleToInstall>, installedRules: Map<string, RuleAlertType> ) => { - 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<string, AddPrepackagedRulesSchema>, + latestPrebuiltRules: Map<string, PrebuiltRuleToInstall>, installedRules: Map<string, RuleAlertType> ) => { - 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<string, RuleAlertType> ): 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<string, RuleAlertType> -): 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<string, any> { + 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<SavedObjectsFindOptions, 'type'> 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<typeof rulesClientMock.create>; let savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>; let ruleExecutionLog: ReturnType<typeof ruleExecutionLogMock.forRoutes.create>; @@ -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<void> => { 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<Promise<PartialRule<RuleParams> | 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<T = RuleAlertType> { 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<typeof queryRuleByIdSchema, QueryRuleByIdSchemaDecoded>( - 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<typeof serverMock.create>; 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 79% 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 8d1dc2cc7c49e..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( 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<typeof serverMock.create>; 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<typeof performBulkActionSchema>(performBulkActionSchema), - query: buildRouteValidation<typeof performBulkActionQuerySchema>( - 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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType<typeof mlServicesMock.createSetupContract>; @@ -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<typeof serverMock.create>; 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<unknown, unknown, QueryRulesBulkSchemaDecoded, 'delete' | 'post'>; +type Config = RouteConfig<unknown, unknown, BulkDeleteRulesRequestBody, 'delete' | 'post'>; 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<typeof queryRulesBulkSchema, QueryRulesBulkSchemaDecoded>( - 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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType<typeof mlServicesMock.createSetupContract>; @@ -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<typeof patchRulesBulkSchema>(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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType<typeof mlServicesMock.createSetupContract>; @@ -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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType<typeof mlServicesMock.createSetupContract>; @@ -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<typeof serverMock.create>; 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<typeof queryRulesSchema, QueryRulesSchemaDecoded>( - 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<typeof exportRulesQuerySchema, ExportRulesQuerySchemaDecoded>( - exportRulesQuerySchema - ), - body: buildRouteValidation<typeof exportRulesSchema, ExportRulesSchemaDecoded>( - exportRulesSchema + query: buildRouteValidation<typeof ExportRulesRequestQuery, ExportRulesRequestQueryDecoded>( + 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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let logger: ReturnType<typeof loggingSystemMock.createLogger>; 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<typeof findRulesSchema, FindRulesSchemaDecoded>( - findRulesSchema + query: buildRouteValidation<typeof FindRulesRequestQuery, FindRulesRequestQueryDecoded>( + 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<typeof createMockConfig>; let server: ReturnType<typeof serverMock.create>; let request: ReturnType<typeof requestMock.create>; 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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType<typeof mlServicesMock.createSetupContract>; @@ -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<typeof patchRulesSchema>(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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let logger: ReturnType<typeof loggingSystemMock.createLogger>; @@ -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<typeof queryRulesSchema, QueryRulesSchemaDecoded>( - 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<typeof serverMock.create>; let { clients, context } = requestContextMock.createTools(); let ml: ReturnType<typeof mlServicesMock.createSetupContract>; @@ -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 = <T>(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<T extends RuleCreateProps = RuleCreateProps> { + 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<typeof rulesClientMock.create>; 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<typeof loggingSystemMock.createLogger>; 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<string, ExceptionListSchema>; }): [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<ImportRulesSchema> => ({ +export const getOutputSample = (): Partial<RuleToImport> => ({ rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -30,7 +31,7 @@ export const getOutputSample = (): Partial<ImportRulesSchema> => ({ type: 'query', }); -export const getSampleAsNdjson = (sample: Partial<ImportRulesSchema>): string => { +export const getSampleAsNdjson = (sample: Partial<RuleToImport>): 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<ImportExceptionsListSchema | ImportExceptionListItemSchema | Error>; - rules: Array<ImportRulesSchema | Error>; + rules: Array<RuleToImport | Error>; }>((items) => ({ exceptions: items.exceptions, rules: validateRules(items.rules), })); }; -export const validateRules = ( - rules: Array<ImportRulesSchema | Error> -): Array<ImportRulesSchema | Error> => { - return rules.map((obj: ImportRulesSchema | Error) => { +export const validateRules = (rules: Array<RuleToImport | Error>): Array<RuleToImport | Error> => { + 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<ImportExceptionsListSchema | ImportExceptionListItemSchema | Error>; - rules: Array<ImportRulesSchema | Error>; + rules: Array<RuleToImport | Error>; }>( (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<ImportRulesSchema | Error>; + rules: Array<RuleToImport | Error>; savedObjectsClient: SavedObjectsClientContract; }): Promise<Record<string, ExceptionListSchema>> => { const [lists] = rules.reduce<ListArray[]>((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<ImportExceptionsListSchema | ImportExceptionListItemSchema>; 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<RuleParams> => +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<RuleParams> => lastExecutionDate: '2022-03-31T21:47:25.695Z', lastDuration: 0, }, - } as unknown as SanitizedRule<RuleParams>); - -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<RuleParams>, - 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<RuleParams>, - 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<RuleParams>, - 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<RuleParams>, - 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<RuleParams>, - 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<RuleParams>, - 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<RuleParams>, - 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<RuleParams>, - 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<FullResponseSchema['actions']>([ - { - 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<FullResponseSchema['actions']>([ - { - 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<FullResponseSchema['actions']>([ - { - 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<FullResponseSchema['actions']>([ - { - 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<RuleParams>; + } 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<RuleParams>; + } as RuleAlertType; expect( getUpdatedActionsParams({ @@ -788,7 +409,7 @@ describe('utils', () => { actions: [], throttle: null, notifyWhen: 'onActiveAlert', - } as SanitizedRule<RuleParams>; + } 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<RuleAlertType | 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<LegacyIRuleActionsAttributes>({ + 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<RuleAlertType, 'id'> => { + const { id, ...restOfRule } = rule; + + const actionReference = references.reduce<Record<string, SavedObjectReference>>( + (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<RuleAction[]>((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<void> => { + 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<RuleResponse['actions']>([ + { + 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<RuleResponse['actions']>([ + { + 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<RuleResponse['actions']>([ + { + 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<RuleResponse['actions']>([ + { + 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<RuleParams> | ResolvedSanitizedRule<RuleParams>, 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<RuleParams> => (obj as ResolvedSanitizedRule<RuleParams>).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<typeof getCreateRulesSchemaMock>) => { 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<string, LegacyRulesActionsSavedObject> -): 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<Partial<FullResponseSchema>>; + data: Array<Partial<RuleResponse>>; } | null => { return { page: ruleFindResults.page, @@ -121,7 +121,7 @@ export const transform = ( rule: PartialRule<RuleParams>, 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<Action | Error> => { +): Promise<RuleAction | Error> => { try { const search = createQuery('action', action.id); - const foundAction = await savedObjectsClient.find<Action>({ + const foundAction = await savedObjectsClient.find<RuleAction>({ type: 'action', search, rootSearchFields: ['_id', 'originId'], @@ -247,7 +235,7 @@ export const migrateLegacyActionsIds = async ( rules: PromiseFromStreams[], savedObjectsClient: SavedObjectsClientContract ): Promise<PromiseFromStreams[]> => { - 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<Action | Error> = await pMap( + const newActions: Array<RuleAction | Error> = 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<Action | Error, Error>( + const [actionMigrationErrors, newlyMigratedActions] = partition<RuleAction | Error, Error>( (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<RuleParams>, 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<RuleParams>, 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<StartPlugins>, + 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<RuleParams>; + +export const isAlertType = ( + partialAlert: PartialRule<RuleParams> +): 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<typeof baseRuleParams>; 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<typeof eqlSpecificRuleParams>; @@ -139,11 +140,11 @@ export type EqlRuleParams = t.TypeOf<typeof eqlRuleParams>; 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<typeof threatSpecificRuleParams>; @@ -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<typeof unifiedQueryRuleParams>; 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<typeof thresholdSpecificRuleParams>; @@ -223,13 +224,13 @@ export type MachineLearningRuleParams = t.TypeOf<typeof machineLearningRuleParam const newTermsSpecificRuleParams = t.type({ type: t.literal('new_terms'), - query, - newTermsFields, - historyWindowStart, - index: indexOrUndefined, - filters: filtersOrUndefined, + query: RuleQuery, + newTermsFields: NewTermsFields, + historyWindowStart: HistoryWindowStart, + index: t.union([IndexPatternArray, t.undefined]), + filters: t.union([RuleFilterArray, t.undefined]), language: nonEqlLanguages, - dataViewId: dataViewIdOrUndefined, + dataViewId: t.union([DataViewId, t.undefined]), }); export const newTermsRuleParams = t.intersection([baseRuleParams, newTermsSpecificRuleParams]); export type NewTermsSpecificRuleParams = t.TypeOf<typeof newTermsSpecificRuleParams>; @@ -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<typeof internalRuleCreate>; 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<typeof internalRuleUpdate>; 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<RuleParams>) => ({ 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<SignalSourceHit>['_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<RuleParams>; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export interface IRuleAssetSOAttributes extends Record<string, any> { - 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<RuleParams> -): partialAlert is RuleAlertType => { - const ruleTypeValues = Object.values(ruleTypeMappings) as unknown as string[]; - return ruleTypeValues.includes(partialAlert.alertTypeId as string); -}; - -export interface CreateRulesOptions<T extends CreateRulesSchema = CreateRulesSchema> { - 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<RuleParams> | 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<RuleParams>, - 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<RuleParams>['muteAll']; - throttle: string | null | undefined; -}): Promise<void> => { - 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<RuleParams>; - ruleThrottle: string | null; - actions: LegacyRuleAlertSavedObjectAction[]; - references: SavedObjectReference[]; -}): Omit<SanitizedRule<RuleParams>, 'id'> => { - const { id, ...restOfRule } = rule; - - const actionReference = references.reduce<Record<string, SavedObjectReference>>( - (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<RuleAction[]>((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<SanitizedRule<RuleParams> | 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<LegacyIRuleActionsAttributes>({ - 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<AlertInstanceState, AlertInstanceContext, 'default'>; - 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<ImportTimelineResultSchema | Error> => { 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<ImportRulesSchema | RulesObjectsExportResultDetails>( + return createFilterStream<RuleToImport | RulesObjectsExportResultDetails>( (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_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<void> { + 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<void> { 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<void> { + 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<void> { 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/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_count.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_count.tsx new file mode 100644 index 0000000000000..3316dbd404e57 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_count.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import React from 'react'; +import { ClientPluginsStart } from '../../../../../plugin'; +import { KpiWrapper } from '../monitor_summary/kpi_wrapper'; +import { useMonitorQueryId } from '../hooks/use_monitor_query_id'; + +export const FailedTestsCount = (time: { to: string; from: string }) => { + const { observability } = useKibana<ClientPluginsStart>().services; + + const { ExploratoryViewEmbeddable } = observability; + + const monitorId = useMonitorQueryId(); + + return ( + <KpiWrapper> + <ExploratoryViewEmbeddable + reportType="single-metric" + attributes={[ + { + time, + reportDefinitions: { + 'monitor.id': [monitorId], + }, + dataType: 'synthetics', + selectedMetricField: 'monitor_failed_tests', + name: 'synthetics-series-1', + }, + ]} + /> + </KpiWrapper> + ); +}; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/monitor_errors.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/monitor_errors.tsx index 246e4ea19b94d..fba0664f0ef07 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/monitor_errors.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/monitor_errors.tsx @@ -14,6 +14,7 @@ import { } from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; +import { FailedTestsCount } from './failed_tests_count'; import { useGetUrlParams } from '../../../hooks'; import { SyntheticsDatePicker } from '../../common/date_picker/synthetics_date_picker'; import { MonitorErrorsCount } from '../monitor_summary/monitor_errors_count'; @@ -34,7 +35,14 @@ export const MonitorErrors = () => { <EuiTitle size="xs"> <h3 css={{ margin: euiTheme.size.s, marginBottom: 0 }}>{OVERVIEW_LABEL}</h3> </EuiTitle> - <MonitorErrorsCount to={dateRangeEnd} from={dateRangeStart} /> + <EuiFlexGroup> + <EuiFlexItem> + <MonitorErrorsCount to={dateRangeEnd} from={dateRangeStart} /> + </EuiFlexItem> + <EuiFlexItem> + <FailedTestsCount to={dateRangeEnd} from={dateRangeStart} /> + </EuiFlexItem> + </EuiFlexGroup> </EuiPanel> </EuiFlexItem> <EuiFlexItem grow={3}> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_errors_count.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_errors_count.tsx index c4809274da190..30a220f3f10b8 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_errors_count.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_errors_count.tsx @@ -8,9 +8,9 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import React from 'react'; import { ReportTypes } from '@kbn/observability-plugin/public'; -import { useParams } from 'react-router-dom'; import { KpiWrapper } from './kpi_wrapper'; import { ClientPluginsStart } from '../../../../../plugin'; +import { useMonitorQueryId } from '../hooks/use_monitor_query_id'; interface MonitorErrorsCountProps { from: string; @@ -22,7 +22,7 @@ export const MonitorErrorsCount = (props: MonitorErrorsCountProps) => { const { ExploratoryViewEmbeddable } = observability; - const { monitorId } = useParams<{ monitorId: string }>(); + const monitorId = useMonitorQueryId(); return ( <KpiWrapper> @@ -34,7 +34,7 @@ export const MonitorErrorsCount = (props: MonitorErrorsCountProps) => { time: props, reportDefinitions: { config_id: [monitorId] }, dataType: 'synthetics', - selectedMetricField: 'state.id', + selectedMetricField: 'monitor_errors', name: 'synthetics-series-1', }, ]} 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/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/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 88e4610c3e74f..0bf0d3908eeb9 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -372,6 +372,7 @@ "controls.controlGroup.management.validate.title": "Valider les sélections utilisateur", "controls.controlGroup.title": "Groupe de contrôle", "controls.controlGroup.toolbarButtonTitle": "Contrôles", + "controls.frame.error.message": "Une erreur s'est produite. En savoir plus", "controls.optionsList.description": "Ajoutez un menu pour la sélection de valeurs de champ.", "controls.optionsList.displayName": "Liste des options", "controls.optionsList.editor.allowMultiselectTitle": "Permettre des sélections multiples dans une liste déroulante", @@ -2331,7 +2332,6 @@ "embeddableApi.errors.paneldoesNotExist": "Panneau introuvable", "embeddableApi.helloworld.displayName": "bonjour", "embeddableApi.panel.dashboardPanelAriaLabel": "Panneau du tableau de bord", - "embeddableApi.panel.errorEmbeddable.message": "Une erreur s'est produite. En savoir plus", "embeddableApi.panel.inspectPanel.displayName": "Inspecter", "embeddableApi.panel.inspectPanel.untitledEmbeddableFilename": "sans titre", "embeddableApi.panel.optionsMenu.panelOptionsButtonAriaLabel": "Options de panneau", @@ -7191,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", @@ -7888,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", @@ -15602,6 +15597,15 @@ "xpack.infra.homePage.noMetricsIndicesInstructionsActionLabel": "Voir les instructions de configuration", "xpack.infra.homePage.settingsTabTitle": "Paramètres", "xpack.infra.homePage.toolbar.kqlSearchFieldPlaceholder": "Rechercher des données d'infrastructure… (par exemple host.name:host-1)", + "xpack.infra.hostsTable.nameColumnHeader": "Nom", + "xpack.infra.hostsTable.operatingSystemColumnHeader": "Système d'exploitation", + "xpack.infra.hostsTable.numberOfCpusColumnHeader": "Nombre de processeurs", + "xpack.infra.hostsTable.diskLatencyColumnHeader": "", + "xpack.infra.hostsTable.averageTxColumnHeader": "", + "xpack.infra.hostsTable.averageRxColumnHeader": "", + "xpack.infra.hostsTable.averageMemoryTotalColumnHeader": "Total de la mémoire (moy.)", + "xpack.infra.hostsTable.servicesOnHostColumnHeader": "", + "xpack.infra.hostsTable.averageMemoryUsageColumnHeader": "Utilisation de la mémoire (moy.)", "xpack.infra.infra.nodeDetails.apmTabLabel": "APM", "xpack.infra.infra.nodeDetails.createAlertLink": "Créer une règle d'inventaire", "xpack.infra.infra.nodeDetails.openAsPage": "Ouvrir en tant que page", @@ -17499,7 +17503,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", @@ -17518,7 +17521,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", @@ -17528,7 +17530,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", @@ -19175,7 +19176,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}", @@ -19627,7 +19627,6 @@ "xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTooltip": "Score normalisé compris entre 0 et 100, qui indique l'importance relative de l'enregistrement des anomalies lorsque le groupe a été initialement traité.", "xpack.ml.anomaliesTable.anomalyDetails.interimResultLabel": "Résultat temporaire", "xpack.ml.anomaliesTable.anomalyDetails.jobIdTitle": "ID tâche", - "xpack.ml.anomaliesTable.anomalyDetails.multiBucketImpactTitle": "Impact multi-groupe", "xpack.ml.anomaliesTable.anomalyDetails.probabilityTitle": "Probabilité", "xpack.ml.anomaliesTable.anomalyDetails.recordScoreTitle": "Score d'enregistrement", "xpack.ml.anomaliesTable.anomalyDetails.recordScoreTooltip": "Score normalisé compris entre 0 et 100, qui indique l'importance relative du résultat d'enregistrement des anomalies. Cette valeur peut changer au fil de l'analyse de nouvelles données.", @@ -25609,7 +25608,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.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}}", @@ -26155,8 +26154,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", @@ -26217,7 +26214,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", @@ -27345,7 +27341,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", @@ -28153,7 +28149,7 @@ "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.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 :", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 9c20bf06e9f46..91d6ae6f2bcb5 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -372,6 +372,7 @@ "controls.controlGroup.management.validate.title": "ユーザー選択を検証", "controls.controlGroup.title": "コントロールグループ", "controls.controlGroup.toolbarButtonTitle": "コントロール", + "controls.frame.error.message": "エラーが発生しました。続きを読む", "controls.optionsList.description": "フィールド値を選択するメニューを追加", "controls.optionsList.displayName": "オプションリスト", "controls.optionsList.editor.allowMultiselectTitle": "ドロップダウンでの複数選択を許可", @@ -2327,7 +2328,6 @@ "embeddableApi.errors.paneldoesNotExist": "パネルが見つかりません", "embeddableApi.helloworld.displayName": "こんにちは", "embeddableApi.panel.dashboardPanelAriaLabel": "ダッシュボードパネル", - "embeddableApi.panel.errorEmbeddable.message": "エラーが発生しました。続きを読む", "embeddableApi.panel.inspectPanel.displayName": "検査", "embeddableApi.panel.inspectPanel.untitledEmbeddableFilename": "無題", "embeddableApi.panel.optionsMenu.panelOptionsButtonAriaLabel": "パネルオプション", @@ -7179,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": "エラーのオカレンス", @@ -7875,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": "平均", @@ -15587,6 +15582,15 @@ "xpack.infra.homePage.noMetricsIndicesInstructionsActionLabel": "セットアップの手順を表示", "xpack.infra.homePage.settingsTabTitle": "設定", "xpack.infra.homePage.toolbar.kqlSearchFieldPlaceholder": "インフラストラクチャデータを検索…(例:host.name:host-1)", + "xpack.infra.hostsTable.nameColumnHeader": "名前", + "xpack.infra.hostsTable.operatingSystemColumnHeader": "オペレーティングシステム", + "xpack.infra.hostsTable.numberOfCpusColumnHeader": "CPU数", + "xpack.infra.hostsTable.diskLatencyColumnHeader": "", + "xpack.infra.hostsTable.averageTxColumnHeader": "", + "xpack.infra.hostsTable.averageRxColumnHeader": "", + "xpack.infra.hostsTable.averageMemoryTotalColumnHeader": "メモリ合計 (平均) ", + "xpack.infra.hostsTable.servicesOnHostColumnHeader": "", + "xpack.infra.hostsTable.averageMemoryUsageColumnHeader": "メモリー使用状況(平均)", "xpack.infra.infra.nodeDetails.apmTabLabel": "APM", "xpack.infra.infra.nodeDetails.createAlertLink": "インベントリルールの作成", "xpack.infra.infra.nodeDetails.openAsPage": "ページとして開く", @@ -17482,7 +17486,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]?:文字列", @@ -17501,7 +17504,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": "合計の割合", @@ -17511,7 +17513,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": "指定された集計関数を計算する列", @@ -19156,7 +19157,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}の詳細を表示", @@ -19608,7 +19608,6 @@ "xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTooltip": "0~100の正規化されたスコア。バケットが最初に処理されたときの異常レコード結果の相対的な有意性を示します。", "xpack.ml.anomaliesTable.anomalyDetails.interimResultLabel": "中間結果", "xpack.ml.anomaliesTable.anomalyDetails.jobIdTitle": "ジョブID", - "xpack.ml.anomaliesTable.anomalyDetails.multiBucketImpactTitle": "複数バケットの影響", "xpack.ml.anomaliesTable.anomalyDetails.probabilityTitle": "確率", "xpack.ml.anomaliesTable.anomalyDetails.recordScoreTitle": "レコードスコア", "xpack.ml.anomaliesTable.anomalyDetails.recordScoreTooltip": "0~100の正規化されたスコア。異常レコード結果の相対的な有意性を示します。新しいデータが分析されると、この値が変化する場合があります。", @@ -25584,7 +25583,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.disassociateListSuccessText": "例外リスト({id})が正常に削除されました", "xpack.securitySolution.exceptions.failedLoadPolicies": "ポリシーの読み込みエラーが発生しました:\"{error}\"", "xpack.securitySolution.exceptions.fetch404Error": "関連付けられた例外リスト({listId})は存在しません。その他の例外を検出ルールに追加するには、見つからない例外リストを削除してください。", "xpack.securitySolution.exceptions.hideCommentsLabel": "({comments}){comments, plural, other {件のコメント}}を非表示", @@ -26130,8 +26129,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": "カスタムジョブを作成", @@ -26192,7 +26189,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": "イベントレンダラーのカスタマイズ", @@ -27320,7 +27316,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": "一斉アクション", @@ -28128,7 +28124,7 @@ "xpack.securitySolution.exceptions.cancelLabel": "キャンセル", "xpack.securitySolution.exceptions.clearExceptionsLabel": "例外リストを削除", "xpack.securitySolution.exceptions.commentEventLabel": "コメントを追加しました", - "xpack.securitySolution.exceptions.dissasociateExceptionListError": "例外リストを削除できませんでした", + "xpack.securitySolution.exceptions.disassociateExceptionListError": "例外リストを削除できませんでした", "xpack.securitySolution.exceptions.errorLabel": "エラー", "xpack.securitySolution.exceptions.fetchError": "例外リストの取得エラー", "xpack.securitySolution.exceptions.modalErrorAccordionText": "ルール参照情報を表示:", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 70faac2c66939..c929f0f0d80ba 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -372,6 +372,7 @@ "controls.controlGroup.management.validate.title": "验证用户选择", "controls.controlGroup.title": "控件组", "controls.controlGroup.toolbarButtonTitle": "控件", + "controls.frame.error.message": "发生错误。阅读更多内容", "controls.optionsList.description": "添加用于选择字段值的菜单。", "controls.optionsList.displayName": "选项列表", "controls.optionsList.editor.allowMultiselectTitle": "下拉列表中允许多选", @@ -2331,7 +2332,6 @@ "embeddableApi.errors.paneldoesNotExist": "未找到面板", "embeddableApi.helloworld.displayName": "hello world", "embeddableApi.panel.dashboardPanelAriaLabel": "仪表板面板", - "embeddableApi.panel.errorEmbeddable.message": "发生错误。阅读更多内容", "embeddableApi.panel.inspectPanel.displayName": "检查", "embeddableApi.panel.inspectPanel.untitledEmbeddableFilename": "未命名", "embeddableApi.panel.optionsMenu.panelOptionsButtonAriaLabel": "面板选项", @@ -7195,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": "错误发生", @@ -7892,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": "平均值", @@ -15608,6 +15603,15 @@ "xpack.infra.homePage.noMetricsIndicesInstructionsActionLabel": "查看设置说明", "xpack.infra.homePage.settingsTabTitle": "设置", "xpack.infra.homePage.toolbar.kqlSearchFieldPlaceholder": "搜索基础设施数据……(例如 host.name:host-1)", + "xpack.infra.hostsTable.nameColumnHeader": "名称", + "xpack.infra.hostsTable.operatingSystemColumnHeader": "操作系统", + "xpack.infra.hostsTable.numberOfCpusColumnHeader": "# 个 CPU", + "xpack.infra.hostsTable.diskLatencyColumnHeader": "", + "xpack.infra.hostsTable.averageTxColumnHeader": "", + "xpack.infra.hostsTable.averageRxColumnHeader": "", + "xpack.infra.hostsTable.averageMemoryTotalColumnHeader": "内存合计 (平均值)", + "xpack.infra.hostsTable.servicesOnHostColumnHeader": "", + "xpack.infra.hostsTable.averageMemoryUsageColumnHeader": "内存使用率(平均值)", "xpack.infra.infra.nodeDetails.apmTabLabel": "APM", "xpack.infra.infra.nodeDetails.createAlertLink": "创建库存规则", "xpack.infra.infra.nodeDetails.openAsPage": "以页面形式打开", @@ -17507,7 +17511,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", @@ -17526,7 +17529,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": "总计的百分比", @@ -17536,7 +17538,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": "用于计算以下项的指定聚合函数的列", @@ -19182,7 +19183,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} 的详情", @@ -19638,7 +19638,6 @@ "xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTooltip": "介于 0-100 之间的标准化分数,表示初始处理存储桶时异常记录的相对意义。", "xpack.ml.anomaliesTable.anomalyDetails.interimResultLabel": "中间结果", "xpack.ml.anomaliesTable.anomalyDetails.jobIdTitle": "作业 ID", - "xpack.ml.anomaliesTable.anomalyDetails.multiBucketImpactTitle": "多存储桶影响", "xpack.ml.anomaliesTable.anomalyDetails.probabilityTitle": "可能性", "xpack.ml.anomaliesTable.anomalyDetails.recordScoreTitle": "记录分数", "xpack.ml.anomaliesTable.anomalyDetails.recordScoreTooltip": "介于 0-100 之间的标准化分数,表示异常记录结果的相对意义。在分析新数据时,该值可能会更改。", @@ -25618,7 +25617,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.disassociateListSuccessText": "例外列表 ({id}) 已成功移除", "xpack.securitySolution.exceptions.failedLoadPolicies": "加载策略时出错:“{error}”", "xpack.securitySolution.exceptions.fetch404Error": "关联的例外列表 ({listId}) 已不存在。请移除缺少的例外列表,以将其他例外添加到检测规则。", "xpack.securitySolution.exceptions.hideCommentsLabel": "隐藏 ({comments}) 个{comments, plural, other {注释}}", @@ -26164,8 +26163,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": "创建定制作业", @@ -26226,7 +26223,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": "定制事件呈现器", @@ -27354,7 +27350,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": "批处理操作", @@ -28162,7 +28158,7 @@ "xpack.securitySolution.exceptions.cancelLabel": "取消", "xpack.securitySolution.exceptions.clearExceptionsLabel": "移除例外列表", "xpack.securitySolution.exceptions.commentEventLabel": "已添加注释", - "xpack.securitySolution.exceptions.dissasociateExceptionListError": "无法移除例外列表", + "xpack.securitySolution.exceptions.disassociateExceptionListError": "无法移除例外列表", "xpack.securitySolution.exceptions.errorLabel": "错误", "xpack.securitySolution.exceptions.fetchError": "提取例外列表时出错", "xpack.securitySolution.exceptions.modalErrorAccordionText": "显示规则引用信息:", 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/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<estypes.SearchHit<any>>; + 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/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/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/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts index 80dffef7cd3ee..403d74e2290d0 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts @@ -506,8 +506,7 @@ export default ({ getService }: FtrProviderContext): void => { }); it('400s if the title is too long', async () => { - const longTitle = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nulla enim, rutrum sit amet euismod venenatis, blandit et massa. Nulla id consectetur enim.'; + const longTitle = 'a'.repeat(161); const postedCase = await createCase(supertest, postCaseReq); await updateCase({ diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/post_case.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/post_case.ts index 76759902d7a37..47a1e197ac213 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/post_case.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/post_case.ts @@ -252,8 +252,7 @@ export default ({ getService }: FtrProviderContext): void => { }); it('400s if the title is too long', async () => { - const longTitle = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nulla enim, rutrum sit amet euismod venenatis, blandit et massa. Nulla id consectetur enim.'; + const longTitle = 'a'.repeat(161); await createCase(supertest, getPostCaseRequest({ title: longTitle }), 400); }); 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<LegacyUrlAlias[]> { + 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<FtrProviderContext, 'getService'>) { 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 173aaa86c4328..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, 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-*', '<my-index-{now/d}*>']), 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<SuperTest.Test>, log: ToolingLog, - rule: CreateRulesSchema -): Promise<FullResponseSchema> => { + rule: RuleCreateProps +): Promise<RuleResponse> => { 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<SuperTest.Test>, - rule: CreateRulesSchema, + rule: RuleCreateProps, auth: { user: string; pass: string } -): Promise<FullResponseSchema> => { +): Promise<RuleResponse> => { 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<SuperTest.Test>, log: ToolingLog, - rule: CreateRulesSchema, + rule: RuleCreateProps, entries: NonEmptyEntriesArray[], endpointEntries?: Array<{ entries: NonEmptyEntriesArray; osTypes: OsTypeArray | undefined; }> -): Promise<FullResponseSchema> => { +): Promise<RuleResponse> => { 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<SuperTest.Test>, log: ToolingLog, listId: string -): Promise<FullResponseSchema> => { +): Promise<RuleResponse> => { 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<SuperTest.Test>, log: ToolingLog, ruleId: string -): Promise<FullResponseSchema> => { +): Promise<RuleResponse> => { 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<FullResponseSchema> => ({ +export const getComplexRuleOutput = (ruleId = 'rule-1'): Partial<RuleResponse> => ({ 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<SuperTest.Test>, 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<SuperTest.Test>, log: ToolingLog -): Promise<PrePackagedRulesAndTimelinesStatusSchema> => { - const response = await supertest - .get(`${DETECTION_ENGINE_PREPACKAGED_URL}/_status`) - .set('kbn-xsrf', 'true') - .send(); +): Promise<GetPrebuiltRulesAndTimelinesStatusResponse> => { + 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<SuperTest.Test>, log: ToolingLog, ruleId: string -): Promise<FullResponseSchema> => { +): Promise<RuleResponse> => { 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<RuleResponse, ServerGeneratedProperties>; /** * 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<FullResponseSchema> => { + rule: RuleResponse +): Partial<RuleResponse> => { 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<SuperTest.Test>, log: ToolingLog, - updatedRule: UpdateRulesSchema -): Promise<FullResponseSchema> => { + updatedRule: RuleUpdateProps +): Promise<RuleResponse> => { const response = await supertest .put(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') 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/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/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 39da46195d79a..f97953886c2a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2283,7 +2283,7 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@hapi/validate@1.x.x", "@hapi/validate@^1.1.1": +"@hapi/validate@1.x.x", "@hapi/validate@^1.1.1", "@hapi/validate@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@hapi/validate/-/validate-1.1.3.tgz#f750a07283929e09b51aa16be34affb44e1931ad" integrity sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA== @@ -2605,10 +2605,6 @@ version "0.0.0" uid "" -"@kbn/adhoc-profiler@link:bazel-bin/packages/kbn-adhoc-profiler": - version "0.0.0" - uid "" - "@kbn/aiops-components@link:bazel-bin/x-pack/packages/ml/aiops_components": version "0.0.0" uid "" @@ -4170,21 +4166,6 @@ resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz#c15367178d8bfe4765e6b47b542fe821ce259c7b" integrity sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ== -"@mapbox/node-pre-gyp@^1.0.0": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c" - integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA== - dependencies: - detect-libc "^2.0.0" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.7" - nopt "^5.0.0" - npmlog "^5.0.1" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.11" - "@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2" @@ -6816,10 +6797,6 @@ version "0.0.0" uid "" -"@types/kbn__adhoc-profiler@link:bazel-bin/packages/kbn-adhoc-profiler/npm_module_types": - version "0.0.0" - uid "" - "@types/kbn__aiops-components@link:bazel-bin/x-pack/packages/ml/aiops_components/npm_module_types": version "0.0.0" uid "" @@ -10834,13 +10811,6 @@ binary-search@^1.3.3: resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.6.tgz#e32426016a0c5092f0f3598836a1c7da3560565c" integrity sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA== -bindings@^1.2.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - bitmap-sdf@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/bitmap-sdf/-/bitmap-sdf-1.0.3.tgz#c99913e5729357a6fd350de34158180c013880b2" @@ -10997,6 +10967,14 @@ brfs@^2.0.0, brfs@^2.0.2: static-module "^3.0.2" through2 "^2.0.0" +brok@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/brok/-/brok-5.0.2.tgz#b77e7203ce89d30939a5b877a9bb3acb4dffc848" + integrity sha512-mqsoOGPjcP9oltC8dD4PnRCiJREmFg+ee588mVYZgZNd8YV5Zo6eOLv/fp6HxdYffaxvkKfPHjc+sRWIkuIu7A== + dependencies: + "@hapi/hoek" "^9.0.4" + "@hapi/validate" "^1.1.3" + brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -13509,11 +13487,6 @@ delaunator@5: dependencies: robust-predicates "^3.0.0" -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -15445,11 +15418,6 @@ file-system-cache@^1.0.5: fs-extra "^0.30.0" ramda "^0.21.0" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - filelist@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" @@ -15548,11 +15516,6 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -findit2@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/findit2/-/findit2-2.2.3.tgz#58a466697df8a6205cdfdbf395536b8bd777a5f6" - integrity sha512-lg/Moejf4qXovVutL0Lz4IsaPoNYMuxt4PA0nGqFxnJ1CTTGGlEO2wKgoDpwknhvZ8k4Q2F+eesgkLbG2Mxfog== - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -20877,11 +20840,6 @@ nan@^2.13.2, nan@^2.14.2, nan@^2.15.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== -nan@^2.14.0: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== - nano-css@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.2.1.tgz#73b8470fa40b028a134d3393ae36bbb34b9fa332" @@ -21855,7 +21813,7 @@ p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.3.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.0, p-limit@^3.0.1, p-limit@^3.0.2: +p-limit@^3.0.1, p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -22287,11 +22245,6 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -22834,22 +22787,6 @@ potpack@^1.0.2: resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14" integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ== -pprof@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/pprof/-/pprof-3.2.0.tgz#5a60638dc51a61128a3d57c74514e8fd99e93722" - integrity sha512-yhORhVWefg94HZgjVa6CDtYSNZJnJzZ82d4pkmrZJxf1/Y29Me/uHYLEVo6KawKKFhQywl5cGbkdnVx9bZoMew== - dependencies: - "@mapbox/node-pre-gyp" "^1.0.0" - bindings "^1.2.1" - delay "^5.0.0" - findit2 "^2.2.3" - nan "^2.14.0" - p-limit "^3.0.0" - pify "^5.0.0" - protobufjs "~6.11.0" - source-map "^0.7.3" - split "^1.0.1" - preact-render-to-string@^5.1.19: version "5.1.19" resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.1.19.tgz#ffae7c3bd1680be5ecf5991d41fe3023b3051e0e" @@ -23130,7 +23067,7 @@ protobufjs@6.8.8: "@types/node" "^10.1.0" long "^4.0.0" -protobufjs@^6.11.3, protobufjs@~6.11.0: +protobufjs@^6.11.3: version "6.11.3" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74" integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== @@ -25957,13 +25894,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -26957,7 +26887,7 @@ through2@~0.4.1: readable-stream "~1.0.17" xtend "~2.1.1" -through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8, through@~2.3.4: +"through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=