Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution] Allow users to edit related_integrations field for custom rules #178295

Merged
merged 56 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
0c45552
provide all integrations to UI
maximpn Mar 8, 2024
161f38c
update rules schema
maximpn Mar 8, 2024
10b6315
implement basic related integration editing
maximpn Mar 12, 2024
b381550
fix useManagedUser
maximpn Mar 13, 2024
aabd54b
provide non installed package version
maximpn Mar 13, 2024
d1276c6
add installed status
maximpn Mar 13, 2024
8c575f8
fix unit test
maximpn Mar 14, 2024
5d6640d
add extractIntegrations unit tests
maximpn Mar 14, 2024
524d786
implement related integrations editing design
maximpn Mar 29, 2024
65314de
fix version dependency validator
maximpn Mar 29, 2024
8527033
improve integration options rendering in different cases
maximpn Mar 30, 2024
e75c27e
mark fields as invalid in case of an error
maximpn Apr 1, 2024
1954d35
cover related integrations validator by tests
maximpn Apr 1, 2024
d11a49a
add related integrations functional tests
maximpn Apr 3, 2024
437c1d6
move createReactQueryWrapper to a common folder
maximpn Apr 5, 2024
5446238
revert select integration status colors
maximpn Apr 5, 2024
a57ca51
adds i18n for integration status
maximpn Apr 5, 2024
5dfe16e
adjust related integrations shown on the rule details page
maximpn Apr 5, 2024
697e22e
fix the endpoint to handle packages without policy templates
maximpn Apr 6, 2024
6b03684
return all integrations instead of only security category
maximpn Apr 6, 2024
49f922b
fix test ids
maximpn Apr 6, 2024
9477873
add a basic cypress test for related integrations editing
maximpn Apr 6, 2024
5e55189
remove unused translations
maximpn Apr 6, 2024
d2b04d5
fix integrations mock in a unit test
maximpn Apr 7, 2024
5c5bed1
fix unit tests
maximpn Apr 7, 2024
5fd1086
fix use_integrations unit tests
maximpn Apr 7, 2024
dba929e
add define rule form related integrations unit tests
maximpn Apr 8, 2024
f81c755
shorten an import path
maximpn Apr 8, 2024
abf5bf2
remove unnecessary comment
maximpn Apr 9, 2024
74deadc
remove unused translation
maximpn Apr 9, 2024
3afb234
fix related integrations cypress tests
maximpn Apr 9, 2024
3f305f8
sort integrations to display security category first
maximpn Apr 9, 2024
b2f0a86
fix a version dependency placeholder
maximpn Apr 9, 2024
a46d612
fix entity flyout cypress tests
maximpn Apr 9, 2024
5f0398b
update hint text
maximpn Apr 9, 2024
400b254
import prebuilt rules package name
maximpn Apr 9, 2024
ada58b0
replace version dependency text with version range
maximpn Apr 10, 2024
5889290
add functional tests
maximpn Apr 11, 2024
632dab4
correct related integrations help text
maximpn Apr 11, 2024
e048e57
add an explanation comment for POPOVER_WIDTH
maximpn Apr 12, 2024
4340f6c
simplify handleIntegrationChange
maximpn Apr 12, 2024
6c89788
avoid translations concatenation in the code
maximpn Apr 12, 2024
28d94bd
rename version range to version constraint
maximpn Apr 12, 2024
5e9a276
handle cases when users install a prerelease integration version
maximpn Apr 12, 2024
ec48cc8
fix combobox overflowing parent row
maximpn Apr 12, 2024
9ea7cc3
rename an updated test suite
maximpn Apr 15, 2024
06c5cef
add an extra integration test
maximpn Apr 15, 2024
bc55c1d
updates to match with new design
maximpn Apr 15, 2024
22d66d2
prevent selection of the same integration more than once
maximpn Apr 15, 2024
65bfebe
remove an unused param
maximpn Apr 15, 2024
1fde510
remove commented code
maximpn Apr 15, 2024
add0a1e
simplify RelatedIntegrationsHelpInfo with useToggle hook
maximpn Apr 15, 2024
0f8abc8
make related integrations user friendly by allowing to submit empty f…
maximpn Apr 16, 2024
d21bc23
fix label unit test
maximpn Apr 17, 2024
85edd93
remove related_integrations field from PrebuiltRuleAsset
maximpn Apr 29, 2024
82acefe
sort integrations by status
maximpn May 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/kbn-doc-links/src/get_doc_links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
privileges: `${SECURITY_SOLUTION_DOCS}endpoint-management-req.html`,
manageDetectionRules: `${SECURITY_SOLUTION_DOCS}rules-ui-management.html`,
createEsqlRuleType: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html#create-esql-rule`,
ruleUiAdvancedParams: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html#rule-ui-advanced-params`,
entityAnalytics: {
riskScorePrerequisites: `${SECURITY_SOLUTION_DOCS}ers-requirements.html`,
hostRiskScore: `${SECURITY_SOLUTION_DOCS}host-risk-score.html`,
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-doc-links/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ export interface DocLinks {
readonly privileges: string;
readonly manageDetectionRules: string;
readonly createEsqlRuleType: string;
readonly ruleUiAdvancedParams: string;
readonly entityAnalytics: {
readonly riskScorePrerequisites: string;
readonly hostRiskScore: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*/

import type { Integration } from '../model/integrations';

export interface GetAllIntegrationsResponse {
integrations: Integration[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
* 2.0.
*/

export * from './get_all_integrations/get_all_integrations_route';

export * from './get_installed_integrations/get_installed_integrations_route';
export * from './urls';

export * from './model/integrations';
export * from './model/installed_integrations';
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

// -------------------------------------------------------------------------------------------------
// Fleet Package Integration

/**
* Information about a Fleet integration including info about its package.
*
* @example
* {
* package_name: 'aws',
* package_title: 'AWS',
* integration_name: 'cloudtrail',
* integration_title: 'AWS CloudTrail',
* latest_package_version: '1.2.3',
* is_installed: false
* is_enabled: false
* }
*
* @example
* {
* package_name: 'aws',
* package_title: 'AWS',
* integration_name: 'cloudtrail',
* integration_title: 'AWS CloudTrail',
* latest_package_version: '1.16.1',
* installed_package_version: '1.16.1',
* is_installed: true
* is_enabled: false
* }
*
* @example
* {
* package_name: 'system',
* package_title: 'System',
* latest_package_version: '2.0.1',
* installed_package_version: '1.13.0',
* is_installed: true
* is_enabled: true
* }
*
*/
export interface Integration {
/**
* Name is a unique package id within a given cluster.
* There can't be 2 or more different packages with the same name.
* @example 'aws'
*/
package_name: string;

/**
* Title is a user-friendly name of the package that we show in the UI.
* @example 'AWS'
*/
package_title: string;

/**
* Whether the package is installed
*/
is_installed: boolean;

/**
* Whether this integration is enabled
*/
is_enabled: boolean;

/**
* Version of the latest available package. Semver-compatible.
* @example '1.2.3'
*/
latest_package_version: string;

/**
* Version of the installed package. Semver-compatible.
* @example '1.2.3'
*/
installed_package_version?: string;

/**
* Name identifies an integration within its package.
* Undefined when package name === integration name. This indicates that it's the only integration
* within this package.
* @example 'cloudtrail'
* @example undefined
*/
integration_name?: string;

/**
* Title is a user-friendly name of the integration that we show in the UI.
* Undefined when package name === integration name. This indicates that it's the only integration
* within this package.
* @example 'AWS CloudTrail'
* @example undefined
*/
integration_title?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@

import { INTERNAL_DETECTION_ENGINE_URL as INTERNAL_URL } from '../../../constants';

export const GET_ALL_INTEGRATIONS_URL = `${INTERNAL_URL}/fleet/integrations/all` as const;

export const GET_INSTALLED_INTEGRATIONS_URL =
`${INTERNAL_URL}/fleet/integrations/installed` as const;
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ import {
MaxSignals,
ThreatArray,
SetupGuide,
RelatedIntegrationArray,
RuleObjectId,
RuleSignatureId,
IsRuleImmutable,
RuleSource,
RelatedIntegrationArray,
RequiredFieldArray,
RuleQuery,
IndexPatternArray,
Expand Down Expand Up @@ -136,6 +136,7 @@ export const BaseDefaultableFields = z.object({
max_signals: MaxSignals.optional(),
threat: ThreatArray.optional(),
setup: SetupGuide.optional(),
related_integrations: RelatedIntegrationArray.optional(),
});

export type BaseCreateProps = z.infer<typeof BaseCreateProps>;
Expand Down Expand Up @@ -163,7 +164,6 @@ export const ResponseFields = z.object({
created_at: z.string().datetime(),
created_by: z.string(),
revision: z.number().int().min(0),
related_integrations: RelatedIntegrationArray,
required_fields: RequiredFieldArray,
execution_summary: RuleExecutionSummary.optional(),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ components:
setup:
$ref: './common_attributes.schema.yaml#/components/schemas/SetupGuide'

related_integrations:
$ref: './common_attributes.schema.yaml#/components/schemas/RelatedIntegrationArray'

BaseCreateProps:
x-inline: true
allOf:
Expand Down Expand Up @@ -178,13 +181,11 @@ components:
revision:
type: integer
minimum: 0
# NOTE: For now, Related Integrations and Required Fields are
# NOTE: For now, Required Fields are
# supported for prebuilt rules only. We don't want to allow users to edit these 3
# fields via the API. If we added them to baseParams.defaultable, they would
# become a part of the request schema as optional fields. This is why we add them
# here, in order to add them only to the response schema.
related_integrations:
$ref: './common_attributes.schema.yaml#/components/schemas/RelatedIntegrationArray'
required_fields:
$ref: './common_attributes.schema.yaml#/components/schemas/RequiredFieldArray'
execution_summary:
Expand Down
Original file line number Diff line number Diff line change
@@ -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 React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

export function createReactQueryWrapper(): React.FC {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
// Turn retries off, otherwise we won't be able to test errors
retry: false,
},
},
});

// eslint-disable-next-line react/display-name
return ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export * from './test_providers';
export * from './timeline_results';
export * from './utils';
export * from './create_store';
export * from './create_react_query_wrapper';
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,49 @@
* 2.0.
*/

import type { GetInstalledIntegrationsResponse } from '../../../../../common/api/detection_engine/fleet_integrations';
import type {
GetAllIntegrationsResponse,
GetInstalledIntegrationsResponse,
} from '../../../../../common/api/detection_engine/fleet_integrations';
import type {
FetchAllIntegrationsArgs,
FetchInstalledIntegrationsArgs,
IFleetIntegrationsApiClient,
} from '../api_client_interface';

export const fleetIntegrationsApi: jest.Mocked<IFleetIntegrationsApiClient> = {
fetchAllIntegrations: jest
.fn<Promise<GetAllIntegrationsResponse>, [FetchAllIntegrationsArgs]>()
.mockResolvedValue({
integrations: [
{
package_name: 'o365',
package_title: 'Microsoft 365',
latest_package_version: '1.2.0',
installed_package_version: '1.0.0',
is_installed: false,
is_enabled: false,
},
{
package_name: 'atlassian_bitbucket',
package_title: 'Atlassian Bitbucket',
latest_package_version: '1.0.1',
installed_package_version: '1.0.1',
integration_name: 'audit',
integration_title: 'Audit Logs',
is_installed: true,
is_enabled: true,
},
{
package_name: 'system',
package_title: 'System',
latest_package_version: '1.6.4',
installed_package_version: '1.6.4',
is_installed: true,
is_enabled: true,
},
],
}),
fetchInstalledIntegrations: jest
.fn<Promise<GetInstalledIntegrationsResponse>, [FetchInstalledIntegrationsArgs]>()
.mockResolvedValue({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,31 @@
* 2.0.
*/

import type { GetInstalledIntegrationsResponse } from '../../../../common/api/detection_engine/fleet_integrations';
import { GET_INSTALLED_INTEGRATIONS_URL } from '../../../../common/api/detection_engine/fleet_integrations';
import type {
GetAllIntegrationsResponse,
GetInstalledIntegrationsResponse,
} from '../../../../common/api/detection_engine/fleet_integrations';
import {
GET_ALL_INTEGRATIONS_URL,
GET_INSTALLED_INTEGRATIONS_URL,
} from '../../../../common/api/detection_engine/fleet_integrations';
import { KibanaServices } from '../../../common/lib/kibana';

import type {
FetchAllIntegrationsArgs,
FetchInstalledIntegrationsArgs,
IFleetIntegrationsApiClient,
} from './api_client_interface';

export const fleetIntegrationsApi: IFleetIntegrationsApiClient = {
fetchAllIntegrations: (args: FetchAllIntegrationsArgs): Promise<GetAllIntegrationsResponse> => {
return http().fetch<GetAllIntegrationsResponse>(GET_ALL_INTEGRATIONS_URL, {
method: 'GET',
version: '1',
signal: args.signal,
});
},

fetchInstalledIntegrations: (
args: FetchInstalledIntegrationsArgs
): Promise<GetInstalledIntegrationsResponse> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@
* 2.0.
*/

import type { GetInstalledIntegrationsResponse } from '../../../../common/api/detection_engine/fleet_integrations';
import type {
GetInstalledIntegrationsResponse,
GetAllIntegrationsResponse,
} from '../../../../common/api/detection_engine/fleet_integrations';

export interface IFleetIntegrationsApiClient {
/**
* Fetch all integrations with installed and enabled statuses
*
* @throws An error if response is not OK
*/
fetchAllIntegrations(args: FetchAllIntegrationsArgs): Promise<GetAllIntegrationsResponse>;

/**
* Fetch all installed integrations.
* @throws An error if response is not OK
Expand All @@ -17,6 +27,13 @@ export interface IFleetIntegrationsApiClient {
): Promise<GetInstalledIntegrationsResponse>;
}

export interface FetchAllIntegrationsArgs {
/**
* Optional signal for cancelling the request.
*/
signal?: AbortSignal;
}

export interface FetchInstalledIntegrationsArgs {
/**
* Array of Fleet packages to filter for.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const DEFAULT_RELATED_INTEGRATION = { package: '', version: '' };
Original file line number Diff line number Diff line change
@@ -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 { RelatedIntegrations } from './related_integrations';
Loading