Skip to content

Commit

Permalink
[Rules migration] Add pagination functionality to rules migration tab…
Browse files Browse the repository at this point in the history
…le (elastic#11313) (elastic#202494)

## Summary

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

With these changes we add pagination functionality for the rules
migration table. This way we will improve the performance within the
page.

Also, added as part of these PR:
* moved `install` and `install_translated` routes to the `rules/api`
folder; before those were located in `rules/api/rules` and made
confusion
* a new `translation_stats` route to return stats for the specific
migration about the translated rules, like `total` number of the rules,
and number of `prebuilt`, `custom` and `installable` rules
* add `Updated` table column
* small UI fixes:
  * use correct icon for "SIEM rule migration"
* do not remove "Install translated rules" button and rather disable it
when there are no installable rules
  * do not allow user to update translation status via UI

---------

Co-authored-by: kibanamachine <[email protected]>
(cherry picked from commit a662233)

# Conflicts:
#	x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts
#	x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts
#	x-pack/test/api_integration/services/security_solution_api.gen.ts
  • Loading branch information
e40pud committed Dec 3, 2024
1 parent f3da0dc commit 826a4d1
Show file tree
Hide file tree
Showing 40 changed files with 846 additions and 236 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,16 @@ import type {
CreateRuleMigrationRequestBodyInput,
CreateRuleMigrationResponse,
GetAllStatsRuleMigrationResponse,
GetRuleMigrationRequestQueryInput,
GetRuleMigrationRequestParamsInput,
GetRuleMigrationResponse,
GetRuleMigrationResourcesRequestQueryInput,
GetRuleMigrationResourcesRequestParamsInput,
GetRuleMigrationResourcesResponse,
GetRuleMigrationStatsRequestParamsInput,
GetRuleMigrationStatsResponse,
GetRuleMigrationTranslationStatsRequestParamsInput,
GetRuleMigrationTranslationStatsResponse,
InstallMigrationRulesRequestParamsInput,
InstallMigrationRulesRequestBodyInput,
InstallMigrationRulesResponse,
Expand Down Expand Up @@ -1462,6 +1465,8 @@ finalize it.
[ELASTIC_HTTP_VERSION_HEADER]: '1',
},
method: 'GET',

query: props.query,
})
.catch(catchAxiosErrorFormatAndThrow);
}
Expand Down Expand Up @@ -1500,6 +1505,27 @@ finalize it.
})
.catch(catchAxiosErrorFormatAndThrow);
}
/**
* Retrieves the translation stats of a SIEM rules migration using the migration id provided
*/
async getRuleMigrationTranslationStats(props: GetRuleMigrationTranslationStatsProps) {
this.log.info(`${new Date().toISOString()} Calling API GetRuleMigrationTranslationStats`);
return this.kbnClient
.request<GetRuleMigrationTranslationStatsResponse>({
path: replaceParams(
'/internal/siem_migrations/rules/{migration_id}/translation_stats',
props.params
),
headers: {
[ELASTIC_HTTP_VERSION_HEADER]: '1',
},
method: 'GET',
})
.catch(catchAxiosErrorFormatAndThrow);
}
/**
* Get the details of an existing saved Timeline or Timeline template.
*/
async getTimeline(props: GetTimelineProps) {
this.log.info(`${new Date().toISOString()} Calling API GetTimeline`);
return this.kbnClient
Expand Down Expand Up @@ -2366,6 +2392,7 @@ export interface GetRuleExecutionResultsProps {
params: GetRuleExecutionResultsRequestParamsInput;
}
export interface GetRuleMigrationProps {
query: GetRuleMigrationRequestQueryInput;
params: GetRuleMigrationRequestParamsInput;
}
export interface GetRuleMigrationResourcesProps {
Expand All @@ -2375,6 +2402,9 @@ export interface GetRuleMigrationResourcesProps {
export interface GetRuleMigrationStatsProps {
params: GetRuleMigrationStatsRequestParamsInput;
}
export interface GetRuleMigrationTranslationStatsProps {
params: GetRuleMigrationTranslationStatsRequestParamsInput;
}
export interface GetTimelineProps {
query: GetTimelineRequestQueryInput;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const SIEM_RULE_MIGRATION_PATH = `${SIEM_RULE_MIGRATIONS_PATH}/{migration
export const SIEM_RULE_MIGRATION_START_PATH = `${SIEM_RULE_MIGRATION_PATH}/start` as const;
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_TRANSLATION_STATS_PATH =
`${SIEM_RULE_MIGRATION_PATH}/translation_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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
RuleMigrationComments,
RuleMigrationTaskStats,
RuleMigration,
RuleMigrationTranslationStats,
RuleMigrationResourceData,
RuleMigrationResourceType,
RuleMigrationResource,
Expand All @@ -44,6 +45,13 @@ export const CreateRuleMigrationResponse = z.object({

export type GetAllStatsRuleMigrationResponse = z.infer<typeof GetAllStatsRuleMigrationResponse>;
export const GetAllStatsRuleMigrationResponse = z.array(RuleMigrationTaskStats);
export type GetRuleMigrationRequestQuery = z.infer<typeof GetRuleMigrationRequestQuery>;
export const GetRuleMigrationRequestQuery = z.object({
page: z.coerce.number().optional(),
per_page: z.coerce.number().optional(),
search_term: z.string().optional(),
});
export type GetRuleMigrationRequestQueryInput = z.input<typeof GetRuleMigrationRequestQuery>;

export type GetRuleMigrationRequestParams = z.infer<typeof GetRuleMigrationRequestParams>;
export const GetRuleMigrationRequestParams = z.object({
Expand All @@ -52,7 +60,13 @@ export const GetRuleMigrationRequestParams = z.object({
export type GetRuleMigrationRequestParamsInput = z.input<typeof GetRuleMigrationRequestParams>;

export type GetRuleMigrationResponse = z.infer<typeof GetRuleMigrationResponse>;
export const GetRuleMigrationResponse = z.array(RuleMigration);
export const GetRuleMigrationResponse = z.object({
/**
* The total number of rules in migration.
*/
total: z.number(),
data: z.array(RuleMigration),
});
export type GetRuleMigrationResourcesRequestQuery = z.infer<
typeof GetRuleMigrationResourcesRequestQuery
>;
Expand Down Expand Up @@ -88,6 +102,21 @@ export type GetRuleMigrationStatsRequestParamsInput = z.input<
export type GetRuleMigrationStatsResponse = z.infer<typeof GetRuleMigrationStatsResponse>;
export const GetRuleMigrationStatsResponse = RuleMigrationTaskStats;

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

export type GetRuleMigrationTranslationStatsResponse = z.infer<
typeof GetRuleMigrationTranslationStatsResponse
>;
export const GetRuleMigrationTranslationStatsResponse = RuleMigrationTranslationStats;

export type InstallMigrationRulesRequestParams = z.infer<typeof InstallMigrationRulesRequestParams>;
export const InstallMigrationRulesRequestParams = z.object({
migration_id: NonEmptyString,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,40 @@ paths:
schema:
description: The migration id to start
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
- name: page
in: query
required: false
schema:
type: number
- name: per_page
in: query
required: false
schema:
type: number
- name: search_term
in: query
required: false
schema:
type: string

responses:
200:
description: Indicates rule migration have been retrieved correctly.
content:
application/json:
schema:
type: array
items:
$ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigration'
type: object
required:
- total
- data
properties:
total:
type: number
description: The total number of rules in migration.
data:
type: array
items:
$ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigration'
204:
description: Indicates the migration id was not found.

Expand Down Expand Up @@ -256,7 +281,7 @@ paths:
in: path
required: true
schema:
description: The migration id to start
description: The migration id to fetch stats for
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
responses:
200:
Expand All @@ -268,6 +293,31 @@ paths:
204:
description: Indicates the migration id was not found.

/internal/siem_migrations/rules/{migration_id}/translation_stats:
get:
summary: Gets a rule migration translation stats
operationId: GetRuleMigrationTranslationStats
x-codegen-enabled: true
description: Retrieves the translation stats of a SIEM rules migration using the migration id provided
tags:
- SIEM Rule Migrations
parameters:
- name: migration_id
in: path
required: true
schema:
description: The migration id to fetch translation stats for
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
responses:
200:
description: Indicates the migration stats has been retrieved correctly.
content:
application/json:
schema:
$ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationTranslationStats'
204:
description: Indicates the migration id was not found.

/internal/siem_migrations/rules/{migration_id}/stop:
put:
summary: Stops an existing rule migration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,38 @@ export const RuleMigrationTaskStats = z.object({
last_updated_at: z.string(),
});

/**
* The rule migration translation stats object.
*/
export type RuleMigrationTranslationStats = z.infer<typeof RuleMigrationTranslationStats>;
export const RuleMigrationTranslationStats = z.object({
/**
* The migration id
*/
id: NonEmptyString,
/**
* The rules migration translation stats.
*/
rules: z.object({
/**
* The total number of rules to migrate.
*/
total: z.number().int(),
/**
* The number of rules that matched Elastic prebuilt rules.
*/
prebuilt: z.number().int(),
/**
* The number of rules that did not match Elastic prebuilt rules and will be installed as custom rules.
*/
custom: z.number().int(),
/**
* The number of rules that can be installed.
*/
installable: z.number().int(),
}),
});

/**
* The type of the rule migration resource.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,39 @@ components:
- running
- stopped
- finished


RuleMigrationTranslationStats:
type: object
description: The rule migration translation stats object.
required:
- id
- rules
properties:
id:
description: The migration id
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
rules:
type: object
description: The rules migration translation stats.
required:
- total
- prebuilt
- custom
- installable
properties:
total:
type: integer
description: The total number of rules to migrate.
prebuilt:
type: integer
description: The number of rules that matched Elastic prebuilt rules.
custom:
type: integer
description: The number of rules that did not match Elastic prebuilt rules and will be installed as custom rules.
installable:
type: integer
description: The number of rules that can be installed.

RuleMigrationTranslationResult:
type: string
description: The rule translation result.
Expand Down
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 { SVGProps } from 'react';
import React from 'react';
export const SiemMigrationsIcon: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={16}
height={16}
fill="none"
viewBox="0 0 32 32"
{...props}
>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_2763_341531)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10 12C15.4292 12 19.8479 16.3267 19.9962 21.7201L20 22V23H11V32H10C4.47715 32 0 27.5228 0 22C0 16.4772 4.47715 12 10 12ZM9 21L9.00005 14.0619C5.05371 14.554 2 17.9204 2 22C2 25.9928 4.92513 29.3024 8.74934 29.9028L9 29.9381V21ZM11 21L11.0009 14.062L11.258 14.0983C14.7544 14.6506 17.4976 17.4677 17.9381 21H11Z"
fill="#343741"
/>
<path d="M26 22C26 13.1634 18.8366 6 10 6V8C17.732 8 24 14.268 24 22H26Z" fill="#007871" />
<path
d="M32 22C32 9.84974 22.1503 0 10 0V2C21.0457 2 30 10.9543 30 22H32Z"
fill="#007871"
/>
</g>
<defs>
<clipPath id="clip0_2763_341531">
<rect width="32" height="32" fill="white" />
</clipPath>
</defs>
</svg>
</svg>
);
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import {
} from '../../common/constants';
import { SIEM_MIGRATIONS_RULES } from '../app/translations';
import type { LinkItem } from '../common/links/types';
import { IconConsoleCloud } from '../common/icons/console_cloud';
import { SiemMigrationsIcon } from '../common/icons/siem_migrations';

export const siemMigrationsLinks: LinkItem = {
id: SecurityPageName.siemMigrationsRules,
title: SIEM_MIGRATIONS_RULES,
description: i18n.translate('xpack.securitySolution.appLinks.siemMigrationsRulesDescription', {
defaultMessage: 'SIEM Rules Migrations.',
}),
landingIcon: IconConsoleCloud,
landingIcon: SiemMigrationsIcon,
path: SIEM_MIGRATIONS_RULES_PATH,
capabilities: [`${SERVER_APP_ID}.show`],
skipUrlState: true,
Expand Down
Loading

0 comments on commit 826a4d1

Please sign in to comment.