mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Osquery] Response Actions fixes (#141041)
This commit is contained in:
parent
d45ab6dbaa
commit
e50db36c16
52 changed files with 517 additions and 199 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -894,6 +894,7 @@ packages/kbn-mapbox-gl @elastic/kibana-gis
|
|||
packages/kbn-monaco @elastic/kibana-app-services
|
||||
packages/kbn-optimizer @elastic/kibana-operations
|
||||
packages/kbn-optimizer-webpack-helpers @elastic/kibana-operations
|
||||
packages/kbn-osquery-io-ts-types @elastic/security-asset-management
|
||||
packages/kbn-performance-testing-dataset-extractor @elastic/kibana-performance-testing
|
||||
packages/kbn-plugin-discovery @elastic/kibana-operations
|
||||
packages/kbn-plugin-generator @elastic/kibana-operations
|
||||
|
|
|
@ -325,6 +325,7 @@
|
|||
"@kbn/ml-is-populated-object": "link:bazel-bin/x-pack/packages/ml/is_populated_object",
|
||||
"@kbn/ml-string-hash": "link:bazel-bin/x-pack/packages/ml/string_hash",
|
||||
"@kbn/monaco": "link:bazel-bin/packages/kbn-monaco",
|
||||
"@kbn/osquery-io-ts-types": "link:bazel-bin/packages/kbn-osquery-io-ts-types",
|
||||
"@kbn/plugin-discovery": "link:bazel-bin/packages/kbn-plugin-discovery",
|
||||
"@kbn/react-field": "link:bazel-bin/packages/kbn-react-field",
|
||||
"@kbn/rule-data-utils": "link:bazel-bin/packages/kbn-rule-data-utils",
|
||||
|
@ -1068,6 +1069,7 @@
|
|||
"@types/kbn__monaco": "link:bazel-bin/packages/kbn-monaco/npm_module_types",
|
||||
"@types/kbn__optimizer": "link:bazel-bin/packages/kbn-optimizer/npm_module_types",
|
||||
"@types/kbn__optimizer-webpack-helpers": "link:bazel-bin/packages/kbn-optimizer-webpack-helpers/npm_module_types",
|
||||
"@types/kbn__osquery-io-ts-types": "link:bazel-bin/packages/kbn-osquery-io-ts-types/npm_module_types",
|
||||
"@types/kbn__performance-testing-dataset-extractor": "link:bazel-bin/packages/kbn-performance-testing-dataset-extractor/npm_module_types",
|
||||
"@types/kbn__plugin-discovery": "link:bazel-bin/packages/kbn-plugin-discovery/npm_module_types",
|
||||
"@types/kbn__plugin-generator": "link:bazel-bin/packages/kbn-plugin-generator/npm_module_types",
|
||||
|
|
|
@ -236,6 +236,7 @@ filegroup(
|
|||
"//packages/kbn-monaco:build",
|
||||
"//packages/kbn-optimizer:build",
|
||||
"//packages/kbn-optimizer-webpack-helpers:build",
|
||||
"//packages/kbn-osquery-io-ts-types:build",
|
||||
"//packages/kbn-performance-testing-dataset-extractor:build",
|
||||
"//packages/kbn-plugin-discovery:build",
|
||||
"//packages/kbn-plugin-generator:build",
|
||||
|
@ -555,6 +556,7 @@ filegroup(
|
|||
"//packages/kbn-monaco:build_types",
|
||||
"//packages/kbn-optimizer:build_types",
|
||||
"//packages/kbn-optimizer-webpack-helpers:build_types",
|
||||
"//packages/kbn-osquery-io-ts-types:build_types",
|
||||
"//packages/kbn-performance-testing-dataset-extractor:build_types",
|
||||
"//packages/kbn-plugin-discovery:build_types",
|
||||
"//packages/kbn-plugin-generator:build_types",
|
||||
|
|
127
packages/kbn-osquery-io-ts-types/BUILD.bazel
Normal file
127
packages/kbn-osquery-io-ts-types/BUILD.bazel
Normal file
|
@ -0,0 +1,127 @@
|
|||
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-osquery-io-ts-types"
|
||||
PKG_REQUIRE_NAME = "@kbn/osquery-io-ts-types"
|
||||
|
||||
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//io-ts",
|
||||
]
|
||||
|
||||
# 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//tslib",
|
||||
"@npm//io-ts",
|
||||
]
|
||||
|
||||
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"],
|
||||
)
|
3
packages/kbn-osquery-io-ts-types/README.md
Normal file
3
packages/kbn-osquery-io-ts-types/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# kbn-osquery-io-ts-types
|
||||
|
||||
Types that are specific to the osquery plugin to be shared among plugins.
|
9
packages/kbn-osquery-io-ts-types/index.ts
Normal file
9
packages/kbn-osquery-io-ts-types/index.ts
Normal file
|
@ -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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './src/live_query';
|
13
packages/kbn-osquery-io-ts-types/jest.config.js
Normal file
13
packages/kbn-osquery-io-ts-types/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test/jest_node',
|
||||
rootDir: '../..',
|
||||
roots: ['<rootDir>/packages/kbn-osquery-io-ts-types'],
|
||||
};
|
7
packages/kbn-osquery-io-ts-types/kibana.jsonc
Normal file
7
packages/kbn-osquery-io-ts-types/kibana.jsonc
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/osquery-io-ts-types",
|
||||
"owner": "@elastic/security-asset-management",
|
||||
"runtimeDeps": [],
|
||||
"typeDeps": [],
|
||||
}
|
9
packages/kbn-osquery-io-ts-types/package.json
Normal file
9
packages/kbn-osquery-io-ts-types/package.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@kbn/osquery-io-ts-types",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "io ts utilities and types to be shared with plugins from the osquery project",
|
||||
"main": "./target_node/index.js",
|
||||
"browser": "./target_web/index.js",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
|
@ -1,8 +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.
|
||||
* 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';
|
||||
|
@ -95,9 +96,9 @@ export const arrayQueries = t.array(
|
|||
t.type({
|
||||
id,
|
||||
query,
|
||||
ecs_mapping: ecsMapping,
|
||||
version,
|
||||
platform,
|
||||
ecs_mapping: ecsMappingOrUndefined,
|
||||
version: versionOrUndefined,
|
||||
platform: platformOrUndefined,
|
||||
})
|
||||
);
|
||||
export type ArrayQueries = t.TypeOf<typeof arrayQueries>;
|
16
packages/kbn-osquery-io-ts-types/tsconfig.json
Normal file
16
packages/kbn-osquery-io-ts-types/tsconfig.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"extends": "../../tsconfig.bazel.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "target_types",
|
||||
"types": [
|
||||
"jest",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
]
|
||||
}
|
|
@ -5,5 +5,4 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './schemas';
|
||||
export * from './utils';
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
|
||||
import { isEmpty, reduce } from 'lodash';
|
||||
import type { DefaultValues } from 'react-hook-form';
|
||||
import type { ECSMapping } from './schemas';
|
||||
|
||||
export type { ECSMapping };
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
|
||||
export type ECSMappingArray = Array<{
|
||||
key: string;
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
packIdOrUndefined,
|
||||
queryOrUndefined,
|
||||
queriesOrUndefined,
|
||||
} from '../../common/schemas';
|
||||
} from '@kbn/osquery-io-ts-types';
|
||||
|
||||
export const createLiveQueryRequestBodySchema = t.partial({
|
||||
agent_ids: t.array(t.string),
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
import type { Description } from '../../common/schemas';
|
||||
import type { Description } from '@kbn/osquery-io-ts-types';
|
||||
import {
|
||||
id,
|
||||
descriptionOrUndefined,
|
||||
|
@ -18,7 +18,7 @@ import {
|
|||
snapshotOrUndefined,
|
||||
removedOrUndefined,
|
||||
ecsMappingOrUndefined,
|
||||
} from '../../common/schemas';
|
||||
} from '@kbn/osquery-io-ts-types';
|
||||
import type { RequiredKeepUndefined } from '../../../types';
|
||||
|
||||
export const createSavedQueryRequestSchema = t.type({
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { filter } from 'lodash';
|
||||
import type { ECSMapping } from '../../common/schemas/common';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { useKibana } from '../common/lib/kibana';
|
||||
import type { ESTermQuery } from '../../common/typed_json';
|
||||
import { useErrorToast } from '../common/hooks/use_error_toast';
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useForm as useHookForm, FormProvider } from 'react-hook-form';
|
||||
import { isEmpty, find, pickBy } from 'lodash';
|
||||
|
@ -14,7 +15,6 @@ import { isEmpty, find, pickBy } from 'lodash';
|
|||
import type { AddToTimelinePayload } from '../../timelines/get_add_to_timeline';
|
||||
import { QueryPackSelectable } from './query_pack_selectable';
|
||||
import type { SavedQuerySOFormData } from '../../saved_queries/form/use_saved_query_form';
|
||||
import type { ECSMapping } from '../../../common/schemas/common/utils';
|
||||
import { useKibana } from '../../common/lib/kibana';
|
||||
import { ResultTabs } from '../../routes/saved_queries/edit/tabs';
|
||||
import { SavedQueryFlyout } from '../../saved_queries';
|
||||
|
|
|
@ -97,6 +97,15 @@ const LiveQueryQueryFieldComponent: React.FC<LiveQueryQueryFieldProps> = ({
|
|||
[permissions.writeLiveQueries]
|
||||
);
|
||||
|
||||
const isAdvancedToggleHidden = useMemo(
|
||||
() =>
|
||||
!(
|
||||
permissions.writeLiveQueries ||
|
||||
permissions.runSavedQueries ||
|
||||
permissions.readSavedQueries
|
||||
),
|
||||
[permissions.readSavedQueries, permissions.runSavedQueries, permissions.writeLiveQueries]
|
||||
);
|
||||
const isSavedQueryDisabled = useMemo(
|
||||
() => !permissions.runSavedQueries || !permissions.readSavedQueries,
|
||||
[permissions.readSavedQueries, permissions.runSavedQueries]
|
||||
|
@ -143,15 +152,17 @@ const LiveQueryQueryFieldComponent: React.FC<LiveQueryQueryFieldProps> = ({
|
|||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<StyledEuiAccordion
|
||||
id="advanced"
|
||||
forceState={advancedContentState}
|
||||
onToggle={handleToggle}
|
||||
buttonContent="Advanced"
|
||||
>
|
||||
<EuiSpacer size="xs" />
|
||||
<ECSMappingEditorField euiFieldProps={ecsFieldProps} />
|
||||
</StyledEuiAccordion>
|
||||
{!isAdvancedToggleHidden && (
|
||||
<StyledEuiAccordion
|
||||
id="advanced"
|
||||
forceState={advancedContentState}
|
||||
onToggle={handleToggle}
|
||||
buttonContent="Advanced"
|
||||
>
|
||||
<EuiSpacer size="xs" />
|
||||
<ECSMappingEditorField euiFieldProps={ecsFieldProps} />
|
||||
</StyledEuiAccordion>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ import type {
|
|||
import { DOCUMENT_FIELD_NAME as RECORDS_FIELD } from '@kbn/lens-plugin/common/constants';
|
||||
import { FilterStateStore } from '@kbn/es-query';
|
||||
import styled from 'styled-components';
|
||||
import type { ECSMapping } from '../../../common/schemas/common';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { SECURITY_APP_NAME } from '../../timelines/get_add_to_timeline';
|
||||
import type { AddToTimelinePayload } from '../../timelines/get_add_to_timeline';
|
||||
import { PackResultsHeader } from './pack_results_header';
|
||||
|
|
|
@ -10,7 +10,7 @@ import { EuiCode, EuiLoadingContent, EuiEmptyPrompt } from '@elastic/eui';
|
|||
import React, { useMemo } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import type { ECSMapping } from '../../common/schemas/common';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import type { AddToTimelinePayload } from '../timelines/get_add_to_timeline';
|
||||
import { LiveQueryForm } from './form';
|
||||
import { useActionResultsPrivileges } from '../action_results/use_action_privileges';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { AgentSelection } from '../../common/schemas/common';
|
||||
import type { AgentSelection } from '@kbn/osquery-io-ts-types';
|
||||
import type { CreateLiveQueryRequestBodySchema } from '../../common/schemas/routes/live_query';
|
||||
import { useKibana } from '../common/lib/kibana';
|
||||
import { useErrorToast } from '../common/hooks/use_error_toast';
|
||||
|
|
|
@ -42,7 +42,9 @@ import deepEqual from 'fast-deep-equal';
|
|||
|
||||
import type { InternalFieldErrors, UseFieldArrayRemove, UseFormReturn } from 'react-hook-form';
|
||||
import { useForm, useController, useFieldArray, useFormContext } from 'react-hook-form';
|
||||
import type { ECSMappingArray, ECSMapping } from '../../../common/schemas/common/utils';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
|
||||
import type { ECSMappingArray } from '../../../common/schemas/common/utils';
|
||||
import {
|
||||
convertECSMappingToArray,
|
||||
convertECSMappingToObject,
|
||||
|
|
|
@ -10,7 +10,7 @@ import { useForm as useHookForm } from 'react-hook-form';
|
|||
import type { Draft } from 'immer';
|
||||
import { produce } from 'immer';
|
||||
import { useMemo } from 'react';
|
||||
import type { ECSMapping } from '../../../common/schemas/common';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
|
||||
export interface UsePackQueryFormProps {
|
||||
uniqueQueryIds: string[];
|
||||
|
|
|
@ -26,10 +26,9 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import React, { createContext, useEffect, useState, useCallback, useContext, useMemo } from 'react';
|
||||
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { pagePathGetters } from '@kbn/fleet-plugin/public';
|
||||
import type { AddToTimelinePayload } from '../timelines/get_add_to_timeline';
|
||||
import type { ECSMapping } from '../../common/schemas/common';
|
||||
import { useAllResults } from './use_all_results';
|
||||
import type { ResultEdges } from '../../common/search_strategy';
|
||||
import { Direction } from '../../common/search_strategy';
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
import { EuiTabbedContent, EuiNotificationBadge } from '@elastic/eui';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import type { AddToTimelinePayload } from '../../../timelines/get_add_to_timeline';
|
||||
import type { ECSMapping } from '../../../../common/schemas/common';
|
||||
import { ResultsTable } from '../../../results/results_table';
|
||||
import { ActionResultsSummary } from '../../../action_results/action_results_summary';
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ import { useHistory } from 'react-router-dom';
|
|||
import deepEqual from 'fast-deep-equal';
|
||||
|
||||
import type { SavedObject } from '@kbn/core/public';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { Direction } from '../../../../common/search_strategy';
|
||||
import type { ECSMapping } from '../../../../common/schemas/common';
|
||||
import { WithHeaderLayout } from '../../../components/layouts';
|
||||
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
|
||||
import { useKibana, useRouterNavigate } from '../../../common/lib/kibana';
|
||||
|
|
|
@ -10,7 +10,7 @@ import { isArray, isEmpty, map } from 'lodash';
|
|||
import type { Draft } from 'immer';
|
||||
import produce from 'immer';
|
||||
import { useMemo } from 'react';
|
||||
import type { ECSMapping } from '../../../common/schemas/common';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { useSavedQueries } from '../use_saved_queries';
|
||||
|
||||
export interface SavedQuerySOFormData {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { useForm as useHookForm, FormProvider } from 'react-hook-form';
|
|||
import { get, isEmpty, map } from 'lodash';
|
||||
import useEffectOnce from 'react-use/lib/useEffectOnce';
|
||||
|
||||
import type { ECSMapping } from '../../../common/schemas/common/utils';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { QueryPackSelectable } from '../../live_queries/form/query_pack_selectable';
|
||||
import { useFormContext } from '../../shared_imports';
|
||||
import type { ArrayItem } from '../../shared_imports';
|
||||
|
@ -98,7 +98,7 @@ const OsqueryResponseActionParamsFormComponent = forwardRef<
|
|||
id: watchedValues.id,
|
||||
savedQueryId: watchedValues.savedQueryId,
|
||||
query: watchedValues.query,
|
||||
ecs_mapping: watchedValues.ecs_mapping,
|
||||
ecsMapping: watchedValues.ecs_mapping,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -139,13 +139,18 @@ const OsqueryResponseActionParamsFormComponent = forwardRef<
|
|||
|
||||
useEffectOnce(() => {
|
||||
if (defaultParams && defaultParams.id) {
|
||||
const { packId, ...restParams } = defaultParams;
|
||||
const { packId, ecsMapping, ...restParams } = defaultParams;
|
||||
// TODO change map into forEach, and type defaultParams
|
||||
map(restParams, (value, key: keyof OsqueryResponseActionsParamsFormFields) => {
|
||||
if (!isEmpty(value)) {
|
||||
setValue(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
if (!isEmpty(ecsMapping)) {
|
||||
setValue('ecs_mapping', ecsMapping);
|
||||
}
|
||||
|
||||
if (!isEmpty(packId)) {
|
||||
setValue('packId', [packId]);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { ReactElement } from 'react';
|
|||
import React, { useMemo } from 'react';
|
||||
import { find } from 'lodash';
|
||||
import { useWatch } from 'react-hook-form';
|
||||
import type { ECSMapping } from '../../../common/schemas/common';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { PackQueriesStatusTable } from '../../live_queries/form/pack_queries_status_table';
|
||||
import { usePacks } from '../../packs/use_packs';
|
||||
import { PacksComboBoxField } from '../../live_queries/form/packs_combobox_field';
|
||||
|
|
|
@ -209,12 +209,14 @@ export class TelemetryEventsSender {
|
|||
type: 'boolean',
|
||||
_meta: {
|
||||
description: '',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
prebuilt: {
|
||||
type: 'boolean',
|
||||
_meta: {
|
||||
description: '',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
ecs_mapping: {
|
||||
|
|
|
@ -6,28 +6,22 @@
|
|||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { ecsMapping, arrayQueries } from '@kbn/osquery-io-ts-types';
|
||||
|
||||
export const OsqueryParams = t.intersection([
|
||||
t.type({
|
||||
id: t.string,
|
||||
}),
|
||||
t.partial({
|
||||
query: t.union([t.string, t.undefined]),
|
||||
ecs_mapping: t.record(t.string, t.record(t.string, t.any)),
|
||||
queries: t.array(
|
||||
t.intersection([
|
||||
t.type({
|
||||
id: t.string,
|
||||
query: t.string,
|
||||
}),
|
||||
t.partial({
|
||||
ecs_mapping: t.record(t.string, t.record(t.string, t.any)),
|
||||
platform: t.union([t.string, t.undefined]),
|
||||
interval: t.union([t.number, t.undefined]),
|
||||
}),
|
||||
])
|
||||
),
|
||||
packId: t.union([t.string, t.undefined]),
|
||||
savedQueryId: t.union([t.string, t.undefined]),
|
||||
}),
|
||||
]);
|
||||
export const OsqueryParams = t.type({
|
||||
id: t.string,
|
||||
query: t.union([t.string, t.undefined]),
|
||||
ecs_mapping: t.union([ecsMapping, t.undefined]),
|
||||
queries: t.union([arrayQueries, t.undefined]),
|
||||
pack_id: t.union([t.string, t.undefined]),
|
||||
saved_query_id: t.union([t.string, t.undefined]),
|
||||
});
|
||||
|
||||
export const OsqueryParamsCamelCase = t.type({
|
||||
id: t.string,
|
||||
query: t.union([t.string, t.undefined]),
|
||||
ecsMapping: t.union([ecsMapping, t.undefined]),
|
||||
queries: t.union([arrayQueries, t.undefined]),
|
||||
packId: t.union([t.string, t.undefined]),
|
||||
savedQueryId: t.union([t.string, t.undefined]),
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { OsqueryParams } from './osquery';
|
||||
import { OsqueryParams, OsqueryParamsCamelCase } from './osquery';
|
||||
|
||||
export enum RESPONSE_ACTION_TYPES {
|
||||
OSQUERY = '.osquery',
|
||||
|
@ -18,7 +18,7 @@ export const SUPPORTED_RESPONSE_ACTION_TYPES = Object.values(RESPONSE_ACTION_TYP
|
|||
const ResponseActionRuleParam = t.exact(
|
||||
t.type({
|
||||
actionTypeId: t.literal(RESPONSE_ACTION_TYPES.OSQUERY),
|
||||
params: OsqueryParams,
|
||||
params: OsqueryParamsCamelCase,
|
||||
})
|
||||
);
|
||||
export type RuleResponseAction = t.TypeOf<typeof ResponseActionRuleParam>;
|
||||
|
|
|
@ -50,12 +50,24 @@ describe('transform_actions', () => {
|
|||
action_type_id: RESPONSE_ACTION_TYPES.OSQUERY,
|
||||
params: {
|
||||
id: 'test',
|
||||
ecs_mapping: {},
|
||||
saved_query_id: undefined,
|
||||
pack_id: undefined,
|
||||
query: undefined,
|
||||
queries: undefined,
|
||||
},
|
||||
};
|
||||
const alertAction = transformRuleToAlertResponseAction(ruleAction);
|
||||
expect(alertAction).toEqual({
|
||||
actionTypeId: ruleAction.action_type_id,
|
||||
params: ruleAction.params,
|
||||
params: {
|
||||
id: 'test',
|
||||
ecsMapping: {},
|
||||
savedQueryId: undefined,
|
||||
packId: undefined,
|
||||
query: undefined,
|
||||
queries: undefined,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -64,12 +76,24 @@ describe('transform_actions', () => {
|
|||
actionTypeId: RESPONSE_ACTION_TYPES.OSQUERY,
|
||||
params: {
|
||||
id: 'test',
|
||||
ecsMapping: {},
|
||||
savedQueryId: undefined,
|
||||
packId: undefined,
|
||||
query: undefined,
|
||||
queries: undefined,
|
||||
},
|
||||
};
|
||||
const ruleAction = transformAlertToRuleResponseAction(alertAction);
|
||||
expect(ruleAction).toEqual({
|
||||
action_type_id: alertAction.actionTypeId,
|
||||
params: alertAction.params,
|
||||
params: {
|
||||
id: 'test',
|
||||
ecs_mapping: {},
|
||||
saved_query_id: undefined,
|
||||
pack_id: undefined,
|
||||
query: undefined,
|
||||
queries: undefined,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -37,8 +37,20 @@ export const transformRuleToAlertResponseAction = ({
|
|||
action_type_id: actionTypeId,
|
||||
params,
|
||||
}: ResponseAction): RuleResponseAction => {
|
||||
const {
|
||||
saved_query_id: savedQueryId,
|
||||
ecs_mapping: ecsMapping,
|
||||
pack_id: packId,
|
||||
...rest
|
||||
} = params;
|
||||
|
||||
return {
|
||||
params,
|
||||
params: {
|
||||
...rest,
|
||||
savedQueryId,
|
||||
ecsMapping,
|
||||
packId,
|
||||
},
|
||||
actionTypeId,
|
||||
};
|
||||
};
|
||||
|
@ -47,8 +59,14 @@ export const transformAlertToRuleResponseAction = ({
|
|||
actionTypeId,
|
||||
params,
|
||||
}: RuleResponseAction): ResponseAction => {
|
||||
const { savedQueryId, ecsMapping, packId, ...rest } = params;
|
||||
return {
|
||||
params,
|
||||
params: {
|
||||
...rest,
|
||||
saved_query_id: savedQueryId,
|
||||
ecs_mapping: ecsMapping,
|
||||
pack_id: packId,
|
||||
},
|
||||
action_type_id: actionTypeId,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@ import React, { useCallback, useMemo, useState } from 'react';
|
|||
import styled from 'styled-components';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import type { AlertRawEventData } from './osquery_tab';
|
||||
import { useOsqueryTab } from './osquery_tab';
|
||||
import { EventFieldsBrowser } from './event_fields_browser';
|
||||
import { JsonView } from './json_view';
|
||||
|
@ -51,21 +52,6 @@ export const EVENT_DETAILS_CONTEXT_ID = 'event-details';
|
|||
|
||||
type EventViewTab = EuiTabbedContentTab;
|
||||
|
||||
export interface AlertRawEventData {
|
||||
_id: string;
|
||||
fields: {
|
||||
['agent.id']?: string[];
|
||||
['kibana.alert.rule.parameters']: Array<{
|
||||
response_actions: Array<{
|
||||
action_type_id: string;
|
||||
params: Record<string, unknown>;
|
||||
}>;
|
||||
}>;
|
||||
['kibana.alert.rule.name']: string[];
|
||||
};
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export type EventViewId =
|
||||
| EventsViewType.tableView
|
||||
| EventsViewType.jsonView
|
||||
|
@ -130,6 +116,7 @@ const TabContentWrapper = styled.div`
|
|||
const RendererContainer = styled.div`
|
||||
overflow-x: auto;
|
||||
padding-right: ${(props) => props.theme.eui.euiSizeXS};
|
||||
|
||||
& .${DETAILS_CLASS_NAME} .euiFlexGroup {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
@ -397,7 +384,6 @@ const EventDetailsComponent: React.FC<Props> = ({
|
|||
|
||||
const osqueryTab = useOsqueryTab({
|
||||
rawEventData: rawEventData as AlertRawEventData,
|
||||
id,
|
||||
});
|
||||
|
||||
const tabs = useMemo(() => {
|
||||
|
|
|
@ -5,13 +5,21 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiNotificationBadge } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import {
|
||||
EuiCode,
|
||||
EuiEmptyPrompt,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiNotificationBadge,
|
||||
} from '@elastic/eui';
|
||||
import React, { useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { PERMISSION_DENIED } from '../../../detection_engine/rule_response_actions/osquery/translations';
|
||||
import { expandDottedObject } from '../../../../common/utils/expand_dotted';
|
||||
import { RESPONSE_ACTION_TYPES } from '../../../../common/detection_engine/rule_response_actions/schemas';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
import type { AlertRawEventData } from './event_details';
|
||||
import { EventsViewType } from './event_details';
|
||||
import * as i18n from './translations';
|
||||
import { useHandleAddToTimeline } from './add_to_timeline_button';
|
||||
|
@ -20,68 +28,126 @@ const TabContentWrapper = styled.div`
|
|||
height: 100%;
|
||||
position: relative;
|
||||
`;
|
||||
type RuleParameters = Array<{
|
||||
response_actions: Array<{
|
||||
action_type_id: string;
|
||||
params: Record<string, unknown>;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
export const useOsqueryTab = ({
|
||||
rawEventData,
|
||||
id,
|
||||
}: {
|
||||
rawEventData?: AlertRawEventData;
|
||||
id: string;
|
||||
}) => {
|
||||
export interface AlertRawEventData {
|
||||
_id: string;
|
||||
fields: {
|
||||
['agent.id']?: string[];
|
||||
['kibana.alert.rule.parameters']: RuleParameters;
|
||||
['kibana.alert.rule.name']: string[];
|
||||
};
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface ExpandedEventFieldsObject {
|
||||
agent?: {
|
||||
id: string[];
|
||||
};
|
||||
kibana: {
|
||||
alert?: {
|
||||
rule?: {
|
||||
parameters: RuleParameters;
|
||||
name: string[];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const useOsqueryTab = ({ rawEventData }: { rawEventData?: AlertRawEventData }) => {
|
||||
const {
|
||||
services: { osquery },
|
||||
services: { osquery, application },
|
||||
} = useKibana();
|
||||
const handleAddToTimeline = useHandleAddToTimeline();
|
||||
const responseActionsEnabled = useIsExperimentalFeatureEnabled('responseActionsEnabled');
|
||||
|
||||
const emptyPrompt = useMemo(
|
||||
() => (
|
||||
<EuiEmptyPrompt
|
||||
iconType="logoOsquery"
|
||||
title={<h2>{PERMISSION_DENIED}</h2>}
|
||||
titleSize="xs"
|
||||
body={
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.osquery.results.missingPrivilleges"
|
||||
defaultMessage="To access these results, ask your administrator for {osquery} Kibana
|
||||
privileges."
|
||||
values={{
|
||||
// eslint-disable-next-line react/jsx-no-literals
|
||||
osquery: <EuiCode>osquery</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
if (!osquery || !rawEventData || !responseActionsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { OsqueryResults } = osquery;
|
||||
const parameters = rawEventData.fields['kibana.alert.rule.parameters'];
|
||||
const expandedEventFieldsObject = expandDottedObject(
|
||||
rawEventData.fields
|
||||
) as ExpandedEventFieldsObject;
|
||||
|
||||
const parameters = expandedEventFieldsObject.kibana?.alert?.rule?.parameters;
|
||||
const responseActions = parameters?.[0].response_actions;
|
||||
|
||||
const osqueryActionsLength = responseActions?.filter(
|
||||
(action: { action_type_id: string }) => action.action_type_id === RESPONSE_ACTION_TYPES.OSQUERY
|
||||
)?.length;
|
||||
|
||||
const agentIds = rawEventData.fields['agent.id'];
|
||||
const ruleName = rawEventData.fields['kibana.alert.rule.name'];
|
||||
if (!osqueryActionsLength) {
|
||||
return;
|
||||
}
|
||||
const ruleName = expandedEventFieldsObject.kibana?.alert?.rule?.name;
|
||||
const agentIds = expandedEventFieldsObject.agent?.id;
|
||||
|
||||
const alertId = rawEventData._id;
|
||||
return osqueryActionsLength
|
||||
? {
|
||||
id: EventsViewType.osqueryView,
|
||||
'data-test-subj': 'osqueryViewTab',
|
||||
name: (
|
||||
<EuiFlexGroup
|
||||
direction="row"
|
||||
alignItems={'center'}
|
||||
justifyContent={'spaceAround'}
|
||||
gutterSize="xs"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<span>{i18n.OSQUERY_VIEW}</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiNotificationBadge data-test-subj="osquery-actions-notification">
|
||||
{osqueryActionsLength}
|
||||
</EuiNotificationBadge>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
content: (
|
||||
<>
|
||||
<TabContentWrapper data-test-subj="osqueryViewWrapper">
|
||||
<OsqueryResults
|
||||
agentIds={agentIds}
|
||||
ruleName={ruleName}
|
||||
alertId={alertId}
|
||||
addToTimeline={handleAddToTimeline}
|
||||
/>
|
||||
</TabContentWrapper>
|
||||
</>
|
||||
),
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
id: EventsViewType.osqueryView,
|
||||
'data-test-subj': 'osqueryViewTab',
|
||||
name: (
|
||||
<EuiFlexGroup
|
||||
direction="row"
|
||||
alignItems={'center'}
|
||||
justifyContent={'spaceAround'}
|
||||
gutterSize="xs"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<span>{i18n.OSQUERY_VIEW}</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiNotificationBadge data-test-subj="osquery-actions-notification">
|
||||
{osqueryActionsLength}
|
||||
</EuiNotificationBadge>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
content: (
|
||||
<>
|
||||
<TabContentWrapper data-test-subj="osqueryViewWrapper">
|
||||
{!application?.capabilities?.osquery?.read ? (
|
||||
emptyPrompt
|
||||
) : (
|
||||
<OsqueryResults
|
||||
agentIds={agentIds}
|
||||
ruleName={ruleName}
|
||||
alertId={alertId}
|
||||
addToTimeline={handleAddToTimeline}
|
||||
/>
|
||||
)}
|
||||
</TabContentWrapper>
|
||||
</>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ interface IProps {
|
|||
}
|
||||
|
||||
export const OsqueryResponseAction = React.memo((props: IProps) => {
|
||||
const { osquery } = useKibana().services;
|
||||
const { osquery, application } = useKibana().services;
|
||||
const OsqueryForm = useMemo(
|
||||
() => osquery?.OsqueryResponseActionTypeForm,
|
||||
[osquery?.OsqueryResponseActionTypeForm]
|
||||
|
@ -27,13 +27,20 @@ export const OsqueryResponseAction = React.memo((props: IProps) => {
|
|||
|
||||
if (osquery) {
|
||||
const { disabled, permissionDenied } = osquery?.fetchInstallationStatus();
|
||||
const disabledOsqueryPermission = !(
|
||||
application?.capabilities?.osquery?.writeLiveQueries ||
|
||||
(application?.capabilities?.osquery?.runSavedQueries &&
|
||||
(application?.capabilities?.osquery?.readSavedQueries ||
|
||||
application?.capabilities?.osquery?.readPacks))
|
||||
);
|
||||
|
||||
if (permissionDenied) {
|
||||
if (permissionDenied || disabledOsqueryPermission) {
|
||||
return (
|
||||
<>
|
||||
<EuiEmptyPrompt
|
||||
title={<h2>{PERMISSION_DENIED}</h2>}
|
||||
titleSize="xs"
|
||||
iconType="logoOsquery"
|
||||
body={
|
||||
<p>
|
||||
<FormattedMessage
|
||||
|
@ -55,6 +62,7 @@ export const OsqueryResponseAction = React.memo((props: IProps) => {
|
|||
if (disabled) {
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
iconType="logoOsquery"
|
||||
title={<h2>{SHORT_EMPTY_TITLE}</h2>}
|
||||
titleSize="xs"
|
||||
body={<p>{NOT_AVAILABLE}</p>}
|
||||
|
|
|
@ -125,6 +125,7 @@ export const RuleActionsField: React.FC<Props> = ({ field, messageVariables }) =
|
|||
setActionParamsProperty,
|
||||
featureId: SecurityConnectorFeatureId,
|
||||
defaultActionMessage: DEFAULT_ACTION_MESSAGE,
|
||||
hideActionHeader: true,
|
||||
}),
|
||||
[
|
||||
actions,
|
||||
|
|
|
@ -14,7 +14,7 @@ import { HeaderSection } from '../../../../common/components/header_section';
|
|||
interface StepPanelProps {
|
||||
children: React.ReactNode;
|
||||
loading: boolean;
|
||||
title: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const MyPanel = styled(EuiPanel)`
|
||||
|
@ -33,7 +33,7 @@ const StepPanelComponent: React.FC<StepPanelProps> = ({ children, loading, title
|
|||
data-test-subj="stepPanelProgress"
|
||||
/>
|
||||
)}
|
||||
<HeaderSection title={title} />
|
||||
{title && <HeaderSection title={title} />}
|
||||
{children}
|
||||
</MyPanel>
|
||||
);
|
||||
|
|
|
@ -34,12 +34,5 @@ export const getSchema = ({
|
|||
defaultMessage: 'Actions frequency',
|
||||
}
|
||||
),
|
||||
helpText: i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.fieldThrottleHelpText',
|
||||
{
|
||||
defaultMessage:
|
||||
'Select when automated actions should be performed if a rule evaluates as true.',
|
||||
}
|
||||
),
|
||||
},
|
||||
});
|
||||
|
|
|
@ -13,10 +13,12 @@ import {
|
|||
EuiButton,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { findIndex } from 'lodash/fp';
|
||||
import type { FC } from 'react';
|
||||
import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import type { ActionVariables } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { UseArray } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
||||
|
@ -40,6 +42,7 @@ import { getSchema } from './get_schema';
|
|||
import * as I18n from './translations';
|
||||
import { APP_UI_ID } from '../../../../../common/constants';
|
||||
import { useManageCaseAction } from './use_manage_case_action';
|
||||
import { THROTTLE_FIELD_HELP_TEXT, THROTTLE_FIELD_HELP_TEXT_WHEN_QUERY } from './translations';
|
||||
|
||||
interface StepRuleActionsProps extends RuleStepProps {
|
||||
defaultValues?: ActionsStepRule | null;
|
||||
|
@ -66,6 +69,22 @@ const getThrottleOptions = (throttle?: string | null) => {
|
|||
return THROTTLE_OPTIONS;
|
||||
};
|
||||
|
||||
const DisplayActionsHeader = () => {
|
||||
return (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
defaultMessage="Actions"
|
||||
id="xpack.securitySolution.detectionEngine.rule.editRule.actionSectionsTitle"
|
||||
/>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="l" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({
|
||||
addPadding = false,
|
||||
defaultValues,
|
||||
|
@ -164,11 +183,14 @@ const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({
|
|||
isLoading: isLoadingCaseAction,
|
||||
dataTestSubj: 'detectionEngineStepRuleActionsThrottle',
|
||||
hasNoInitialSelection: false,
|
||||
helpText: isQueryRule(ruleType)
|
||||
? THROTTLE_FIELD_HELP_TEXT_WHEN_QUERY
|
||||
: THROTTLE_FIELD_HELP_TEXT,
|
||||
euiFieldProps: {
|
||||
options: throttleOptions,
|
||||
},
|
||||
}),
|
||||
[isLoading, isLoadingCaseAction, throttleOptions]
|
||||
[isLoading, isLoadingCaseAction, ruleType, throttleOptions]
|
||||
);
|
||||
|
||||
const displayActionsOptions = useMemo(
|
||||
|
@ -192,11 +214,9 @@ const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({
|
|||
const displayResponseActionsOptions = useMemo(() => {
|
||||
if (isQueryRule(ruleType)) {
|
||||
return (
|
||||
<>
|
||||
<UseArray path="responseActions">
|
||||
{(params) => <ResponseActionsForm {...params} saveClickRef={saveClickRef} />}
|
||||
</UseArray>
|
||||
</>
|
||||
<UseArray path="responseActions" initialNumberOfItems={0}>
|
||||
{(params) => <ResponseActionsForm {...params} saveClickRef={saveClickRef} />}
|
||||
</UseArray>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
@ -205,6 +225,7 @@ const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({
|
|||
const displayActionsDropDown = useMemo(() => {
|
||||
return application.capabilities.actions.show ? (
|
||||
<>
|
||||
<DisplayActionsHeader />
|
||||
<UseField
|
||||
path="throttle"
|
||||
component={ThrottleSelectField}
|
||||
|
|
|
@ -28,3 +28,19 @@ export const NO_ACTIONS_READ_PERMISSIONS = i18n.translate(
|
|||
'Cannot create rule actions. You do not have "Read" permissions for the "Actions" plugin.',
|
||||
}
|
||||
);
|
||||
|
||||
export const THROTTLE_FIELD_HELP_TEXT = i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.fieldThrottleHelpText',
|
||||
{
|
||||
defaultMessage:
|
||||
'Select when automated actions should be performed if a rule evaluates as true.',
|
||||
}
|
||||
);
|
||||
|
||||
export const THROTTLE_FIELD_HELP_TEXT_WHEN_QUERY = i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.fieldThrottleHelpTextWhenQuery',
|
||||
{
|
||||
defaultMessage:
|
||||
'Select when automated actions should be performed if a rule evaluates as true. This frequency does not apply to Response Actions.',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -281,7 +281,7 @@ const EditRulePageComponent: FC = () => {
|
|||
content: (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<StepPanel loading={loading} title={ruleI18n.ACTIONS}>
|
||||
<StepPanel loading={loading}>
|
||||
{actionsStep.data != null && (
|
||||
<StepRuleActions
|
||||
isReadOnlyView={false}
|
||||
|
|
|
@ -140,7 +140,7 @@ describe('rule helpers', () => {
|
|||
enabled: true,
|
||||
throttle: 'no_actions',
|
||||
actions: [],
|
||||
responseActions: [],
|
||||
responseActions: undefined,
|
||||
};
|
||||
const aboutRuleDataDetailsData = {
|
||||
note: '# this is some markdown documentation',
|
||||
|
@ -411,7 +411,7 @@ describe('rule helpers', () => {
|
|||
actionTypeId: 'action_type_id',
|
||||
},
|
||||
],
|
||||
responseActions: [],
|
||||
responseActions: undefined,
|
||||
enabled: mockedRule.enabled,
|
||||
throttle: 'no_actions',
|
||||
};
|
||||
|
|
|
@ -76,7 +76,7 @@ export const getActionsStepsData = (
|
|||
response_actions?: ResponseAction[];
|
||||
}
|
||||
): ActionsStepRule => {
|
||||
const { enabled, throttle, meta, actions = [], response_actions: responseActions = [] } = rule;
|
||||
const { enabled, throttle, meta, actions = [], response_actions: responseActions } = rule;
|
||||
|
||||
return {
|
||||
actions: actions?.map(transformRuleToAlertAction),
|
||||
|
|
|
@ -11,7 +11,6 @@ import React, { useMemo } from 'react';
|
|||
import deepEqual from 'fast-deep-equal';
|
||||
import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import type { EntityType } from '@kbn/timelines-plugin/common';
|
||||
import type { AlertRawEventData } from '../../../../common/components/event_details/event_details';
|
||||
import type { BrowserFields } from '../../../../common/containers/source';
|
||||
import { ExpandableEvent, ExpandableEventTitle } from './expandable_event';
|
||||
import { useTimelineEventsDetails } from '../../../containers/details';
|
||||
|
@ -128,7 +127,7 @@ const EventDetailsPanelComponent: React.FC<EventDetailsPanelProps> = ({
|
|||
isIsolateActionSuccessBannerVisible={isIsolateActionSuccessBannerVisible}
|
||||
isHostIsolationPanelOpen={isHostIsolationPanelOpen}
|
||||
loading={loading}
|
||||
rawEventData={rawEventData as AlertRawEventData}
|
||||
rawEventData={rawEventData}
|
||||
showAlertDetails={showAlertDetails}
|
||||
timelineId={timelineId}
|
||||
isReadOnly={isReadOnly}
|
||||
|
@ -166,7 +165,7 @@ const EventDetailsPanelComponent: React.FC<EventDetailsPanelProps> = ({
|
|||
isAlert={isAlert}
|
||||
isDraggable={isDraggable}
|
||||
loading={loading}
|
||||
rawEventData={rawEventData as AlertRawEventData}
|
||||
rawEventData={rawEventData}
|
||||
timelineId={timelineId}
|
||||
timelineTabType={tabType}
|
||||
handleOnEventClosed={handleOnEventClosed}
|
||||
|
|
|
@ -10,27 +10,6 @@ import type { RuleResponseAction } from '../../../../common/detection_engine/rul
|
|||
import { RESPONSE_ACTION_TYPES } from '../../../../common/detection_engine/rule_response_actions/schemas';
|
||||
import type { SetupPlugins } from '../../../plugin_contract';
|
||||
|
||||
interface OsqueryQuery {
|
||||
id: string;
|
||||
query: string;
|
||||
ecs_mapping: Record<string, Record<'field', string>>;
|
||||
version: string;
|
||||
interval?: number;
|
||||
platform: string;
|
||||
}
|
||||
|
||||
interface OsqueryResponseAction {
|
||||
actionTypeId: RESPONSE_ACTION_TYPES.OSQUERY;
|
||||
params: {
|
||||
id: string;
|
||||
queries: OsqueryQuery[];
|
||||
savedQueryId: string;
|
||||
query: string;
|
||||
packId: string;
|
||||
ecs_mapping?: Record<string, { field?: string; value?: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
interface ScheduleNotificationActions {
|
||||
signals: unknown[];
|
||||
responseActions: RuleResponseAction[];
|
||||
|
@ -42,10 +21,6 @@ interface IAlert {
|
|||
};
|
||||
}
|
||||
|
||||
const isOsqueryAction = (action: RuleResponseAction): action is OsqueryResponseAction => {
|
||||
return action.actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY;
|
||||
};
|
||||
|
||||
export const scheduleNotificationResponseActions = (
|
||||
{ signals, responseActions }: ScheduleNotificationActions,
|
||||
osqueryCreateAction?: SetupPlugins['osquery']['osqueryCreateAction']
|
||||
|
@ -55,14 +30,8 @@ export const scheduleNotificationResponseActions = (
|
|||
const alertIds = map(filteredAlerts, '_id');
|
||||
|
||||
responseActions.forEach((responseAction) => {
|
||||
if (isOsqueryAction(responseAction) && osqueryCreateAction) {
|
||||
const {
|
||||
savedQueryId,
|
||||
packId,
|
||||
queries,
|
||||
ecs_mapping: ecsMapping,
|
||||
...rest
|
||||
} = responseAction.params;
|
||||
if (responseAction.actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY && osqueryCreateAction) {
|
||||
const { savedQueryId, packId, queries, ecsMapping, ...rest } = responseAction.params;
|
||||
|
||||
return osqueryCreateAction({
|
||||
...rest,
|
||||
|
|
|
@ -25194,6 +25194,7 @@
|
|||
"xpack.securitySolution.detectionEngine.relatedIntegrations.popoverDescriptionInstalledVersionTooltip": "Non-correspondance de version ; veuillez résoudre le problème ! La version installée est \"{installedVersion}\" alors que la version exigée est \"{requiredVersion}\"",
|
||||
"xpack.securitySolution.detectionEngine.relatedIntegrations.popoverTitle": "[{integrationsCount}] {integrationsCount, plural, =1 {Intégration associée disponible} other {Intégrations associées disponibles}}",
|
||||
"xpack.securitySolution.detectionEngine.rule.editRule.errorMsgDescription": "Une entrée est incorrecte dans {countError, plural, one {cet onglet} other {ces onglets}} : {tabHasError}",
|
||||
"xpack.securitySolution.detectionEngine.rule.editRule.actionSectionsTitle": "Actions",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleCreationDescription": "Créé par : {by} le {date}",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.gapDurationColumnTooltip": "Durée de l'écart dans l'exécution de la règle (hh:mm:ss:SSS). Ajustez l'historique des règles ou {seeDocs} pour réduire les écarts.",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.searchLimitExceededLabel": "Plus de {totalItems} exceptions de règle correspondent aux filtres fournis. Affichage des {maxItems} premières en fonction du \"@timestamp\" le plus récent. Utilisez d'autres contraintes de filtres pour afficher des événements d'exécution supplémentaires.",
|
||||
|
|
|
@ -25170,6 +25170,7 @@
|
|||
"xpack.securitySolution.detectionEngine.relatedIntegrations.popoverDescription": "{integrationsCount, plural, =1 {以下の統合} other {以下の1つ以上の統合}}をインストールおよび構成し、この検出ルールに必要なデータを取り込みます。",
|
||||
"xpack.securitySolution.detectionEngine.relatedIntegrations.popoverDescriptionInstalledVersionTooltip": "バージョン不一致 - 解決してください。バージョン`{requiredVersion}`が必要なときのインストール済みバージョン`{installedVersion}`",
|
||||
"xpack.securitySolution.detectionEngine.rule.editRule.errorMsgDescription": "{countError, plural, one {このタブ} other {これらのタブ}}に無効な入力があります:{tabHasError}",
|
||||
"xpack.securitySolution.detectionEngine.rule.editRule.actionSectionsTitle": "アクション",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleCreationDescription": "作成者:{by} 日付:{date}",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.gapDurationColumnTooltip": "ルール実行のギャップの期間(hh:mm:ss:SSS)。ルールルックバックを調整するか、ギャップの軽減については{seeDocs}してください。",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.searchLimitExceededLabel": "{totalItems}件以上のルール実行が指定されたフィルターと一致します。最新の「@timestamp」で最初の{maxItems}を表示しています。さらにフィルターを絞り込み、追加の実行イベントを表示します。",
|
||||
|
|
|
@ -25200,6 +25200,7 @@
|
|||
"xpack.securitySolution.detectionEngine.relatedIntegrations.popoverDescriptionInstalledVersionTooltip": "版本不匹配 -- 请解决!已安装版本 `{installedVersion}`,而所需版本为 `{requiredVersion}`",
|
||||
"xpack.securitySolution.detectionEngine.relatedIntegrations.popoverTitle": "有 [{integrationsCount}] 个相关{integrationsCount, plural, other {集成}}可用",
|
||||
"xpack.securitySolution.detectionEngine.rule.editRule.errorMsgDescription": "您在{countError, plural, other {以下选项卡}}中的输入无效:{tabHasError}",
|
||||
"xpack.securitySolution.detectionEngine.rule.editRule.actionSectionsTitle": "操作",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleCreationDescription": "由 {by} 于 {date}创建",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.gapDurationColumnTooltip": "规则执行中缺口的持续时间 (hh:mm:ss:SSS)。调整规则回查或{seeDocs}以缩小缺口。",
|
||||
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.searchLimitExceededLabel": "超过 {totalItems} 个规则执行与提供的筛选相匹配。正在按最近的“@timestamp”显示前 {maxItems} 项。进一步限制筛选以查看其他执行事件。",
|
||||
|
|
|
@ -62,6 +62,7 @@ export interface ActionAccordionFormProps {
|
|||
actionTypeRegistry: ActionTypeRegistryContract;
|
||||
recoveryActionGroup?: string;
|
||||
isActionGroupDisabledForActionType?: (actionGroupId: string, actionTypeId: string) => boolean;
|
||||
hideActionHeader?: boolean;
|
||||
}
|
||||
|
||||
interface ActiveActionConnectorState {
|
||||
|
@ -85,6 +86,7 @@ export const ActionForm = ({
|
|||
actionTypeRegistry,
|
||||
recoveryActionGroup,
|
||||
isActionGroupDisabledForActionType,
|
||||
hideActionHeader,
|
||||
}: ActionAccordionFormProps) => {
|
||||
const {
|
||||
http,
|
||||
|
@ -295,15 +297,19 @@ export const ActionForm = ({
|
|||
</SectionLoading>
|
||||
) : (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
defaultMessage="Actions"
|
||||
id="xpack.triggersActionsUI.sections.actionForm.actionSectionsTitle"
|
||||
/>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
{!hideActionHeader && (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
defaultMessage="Actions"
|
||||
id="xpack.triggersActionsUI.sections.actionForm.actionSectionsTitle"
|
||||
/>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
)}
|
||||
{actionTypesIndex &&
|
||||
actions.map((actionItem: RuleAction, index: number) => {
|
||||
const actionConnector = connectors.find((field) => field.id === actionItem.id);
|
||||
|
|
|
@ -3521,6 +3521,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/osquery-io-ts-types@link:bazel-bin/packages/kbn-osquery-io-ts-types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/performance-testing-dataset-extractor@link:bazel-bin/packages/kbn-performance-testing-dataset-extractor":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
@ -7607,6 +7611,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__osquery-io-ts-types@link:bazel-bin/packages/kbn-osquery-io-ts-types/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__performance-testing-dataset-extractor@link:bazel-bin/packages/kbn-performance-testing-dataset-extractor/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue