Skip to content

Commit

Permalink
[Rules migration] Add install and install all migration rules end…
Browse files Browse the repository at this point in the history
…points (elastic#11283) (elastic#202026)

## Summary

[Internal link](elastic/security-team#10820)
to the feature details

With these changes we two new routes:

* `/internal/siem_migrations/rules/install`: allows to install a
specific set of migration rules
* `/internal/siem_migrations/rules/install_translated`: allows to
install all translated rules in specified migration

Also we connect these two new API calls with the "Install" button within
the "migration rules" table and the "Install translated rules" button on
the "SIEM migration rules" page.

### Screenshots


https://github.com/user-attachments/assets/29390d07-eab5-4157-8958-1e3f8459db09

---------

Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Sergi Massaneda <[email protected]>
  • Loading branch information
3 people authored Nov 29, 2024
1 parent 8d2e28a commit 07fbb92
Show file tree
Hide file tree
Showing 36 changed files with 1,361 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ import type {
GetRuleMigrationResourcesResponse,
GetRuleMigrationStatsRequestParamsInput,
GetRuleMigrationStatsResponse,
InstallMigrationRulesRequestParamsInput,
InstallMigrationRulesRequestBodyInput,
InstallMigrationRulesResponse,
InstallTranslatedMigrationRulesRequestParamsInput,
InstallTranslatedMigrationRulesResponse,
StartRuleMigrationRequestParamsInput,
StartRuleMigrationRequestBodyInput,
StartRuleMigrationResponse,
Expand Down Expand Up @@ -1559,6 +1564,22 @@ finalize it.
})
.catch(catchAxiosErrorFormatAndThrow);
}
/**
* Installs migration rules
*/
async installMigrationRules(props: InstallMigrationRulesProps) {
this.log.info(`${new Date().toISOString()} Calling API InstallMigrationRules`);
return this.kbnClient
.request<InstallMigrationRulesResponse>({
path: replaceParams('/internal/siem_migrations/rules/{migration_id}/install', props.params),
headers: {
[ELASTIC_HTTP_VERSION_HEADER]: '1',
},
method: 'POST',
body: props.body,
})
.catch(catchAxiosErrorFormatAndThrow);
}
/**
* Install and update all Elastic prebuilt detection rules and Timelines.
*/
Expand Down Expand Up @@ -1590,6 +1611,24 @@ finalize it.
})
.catch(catchAxiosErrorFormatAndThrow);
}
/**
* Installs all translated migration rules
*/
async installTranslatedMigrationRules(props: InstallTranslatedMigrationRulesProps) {
this.log.info(`${new Date().toISOString()} Calling API InstallTranslatedMigrationRules`);
return this.kbnClient
.request<InstallTranslatedMigrationRulesResponse>({
path: replaceParams(
'/internal/siem_migrations/rules/{migration_id}/install_translated',
props.params
),
headers: {
[ELASTIC_HTTP_VERSION_HEADER]: '1',
},
method: 'POST',
})
.catch(catchAxiosErrorFormatAndThrow);
}
async internalUploadAssetCriticalityRecords(props: InternalUploadAssetCriticalityRecordsProps) {
this.log.info(`${new Date().toISOString()} Calling API InternalUploadAssetCriticalityRecords`);
return this.kbnClient
Expand Down Expand Up @@ -2324,9 +2363,16 @@ export interface InitEntityEngineProps {
export interface InitEntityStoreProps {
body: InitEntityStoreRequestBodyInput;
}
export interface InstallMigrationRulesProps {
params: InstallMigrationRulesRequestParamsInput;
body: InstallMigrationRulesRequestBodyInput;
}
export interface InstallPrepackedTimelinesProps {
body: InstallPrepackedTimelinesRequestBodyInput;
}
export interface InstallTranslatedMigrationRulesProps {
params: InstallTranslatedMigrationRulesRequestParamsInput;
}
export interface InternalUploadAssetCriticalityRecordsProps {
attachment: FormData;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* 2.0.
*/

import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types';

export const SIEM_MIGRATIONS_PATH = '/internal/siem_migrations' as const;
export const SIEM_RULE_MIGRATIONS_PATH = `${SIEM_MIGRATIONS_PATH}/rules` as const;

Expand All @@ -14,6 +16,9 @@ export const SIEM_RULE_MIGRATION_START_PATH = `${SIEM_RULE_MIGRATION_PATH}/start
export const SIEM_RULE_MIGRATION_RETRY_PATH = `${SIEM_RULE_MIGRATION_PATH}/retry` as const;
export const SIEM_RULE_MIGRATION_STATS_PATH = `${SIEM_RULE_MIGRATION_PATH}/stats` as const;
export const SIEM_RULE_MIGRATION_STOP_PATH = `${SIEM_RULE_MIGRATION_PATH}/stop` as const;
export const SIEM_RULE_MIGRATION_INSTALL_PATH = `${SIEM_RULE_MIGRATION_PATH}/install` as const;
export const SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH =
`${SIEM_RULE_MIGRATION_PATH}/install_translated` as const;

export const SIEM_RULE_MIGRATION_RESOURCES_PATH = `${SIEM_RULE_MIGRATION_PATH}/resources` as const;

Expand All @@ -36,3 +41,6 @@ export enum SiemMigrationRuleTranslationResult {
PARTIAL = 'partial',
UNTRANSLATABLE = 'untranslatable',
}

export const DEFAULT_TRANSLATION_RISK_SCORE = 21;
export const DEFAULT_TRANSLATION_SEVERITY: Severity = 'low';
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,48 @@ export type GetRuleMigrationStatsRequestParamsInput = z.input<
export type GetRuleMigrationStatsResponse = z.infer<typeof GetRuleMigrationStatsResponse>;
export const GetRuleMigrationStatsResponse = RuleMigrationTaskStats;

export type InstallMigrationRulesRequestParams = z.infer<typeof InstallMigrationRulesRequestParams>;
export const InstallMigrationRulesRequestParams = z.object({
migration_id: NonEmptyString,
});
export type InstallMigrationRulesRequestParamsInput = z.input<
typeof InstallMigrationRulesRequestParams
>;

export type InstallMigrationRulesRequestBody = z.infer<typeof InstallMigrationRulesRequestBody>;
export const InstallMigrationRulesRequestBody = z.array(NonEmptyString);
export type InstallMigrationRulesRequestBodyInput = z.input<
typeof InstallMigrationRulesRequestBody
>;

export type InstallMigrationRulesResponse = z.infer<typeof InstallMigrationRulesResponse>;
export const InstallMigrationRulesResponse = z.object({
/**
* Indicates rules migrations have been installed.
*/
installed: z.boolean(),
});

export type InstallTranslatedMigrationRulesRequestParams = z.infer<
typeof InstallTranslatedMigrationRulesRequestParams
>;
export const InstallTranslatedMigrationRulesRequestParams = z.object({
migration_id: NonEmptyString,
});
export type InstallTranslatedMigrationRulesRequestParamsInput = z.input<
typeof InstallTranslatedMigrationRulesRequestParams
>;

export type InstallTranslatedMigrationRulesResponse = z.infer<
typeof InstallTranslatedMigrationRulesResponse
>;
export const InstallTranslatedMigrationRulesResponse = z.object({
/**
* Indicates rules migrations have been installed.
*/
installed: z.boolean(),
});

export type StartRuleMigrationRequestParams = z.infer<typeof StartRuleMigrationRequestParams>;
export const StartRuleMigrationRequestParams = z.object({
migration_id: NonEmptyString,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,73 @@ paths:
type: boolean
description: Indicates rules migrations have been updated.

/internal/siem_migrations/rules/{migration_id}/install:
post:
summary: Installs translated migration rules
operationId: InstallMigrationRules
x-codegen-enabled: true
description: Installs migration rules
tags:
- SIEM Rule Migrations
parameters:
- name: migration_id
in: path
required: true
schema:
description: The migration id to isnstall rules for
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
requestBody:
required: true
content:
application/json:
schema:
type: array
items:
description: The rule migration id
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
responses:
200:
description: Indicates rules migrations have been installed correctly.
content:
application/json:
schema:
type: object
required:
- installed
properties:
installed:
type: boolean
description: Indicates rules migrations have been installed.

/internal/siem_migrations/rules/{migration_id}/install_translated:
post:
summary: Installs all translated migration rules
operationId: InstallTranslatedMigrationRules
x-codegen-enabled: true
description: Installs all translated migration rules
tags:
- SIEM Rule Migrations
parameters:
- name: migration_id
in: path
required: true
schema:
description: The migration id to install translated rules for
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
responses:
200:
description: Indicates rules migrations have been installed correctly.
content:
application/json:
schema:
type: object
required:
- installed
properties:
installed:
type: boolean
description: Indicates rules migrations have been installed.

/internal/siem_migrations/rules/stats:
get:
summary: Retrieves the stats for all rule migrations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ import { KibanaServices } from '../../../common/lib/kibana';

import {
SIEM_RULE_MIGRATIONS_ALL_STATS_PATH,
SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH,
SIEM_RULE_MIGRATION_INSTALL_PATH,
SIEM_RULE_MIGRATION_PATH,
SIEM_RULE_MIGRATION_START_PATH,
} from '../../../../common/siem_migrations/constants';
import type {
GetAllStatsRuleMigrationResponse,
GetRuleMigrationResponse,
InstallTranslatedMigrationRulesResponse,
InstallMigrationRulesResponse,
StartRuleMigrationRequestBody,
} from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import type { InstallTranslatedRulesProps, InstallRulesProps } from '../types';

/**
* Retrieves the stats for all the existing migrations, aggregated by `migration_id`.
Expand Down Expand Up @@ -82,3 +87,33 @@ export const getRuleMigrations = async ({
{ method: 'GET', version: '1', signal }
);
};

export const installMigrationRules = async ({
migrationId,
ids,
signal,
}: InstallRulesProps): Promise<InstallMigrationRulesResponse> => {
return KibanaServices.get().http.fetch<InstallMigrationRulesResponse>(
replaceParams(SIEM_RULE_MIGRATION_INSTALL_PATH, { migration_id: migrationId }),
{
method: 'POST',
version: '1',
body: JSON.stringify(ids),
signal,
}
);
};

export const installTranslatedMigrationRules = async ({
migrationId,
signal,
}: InstallTranslatedRulesProps): Promise<InstallTranslatedMigrationRulesResponse> => {
return KibanaServices.get().http.fetch<InstallTranslatedMigrationRulesResponse>(
replaceParams(SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH, { migration_id: migrationId }),
{
method: 'POST',
version: '1',
signal,
}
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
*/

import type { UseQueryOptions } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { replaceParams } from '@kbn/openapi-common/shared';
import { useCallback } from 'react';
import { DEFAULT_QUERY_OPTIONS } from './constants';
import { getRuleMigrations } from '../api';
import type { GetRuleMigrationResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATION_PATH } from '../../../../../common/siem_migrations/constants';

export const useGetRuleMigrationsQuery = (
export const useGetMigrationRulesQuery = (
migrationId: string,
options?: UseQueryOptions<GetRuleMigrationResponse>
) => {
Expand All @@ -31,3 +32,23 @@ export const useGetRuleMigrationsQuery = (
}
);
};

/**
* We should use this hook to invalidate the rule migrations cache. For
* example, rule migrations mutations, like installing a rule, should lead to cache invalidation.
*
* @returns A rule migrations cache invalidation callback
*/
export const useInvalidateGetMigrationRulesQuery = (migrationId: string) => {
const queryClient = useQueryClient();

const SPECIFIC_MIGRATION_PATH = replaceParams(SIEM_RULE_MIGRATION_PATH, {
migration_id: migrationId,
});

return useCallback(() => {
queryClient.invalidateQueries(['GET', SPECIFIC_MIGRATION_PATH], {
refetchType: 'active',
});
}, [SPECIFIC_MIGRATION_PATH, queryClient]);
};
Original file line number Diff line number Diff line change
@@ -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 type { UseMutationOptions } from '@tanstack/react-query';
import { useMutation } from '@tanstack/react-query';
import type { InstallTranslatedMigrationRulesResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH } from '../../../../../common/siem_migrations/constants';
import { installTranslatedMigrationRules } from '../api';
import { useInvalidateGetMigrationRulesQuery } from './use_get_migration_rules_query';

export const INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY = [
'POST',
SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH,
];

export const useInstallAllMigrationRulesMutation = (
migrationId: string,
options?: UseMutationOptions<InstallTranslatedMigrationRulesResponse, Error>
) => {
const invalidateGetRuleMigrationsQuery = useInvalidateGetMigrationRulesQuery(migrationId);

return useMutation<InstallTranslatedMigrationRulesResponse, Error>(
() => installTranslatedMigrationRules({ migrationId }),
{
...options,
mutationKey: INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY,
onSettled: (...args) => {
invalidateGetRuleMigrationsQuery();

if (options?.onSettled) {
options.onSettled(...args);
}
},
}
);
};
Original file line number Diff line number Diff line change
@@ -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 { InstallMigrationRulesResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATION_INSTALL_PATH } from '../../../../../common/siem_migrations/constants';
import { installMigrationRules } from '../api';
import { useInvalidateGetMigrationRulesQuery } from './use_get_migration_rules_query';

export const INSTALL_MIGRATION_RULES_MUTATION_KEY = ['POST', SIEM_RULE_MIGRATION_INSTALL_PATH];

export const useInstallMigrationRulesMutation = (
migrationId: string,
options?: UseMutationOptions<InstallMigrationRulesResponse, Error, string[]>
) => {
const invalidateGetRuleMigrationsQuery = useInvalidateGetMigrationRulesQuery(migrationId);

return useMutation<InstallMigrationRulesResponse, Error, string[]>(
(ids: string[]) => installMigrationRules({ migrationId, ids }),
{
...options,
mutationKey: INSTALL_MIGRATION_RULES_MUTATION_KEY,
onSettled: (...args) => {
invalidateGetRuleMigrationsQuery();

if (options?.onSettled) {
options.onSettled(...args);
}
},
}
);
};
Loading

0 comments on commit 07fbb92

Please sign in to comment.