mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Rules migration] Add rules migrations update route (#11209) (#200815)](https://github.com/elastic/kibana/pull/200815) <!--- Backport version: 8.9.8 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Ievgen Sorokopud","email":"ievgen.sorokopud@elastic.co"},"sourceCommit":{"committedDate":"2024-11-20T12:36:37Z","message":"[Rules migration] Add rules migrations update route (#11209) (#200815)\n\n## Summary\r\n\r\nChanges in this PR:\r\n* Added `update` route to handle bulk rule migrations docs updates\r\n* Exposed `id` field in `RuleMigration` object needed for ES bulk update\r\noperation\r\n* Updated SIEM migrations schemas to use `NonEmptyString` when it is\r\nneeded\r\n\r\n## Testing locally\r\n\r\nEnable the flag\r\n```\r\nxpack.securitySolution.enableExperimental: ['siemMigrationsEnabled']\r\n```\r\n\r\nCreate and start a rule migration. Then use `update` API to updated\r\ncorresponding docs.\r\n\r\ncURL request examples:\r\n\r\n<details>\r\n <summary>Rules migration `create` POST request</summary>\r\n\r\n```\r\ncurl --location --request POST 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \\\r\n--header 'Content-Type: application/json' \\\r\n--data '[\r\n {\r\n \"id\": \"f8c325ea-506e-4105-8ccf-da1492e90115\",\r\n \"vendor\": \"splunk\",\r\n \"title\": \"Linux Auditd Add User Account Type\",\r\n \"description\": \"The following analytic detects the suspicious add user account type. This behavior is critical for a SOC to monitor because it may indicate attempts to gain unauthorized access or maintain control over a system. Such actions could be signs of malicious activity. If confirmed, this could lead to serious consequences, including a compromised system, unauthorized access to sensitive data, or even a wider breach affecting the entire network. Detecting and responding to these signs early is essential to prevent potential security incidents.\",\r\n \"query\": \"sourcetype=\\\"linux:audit\\\" type=ADD_USER \\n| rename hostname as dest \\n| stats count min(_time) as firstTime max(_time) as lastTime by exe pid dest res UID type \\n| `security_content_ctime(firstTime)` \\n| `security_content_ctime(lastTime)`\\n| search *\",\r\n \"query_language\":\"spl\",\r\n \"mitre_attack_ids\": [\r\n \"T1136\"\r\n ]\r\n },\r\n {\r\n \"id\": \"7b87c556-0ca4-47e0-b84c-6cd62a0a3e90\",\r\n \"vendor\": \"splunk\",\r\n \"title\": \"Linux Auditd Change File Owner To Root\",\r\n \"description\": \"The following analytic detects the use of the '\\''chown'\\'' command to change a file owner to '\\''root'\\'' on a Linux system. It leverages Linux Auditd telemetry, specifically monitoring command-line executions and process details. This activity is significant as it may indicate an attempt to escalate privileges by adversaries, malware, or red teamers. If confirmed malicious, this action could allow an attacker to gain root-level access, leading to full control over the compromised host and potential persistence within the environment.\",\r\n \"query\": \"`linux_auditd` `linux_auditd_normalized_proctitle_process`\\r\\n| rename host as dest \\r\\n| where LIKE (process_exec, \\\"%chown %root%\\\") \\r\\n| stats count min(_time) as firstTime max(_time) as lastTime by process_exec proctitle normalized_proctitle_delimiter dest \\r\\n| `security_content_ctime(firstTime)` \\r\\n| `security_content_ctime(lastTime)`\\r\\n| `linux_auditd_change_file_owner_to_root_filter`\",\r\n \"query_language\": \"spl\",\r\n \"mitre_attack_ids\": [\r\n \"T1222\"\r\n ]\r\n }\r\n]'\r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration `start` task request</summary>\r\n\r\n- Assuming the connector `azureOpenAiGPT4o` is already created in the\r\nlocal environment.\r\n- Using the {{`migration_id`}} from the first POST request response\r\n\r\n```\r\ncurl --location --request PUT 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules/{{migration_id}}/start' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \\\r\n--header 'Content-Type: application/json' \\\r\n--data '{\r\n \"connectorId\": \"azureOpenAiGPT4o\"\r\n}'\r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration rules documents request</summary>\r\n\r\n- Using the {{`migration_id`}} from the first POST request response.\r\n\r\n```\r\ncurl --location --request GET 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules/{{migration_id}}' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration `update` PUT request</summary>\r\n\r\n- Using the {{`rule_migration_id_1`}} and {{`rule_migration_id_2`}} from\r\nprevious GET request response\r\n\r\n```\r\ncurl --location --request PUT 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \r\n--data '[\r\n {\r\n \"comments\": [\r\n \"## Migration Summary\\n- The `FROM` command is used to select the `logs-*` index pattern.\\n- The `RENAME` command is used to rename the `host` field to `dest`.\\n- The `WHERE` command filters the rows where `process_exec` contains the pattern `*chown *root*`.\\n- The `STATS` command is used to aggregate the data, counting the number of occurrences and finding the minimum and maximum timestamps, grouped by `process_exec`, `proctitle`, `normalized_proctitle_delimiter`, and `dest`.\\n- The macros `security_content_ctime` and `linux_auditd_change_file_owner_to_root_filter` are placeholders for the corresponding Splunk macros.\",\r\n \"Additional comment 2.0\"\r\n ],\r\n \"translation_result\": \"full\",\r\n \"id\": \"{{rule_migration_id_1}}\"\r\n },\r\n {\r\n \"created_by\": \"elastic2.0\",\r\n \"elastic_rule\": {\r\n \"severity\": \"high\",\r\n \"title\": \"Linux Auditd Change File Owner To Root (UPDATED)\"\r\n },\r\n \"id\": \"{{rule_migration_id_2}}\"\r\n }\r\n]'\r\n```\r\n</details>\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"f6ac2cf8603ca633070e719f69b4fcef45ea92cb","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Threat Hunting","Team: SecuritySolution","backport:prev-minor"],"number":200815,"url":"https://github.com/elastic/kibana/pull/200815","mergeCommit":{"message":"[Rules migration] Add rules migrations update route (#11209) (#200815)\n\n## Summary\r\n\r\nChanges in this PR:\r\n* Added `update` route to handle bulk rule migrations docs updates\r\n* Exposed `id` field in `RuleMigration` object needed for ES bulk update\r\noperation\r\n* Updated SIEM migrations schemas to use `NonEmptyString` when it is\r\nneeded\r\n\r\n## Testing locally\r\n\r\nEnable the flag\r\n```\r\nxpack.securitySolution.enableExperimental: ['siemMigrationsEnabled']\r\n```\r\n\r\nCreate and start a rule migration. Then use `update` API to updated\r\ncorresponding docs.\r\n\r\ncURL request examples:\r\n\r\n<details>\r\n <summary>Rules migration `create` POST request</summary>\r\n\r\n```\r\ncurl --location --request POST 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \\\r\n--header 'Content-Type: application/json' \\\r\n--data '[\r\n {\r\n \"id\": \"f8c325ea-506e-4105-8ccf-da1492e90115\",\r\n \"vendor\": \"splunk\",\r\n \"title\": \"Linux Auditd Add User Account Type\",\r\n \"description\": \"The following analytic detects the suspicious add user account type. This behavior is critical for a SOC to monitor because it may indicate attempts to gain unauthorized access or maintain control over a system. Such actions could be signs of malicious activity. If confirmed, this could lead to serious consequences, including a compromised system, unauthorized access to sensitive data, or even a wider breach affecting the entire network. Detecting and responding to these signs early is essential to prevent potential security incidents.\",\r\n \"query\": \"sourcetype=\\\"linux:audit\\\" type=ADD_USER \\n| rename hostname as dest \\n| stats count min(_time) as firstTime max(_time) as lastTime by exe pid dest res UID type \\n| `security_content_ctime(firstTime)` \\n| `security_content_ctime(lastTime)`\\n| search *\",\r\n \"query_language\":\"spl\",\r\n \"mitre_attack_ids\": [\r\n \"T1136\"\r\n ]\r\n },\r\n {\r\n \"id\": \"7b87c556-0ca4-47e0-b84c-6cd62a0a3e90\",\r\n \"vendor\": \"splunk\",\r\n \"title\": \"Linux Auditd Change File Owner To Root\",\r\n \"description\": \"The following analytic detects the use of the '\\''chown'\\'' command to change a file owner to '\\''root'\\'' on a Linux system. It leverages Linux Auditd telemetry, specifically monitoring command-line executions and process details. This activity is significant as it may indicate an attempt to escalate privileges by adversaries, malware, or red teamers. If confirmed malicious, this action could allow an attacker to gain root-level access, leading to full control over the compromised host and potential persistence within the environment.\",\r\n \"query\": \"`linux_auditd` `linux_auditd_normalized_proctitle_process`\\r\\n| rename host as dest \\r\\n| where LIKE (process_exec, \\\"%chown %root%\\\") \\r\\n| stats count min(_time) as firstTime max(_time) as lastTime by process_exec proctitle normalized_proctitle_delimiter dest \\r\\n| `security_content_ctime(firstTime)` \\r\\n| `security_content_ctime(lastTime)`\\r\\n| `linux_auditd_change_file_owner_to_root_filter`\",\r\n \"query_language\": \"spl\",\r\n \"mitre_attack_ids\": [\r\n \"T1222\"\r\n ]\r\n }\r\n]'\r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration `start` task request</summary>\r\n\r\n- Assuming the connector `azureOpenAiGPT4o` is already created in the\r\nlocal environment.\r\n- Using the {{`migration_id`}} from the first POST request response\r\n\r\n```\r\ncurl --location --request PUT 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules/{{migration_id}}/start' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \\\r\n--header 'Content-Type: application/json' \\\r\n--data '{\r\n \"connectorId\": \"azureOpenAiGPT4o\"\r\n}'\r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration rules documents request</summary>\r\n\r\n- Using the {{`migration_id`}} from the first POST request response.\r\n\r\n```\r\ncurl --location --request GET 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules/{{migration_id}}' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration `update` PUT request</summary>\r\n\r\n- Using the {{`rule_migration_id_1`}} and {{`rule_migration_id_2`}} from\r\nprevious GET request response\r\n\r\n```\r\ncurl --location --request PUT 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \r\n--data '[\r\n {\r\n \"comments\": [\r\n \"## Migration Summary\\n- The `FROM` command is used to select the `logs-*` index pattern.\\n- The `RENAME` command is used to rename the `host` field to `dest`.\\n- The `WHERE` command filters the rows where `process_exec` contains the pattern `*chown *root*`.\\n- The `STATS` command is used to aggregate the data, counting the number of occurrences and finding the minimum and maximum timestamps, grouped by `process_exec`, `proctitle`, `normalized_proctitle_delimiter`, and `dest`.\\n- The macros `security_content_ctime` and `linux_auditd_change_file_owner_to_root_filter` are placeholders for the corresponding Splunk macros.\",\r\n \"Additional comment 2.0\"\r\n ],\r\n \"translation_result\": \"full\",\r\n \"id\": \"{{rule_migration_id_1}}\"\r\n },\r\n {\r\n \"created_by\": \"elastic2.0\",\r\n \"elastic_rule\": {\r\n \"severity\": \"high\",\r\n \"title\": \"Linux Auditd Change File Owner To Root (UPDATED)\"\r\n },\r\n \"id\": \"{{rule_migration_id_2}}\"\r\n }\r\n]'\r\n```\r\n</details>\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"f6ac2cf8603ca633070e719f69b4fcef45ea92cb"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/200815","number":200815,"mergeCommit":{"message":"[Rules migration] Add rules migrations update route (#11209) (#200815)\n\n## Summary\r\n\r\nChanges in this PR:\r\n* Added `update` route to handle bulk rule migrations docs updates\r\n* Exposed `id` field in `RuleMigration` object needed for ES bulk update\r\noperation\r\n* Updated SIEM migrations schemas to use `NonEmptyString` when it is\r\nneeded\r\n\r\n## Testing locally\r\n\r\nEnable the flag\r\n```\r\nxpack.securitySolution.enableExperimental: ['siemMigrationsEnabled']\r\n```\r\n\r\nCreate and start a rule migration. Then use `update` API to updated\r\ncorresponding docs.\r\n\r\ncURL request examples:\r\n\r\n<details>\r\n <summary>Rules migration `create` POST request</summary>\r\n\r\n```\r\ncurl --location --request POST 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \\\r\n--header 'Content-Type: application/json' \\\r\n--data '[\r\n {\r\n \"id\": \"f8c325ea-506e-4105-8ccf-da1492e90115\",\r\n \"vendor\": \"splunk\",\r\n \"title\": \"Linux Auditd Add User Account Type\",\r\n \"description\": \"The following analytic detects the suspicious add user account type. This behavior is critical for a SOC to monitor because it may indicate attempts to gain unauthorized access or maintain control over a system. Such actions could be signs of malicious activity. If confirmed, this could lead to serious consequences, including a compromised system, unauthorized access to sensitive data, or even a wider breach affecting the entire network. Detecting and responding to these signs early is essential to prevent potential security incidents.\",\r\n \"query\": \"sourcetype=\\\"linux:audit\\\" type=ADD_USER \\n| rename hostname as dest \\n| stats count min(_time) as firstTime max(_time) as lastTime by exe pid dest res UID type \\n| `security_content_ctime(firstTime)` \\n| `security_content_ctime(lastTime)`\\n| search *\",\r\n \"query_language\":\"spl\",\r\n \"mitre_attack_ids\": [\r\n \"T1136\"\r\n ]\r\n },\r\n {\r\n \"id\": \"7b87c556-0ca4-47e0-b84c-6cd62a0a3e90\",\r\n \"vendor\": \"splunk\",\r\n \"title\": \"Linux Auditd Change File Owner To Root\",\r\n \"description\": \"The following analytic detects the use of the '\\''chown'\\'' command to change a file owner to '\\''root'\\'' on a Linux system. It leverages Linux Auditd telemetry, specifically monitoring command-line executions and process details. This activity is significant as it may indicate an attempt to escalate privileges by adversaries, malware, or red teamers. If confirmed malicious, this action could allow an attacker to gain root-level access, leading to full control over the compromised host and potential persistence within the environment.\",\r\n \"query\": \"`linux_auditd` `linux_auditd_normalized_proctitle_process`\\r\\n| rename host as dest \\r\\n| where LIKE (process_exec, \\\"%chown %root%\\\") \\r\\n| stats count min(_time) as firstTime max(_time) as lastTime by process_exec proctitle normalized_proctitle_delimiter dest \\r\\n| `security_content_ctime(firstTime)` \\r\\n| `security_content_ctime(lastTime)`\\r\\n| `linux_auditd_change_file_owner_to_root_filter`\",\r\n \"query_language\": \"spl\",\r\n \"mitre_attack_ids\": [\r\n \"T1222\"\r\n ]\r\n }\r\n]'\r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration `start` task request</summary>\r\n\r\n- Assuming the connector `azureOpenAiGPT4o` is already created in the\r\nlocal environment.\r\n- Using the {{`migration_id`}} from the first POST request response\r\n\r\n```\r\ncurl --location --request PUT 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules/{{migration_id}}/start' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \\\r\n--header 'Content-Type: application/json' \\\r\n--data '{\r\n \"connectorId\": \"azureOpenAiGPT4o\"\r\n}'\r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration rules documents request</summary>\r\n\r\n- Using the {{`migration_id`}} from the first POST request response.\r\n\r\n```\r\ncurl --location --request GET 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules/{{migration_id}}' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \r\n```\r\n</details>\r\n\r\n<details>\r\n <summary>Rules migration `update` PUT request</summary>\r\n\r\n- Using the {{`rule_migration_id_1`}} and {{`rule_migration_id_2`}} from\r\nprevious GET request response\r\n\r\n```\r\ncurl --location --request PUT 'http://elastic:changeme@localhost:5601/internal/siem_migrations/rules' \\\r\n--header 'kbn-xsrf;' \\\r\n--header 'x-elastic-internal-origin: security-solution' \\\r\n--header 'elastic-api-version: 1' \r\n--data '[\r\n {\r\n \"comments\": [\r\n \"## Migration Summary\\n- The `FROM` command is used to select the `logs-*` index pattern.\\n- The `RENAME` command is used to rename the `host` field to `dest`.\\n- The `WHERE` command filters the rows where `process_exec` contains the pattern `*chown *root*`.\\n- The `STATS` command is used to aggregate the data, counting the number of occurrences and finding the minimum and maximum timestamps, grouped by `process_exec`, `proctitle`, `normalized_proctitle_delimiter`, and `dest`.\\n- The macros `security_content_ctime` and `linux_auditd_change_file_owner_to_root_filter` are placeholders for the corresponding Splunk macros.\",\r\n \"Additional comment 2.0\"\r\n ],\r\n \"translation_result\": \"full\",\r\n \"id\": \"{{rule_migration_id_1}}\"\r\n },\r\n {\r\n \"created_by\": \"elastic2.0\",\r\n \"elastic_rule\": {\r\n \"severity\": \"high\",\r\n \"title\": \"Linux Auditd Change File Owner To Root (UPDATED)\"\r\n },\r\n \"id\": \"{{rule_migration_id_2}}\"\r\n }\r\n]'\r\n```\r\n</details>\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"f6ac2cf8603ca633070e719f69b4fcef45ea92cb"}}]}] BACKPORT-->
This commit is contained in:
parent
784cbc8f8b
commit
33263b25c2
17 changed files with 408 additions and 85 deletions
|
@ -378,6 +378,8 @@ import type {
|
|||
StartRuleMigrationResponse,
|
||||
StopRuleMigrationRequestParamsInput,
|
||||
StopRuleMigrationResponse,
|
||||
UpdateRuleMigrationRequestBodyInput,
|
||||
UpdateRuleMigrationResponse,
|
||||
UpsertRuleMigrationResourcesRequestParamsInput,
|
||||
UpsertRuleMigrationResourcesRequestBodyInput,
|
||||
UpsertRuleMigrationResourcesResponse,
|
||||
|
@ -2086,6 +2088,22 @@ detection engine rules.
|
|||
})
|
||||
.catch(catchAxiosErrorFormatAndThrow);
|
||||
}
|
||||
/**
|
||||
* Updates rules migrations attributes
|
||||
*/
|
||||
async updateRuleMigration(props: UpdateRuleMigrationProps) {
|
||||
this.log.info(`${new Date().toISOString()} Calling API UpdateRuleMigration`);
|
||||
return this.kbnClient
|
||||
.request<UpdateRuleMigrationResponse>({
|
||||
path: '/internal/siem_migrations/rules',
|
||||
headers: {
|
||||
[ELASTIC_HTTP_VERSION_HEADER]: '1',
|
||||
},
|
||||
method: 'PUT',
|
||||
body: props.body,
|
||||
})
|
||||
.catch(catchAxiosErrorFormatAndThrow);
|
||||
}
|
||||
async uploadAssetCriticalityRecords(props: UploadAssetCriticalityRecordsProps) {
|
||||
this.log.info(`${new Date().toISOString()} Calling API UploadAssetCriticalityRecords`);
|
||||
return this.kbnClient
|
||||
|
@ -2394,6 +2412,9 @@ export interface TriggerRiskScoreCalculationProps {
|
|||
export interface UpdateRuleProps {
|
||||
body: UpdateRuleRequestBodyInput;
|
||||
}
|
||||
export interface UpdateRuleMigrationProps {
|
||||
body: UpdateRuleMigrationRequestBodyInput;
|
||||
}
|
||||
export interface UploadAssetCriticalityRecordsProps {
|
||||
attachment: FormData;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ import { ArrayFromString } from '@kbn/zod-helpers';
|
|||
|
||||
import {
|
||||
OriginalRule,
|
||||
ElasticRulePartial,
|
||||
RuleMigrationTranslationResult,
|
||||
RuleMigrationComments,
|
||||
RuleMigrationAllTaskStats,
|
||||
RuleMigration,
|
||||
RuleMigrationTaskStats,
|
||||
|
@ -26,7 +29,7 @@ import {
|
|||
RuleMigrationResourceType,
|
||||
RuleMigrationResource,
|
||||
} from '../../rule_migration.gen';
|
||||
import { ConnectorId, LangSmithOptions } from '../common.gen';
|
||||
import { NonEmptyString, ConnectorId, LangSmithOptions } from '../../common.gen';
|
||||
|
||||
export type CreateRuleMigrationRequestBody = z.infer<typeof CreateRuleMigrationRequestBody>;
|
||||
export const CreateRuleMigrationRequestBody = z.array(OriginalRule);
|
||||
|
@ -37,7 +40,7 @@ export const CreateRuleMigrationResponse = z.object({
|
|||
/**
|
||||
* The migration id created.
|
||||
*/
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
});
|
||||
|
||||
export type GetAllStatsRuleMigrationResponse = z.infer<typeof GetAllStatsRuleMigrationResponse>;
|
||||
|
@ -45,7 +48,7 @@ export const GetAllStatsRuleMigrationResponse = RuleMigrationAllTaskStats;
|
|||
|
||||
export type GetRuleMigrationRequestParams = z.infer<typeof GetRuleMigrationRequestParams>;
|
||||
export const GetRuleMigrationRequestParams = z.object({
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
});
|
||||
export type GetRuleMigrationRequestParamsInput = z.input<typeof GetRuleMigrationRequestParams>;
|
||||
|
||||
|
@ -66,7 +69,7 @@ export type GetRuleMigrationResourcesRequestParams = z.infer<
|
|||
typeof GetRuleMigrationResourcesRequestParams
|
||||
>;
|
||||
export const GetRuleMigrationResourcesRequestParams = z.object({
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
});
|
||||
export type GetRuleMigrationResourcesRequestParamsInput = z.input<
|
||||
typeof GetRuleMigrationResourcesRequestParams
|
||||
|
@ -77,7 +80,7 @@ export const GetRuleMigrationResourcesResponse = z.array(RuleMigrationResource);
|
|||
|
||||
export type GetRuleMigrationStatsRequestParams = z.infer<typeof GetRuleMigrationStatsRequestParams>;
|
||||
export const GetRuleMigrationStatsRequestParams = z.object({
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
});
|
||||
export type GetRuleMigrationStatsRequestParamsInput = z.input<
|
||||
typeof GetRuleMigrationStatsRequestParams
|
||||
|
@ -88,7 +91,7 @@ export const GetRuleMigrationStatsResponse = RuleMigrationTaskStats;
|
|||
|
||||
export type StartRuleMigrationRequestParams = z.infer<typeof StartRuleMigrationRequestParams>;
|
||||
export const StartRuleMigrationRequestParams = z.object({
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
});
|
||||
export type StartRuleMigrationRequestParamsInput = z.input<typeof StartRuleMigrationRequestParams>;
|
||||
|
||||
|
@ -109,7 +112,7 @@ export const StartRuleMigrationResponse = z.object({
|
|||
|
||||
export type StopRuleMigrationRequestParams = z.infer<typeof StopRuleMigrationRequestParams>;
|
||||
export const StopRuleMigrationRequestParams = z.object({
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
});
|
||||
export type StopRuleMigrationRequestParamsInput = z.input<typeof StopRuleMigrationRequestParams>;
|
||||
|
||||
|
@ -121,11 +124,42 @@ export const StopRuleMigrationResponse = z.object({
|
|||
stopped: z.boolean(),
|
||||
});
|
||||
|
||||
export type UpdateRuleMigrationRequestBody = z.infer<typeof UpdateRuleMigrationRequestBody>;
|
||||
export const UpdateRuleMigrationRequestBody = z.array(
|
||||
z.object({
|
||||
/**
|
||||
* The rule migration id
|
||||
*/
|
||||
id: NonEmptyString,
|
||||
/**
|
||||
* The migrated elastic rule attributes to update.
|
||||
*/
|
||||
elastic_rule: ElasticRulePartial.optional(),
|
||||
/**
|
||||
* The rule translation result.
|
||||
*/
|
||||
translation_result: RuleMigrationTranslationResult.optional(),
|
||||
/**
|
||||
* The comments for the migration including a summary from the LLM in markdown.
|
||||
*/
|
||||
comments: RuleMigrationComments.optional(),
|
||||
})
|
||||
);
|
||||
export type UpdateRuleMigrationRequestBodyInput = z.input<typeof UpdateRuleMigrationRequestBody>;
|
||||
|
||||
export type UpdateRuleMigrationResponse = z.infer<typeof UpdateRuleMigrationResponse>;
|
||||
export const UpdateRuleMigrationResponse = z.object({
|
||||
/**
|
||||
* Indicates rules migrations have been updated.
|
||||
*/
|
||||
updated: z.boolean(),
|
||||
});
|
||||
|
||||
export type UpsertRuleMigrationResourcesRequestParams = z.infer<
|
||||
typeof UpsertRuleMigrationResourcesRequestParams
|
||||
>;
|
||||
export const UpsertRuleMigrationResourcesRequestParams = z.object({
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
});
|
||||
export type UpsertRuleMigrationResourcesRequestParamsInput = z.input<
|
||||
typeof UpsertRuleMigrationResourcesRequestParams
|
||||
|
@ -134,7 +168,16 @@ export type UpsertRuleMigrationResourcesRequestParamsInput = z.input<
|
|||
export type UpsertRuleMigrationResourcesRequestBody = z.infer<
|
||||
typeof UpsertRuleMigrationResourcesRequestBody
|
||||
>;
|
||||
export const UpsertRuleMigrationResourcesRequestBody = z.array(RuleMigrationResourceData);
|
||||
export const UpsertRuleMigrationResourcesRequestBody = z.array(
|
||||
RuleMigrationResourceData.merge(
|
||||
z.object({
|
||||
/**
|
||||
* The rule resource migration id
|
||||
*/
|
||||
id: NonEmptyString,
|
||||
})
|
||||
)
|
||||
);
|
||||
export type UpsertRuleMigrationResourcesRequestBodyInput = z.input<
|
||||
typeof UpsertRuleMigrationResourcesRequestBody
|
||||
>;
|
||||
|
|
|
@ -3,7 +3,6 @@ info:
|
|||
title: SIEM Rules Migration API
|
||||
version: '1'
|
||||
paths:
|
||||
|
||||
# Rule migrations APIs
|
||||
|
||||
/internal/siem_migrations/rules:
|
||||
|
@ -33,8 +32,52 @@ paths:
|
|||
- migration_id
|
||||
properties:
|
||||
migration_id:
|
||||
type: string
|
||||
description: The migration id created.
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
|
||||
put:
|
||||
summary: Updates rules migrations
|
||||
operationId: UpdateRuleMigration
|
||||
x-codegen-enabled: true
|
||||
description: Updates rules migrations attributes
|
||||
tags:
|
||||
- SIEM Rule Migrations
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
properties:
|
||||
id:
|
||||
description: The rule migration id
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
elastic_rule:
|
||||
description: The migrated elastic rule attributes to update.
|
||||
$ref: '../../rule_migration.schema.yaml#/components/schemas/ElasticRulePartial'
|
||||
translation_result:
|
||||
description: The rule translation result.
|
||||
$ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationTranslationResult'
|
||||
comments:
|
||||
description: The comments for the migration including a summary from the LLM in markdown.
|
||||
$ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationComments'
|
||||
responses:
|
||||
200:
|
||||
description: Indicates rules migrations have been updated correctly.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- updated
|
||||
properties:
|
||||
updated:
|
||||
type: boolean
|
||||
description: Indicates rules migrations have been updated.
|
||||
|
||||
/internal/siem_migrations/rules/stats:
|
||||
get:
|
||||
|
@ -67,8 +110,8 @@ paths:
|
|||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The migration id to start
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
responses:
|
||||
200:
|
||||
description: Indicates rule migration have been retrieved correctly.
|
||||
|
@ -94,8 +137,8 @@ paths:
|
|||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The migration id to start
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
|
@ -106,9 +149,9 @@ paths:
|
|||
- connector_id
|
||||
properties:
|
||||
connector_id:
|
||||
$ref: '../common.schema.yaml#/components/schemas/ConnectorId'
|
||||
$ref: '../../common.schema.yaml#/components/schemas/ConnectorId'
|
||||
langsmith_options:
|
||||
$ref: '../common.schema.yaml#/components/schemas/LangSmithOptions'
|
||||
$ref: '../../common.schema.yaml#/components/schemas/LangSmithOptions'
|
||||
responses:
|
||||
200:
|
||||
description: Indicates the migration start request has been processed successfully.
|
||||
|
@ -138,8 +181,8 @@ paths:
|
|||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The migration id to start
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
responses:
|
||||
200:
|
||||
description: Indicates the migration stats has been retrieved correctly.
|
||||
|
@ -163,8 +206,8 @@ paths:
|
|||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The migration id to stop
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
responses:
|
||||
200:
|
||||
description: Indicates migration task stop has been processed successfully.
|
||||
|
@ -197,8 +240,8 @@ paths:
|
|||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The migration id to attach the resources
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
|
@ -206,7 +249,15 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationResourceData'
|
||||
allOf:
|
||||
- $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationResourceData'
|
||||
- type: object
|
||||
required:
|
||||
- id
|
||||
properties:
|
||||
id:
|
||||
description: The rule resource migration id
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
responses:
|
||||
200:
|
||||
description: Indicates migration resources have been created or updated correctly.
|
||||
|
@ -234,8 +285,8 @@ paths:
|
|||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The migration id to attach the resources
|
||||
$ref: '../../common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
- name: type
|
||||
in: query
|
||||
required: false
|
||||
|
|
|
@ -10,12 +10,21 @@
|
|||
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
|
||||
*
|
||||
* info:
|
||||
* title: SIEM Rule Migrations API common components
|
||||
* title: SIEM Rule Migration common components
|
||||
* version: not applicable
|
||||
*/
|
||||
|
||||
import { z } from '@kbn/zod';
|
||||
|
||||
/**
|
||||
* A string that is not empty and does not contain only whitespace
|
||||
*/
|
||||
export type NonEmptyString = z.infer<typeof NonEmptyString>;
|
||||
export const NonEmptyString = z
|
||||
.string()
|
||||
.min(1)
|
||||
.regex(/^(?! *$).+$/);
|
||||
|
||||
/**
|
||||
* The GenAI connector id to use.
|
||||
*/
|
|
@ -1,11 +1,16 @@
|
|||
openapi: 3.0.3
|
||||
info:
|
||||
title: SIEM Rule Migrations API common components
|
||||
title: SIEM Rule Migration common components
|
||||
version: 'not applicable'
|
||||
paths: {}
|
||||
components:
|
||||
x-codegen-enabled: true
|
||||
schemas:
|
||||
NonEmptyString:
|
||||
type: string
|
||||
pattern: ^(?! *$).+$
|
||||
minLength: 1
|
||||
description: A string that is not empty and does not contain only whitespace
|
||||
ConnectorId:
|
||||
type: string
|
||||
description: The GenAI connector id to use.
|
|
@ -10,12 +10,14 @@
|
|||
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
|
||||
*
|
||||
* info:
|
||||
* title: SIEM Rule Migration common components
|
||||
* title: SIEM Rule Migration components
|
||||
* version: not applicable
|
||||
*/
|
||||
|
||||
import { z } from '@kbn/zod';
|
||||
|
||||
import { NonEmptyString } from './common.gen';
|
||||
|
||||
/**
|
||||
* The original rule vendor identifier.
|
||||
*/
|
||||
|
@ -30,7 +32,10 @@ export const OriginalRule = z.object({
|
|||
/**
|
||||
* The original rule id.
|
||||
*/
|
||||
id: z.string(),
|
||||
id: NonEmptyString,
|
||||
/**
|
||||
* The original rule vendor identifier.
|
||||
*/
|
||||
vendor: OriginalRuleVendor,
|
||||
/**
|
||||
* The original rule name.
|
||||
|
@ -82,18 +87,46 @@ export const ElasticRule = z.object({
|
|||
/**
|
||||
* The Elastic prebuilt rule id matched.
|
||||
*/
|
||||
prebuilt_rule_id: z.string().optional(),
|
||||
prebuilt_rule_id: NonEmptyString.optional(),
|
||||
/**
|
||||
* The Elastic rule id installed as a result.
|
||||
*/
|
||||
id: z.string().optional(),
|
||||
id: NonEmptyString.optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* The partial version of the migrated elastic rule.
|
||||
*/
|
||||
export type ElasticRulePartial = z.infer<typeof ElasticRulePartial>;
|
||||
export const ElasticRulePartial = ElasticRule.partial();
|
||||
|
||||
/**
|
||||
* The rule translation result.
|
||||
*/
|
||||
export type RuleMigrationTranslationResult = z.infer<typeof RuleMigrationTranslationResult>;
|
||||
export const RuleMigrationTranslationResult = z.enum(['full', 'partial', 'untranslatable']);
|
||||
export type RuleMigrationTranslationResultEnum = typeof RuleMigrationTranslationResult.enum;
|
||||
export const RuleMigrationTranslationResultEnum = RuleMigrationTranslationResult.enum;
|
||||
|
||||
/**
|
||||
* The status of the rule migration process.
|
||||
*/
|
||||
export type RuleMigrationStatus = z.infer<typeof RuleMigrationStatus>;
|
||||
export const RuleMigrationStatus = z.enum(['pending', 'processing', 'completed', 'failed']);
|
||||
export type RuleMigrationStatusEnum = typeof RuleMigrationStatus.enum;
|
||||
export const RuleMigrationStatusEnum = RuleMigrationStatus.enum;
|
||||
|
||||
/**
|
||||
* The comments for the migration including a summary from the LLM in markdown.
|
||||
*/
|
||||
export type RuleMigrationComments = z.infer<typeof RuleMigrationComments>;
|
||||
export const RuleMigrationComments = z.array(z.string());
|
||||
|
||||
/**
|
||||
* The rule migration document object.
|
||||
*/
|
||||
export type RuleMigration = z.infer<typeof RuleMigration>;
|
||||
export const RuleMigration = z.object({
|
||||
export type RuleMigrationData = z.infer<typeof RuleMigrationData>;
|
||||
export const RuleMigrationData = z.object({
|
||||
/**
|
||||
* The moment of creation
|
||||
*/
|
||||
|
@ -101,25 +134,31 @@ export const RuleMigration = z.object({
|
|||
/**
|
||||
* The migration id.
|
||||
*/
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
/**
|
||||
* The username of the user who created the migration.
|
||||
*/
|
||||
created_by: z.string(),
|
||||
created_by: NonEmptyString,
|
||||
/**
|
||||
* The original rule to migrate.
|
||||
*/
|
||||
original_rule: OriginalRule,
|
||||
/**
|
||||
* The migrated elastic rule.
|
||||
*/
|
||||
elastic_rule: ElasticRule.optional(),
|
||||
/**
|
||||
* The rule translation result.
|
||||
*/
|
||||
translation_result: z.enum(['full', 'partial', 'untranslatable']).optional(),
|
||||
translation_result: RuleMigrationTranslationResult.optional(),
|
||||
/**
|
||||
* The status of the rule migration process.
|
||||
*/
|
||||
status: z.enum(['pending', 'processing', 'completed', 'failed']).default('pending'),
|
||||
status: RuleMigrationStatus.default('pending'),
|
||||
/**
|
||||
* The comments for the migration including a summary from the LLM in markdown.
|
||||
*/
|
||||
comments: z.array(z.string()).optional(),
|
||||
comments: RuleMigrationComments.optional(),
|
||||
/**
|
||||
* The moment of the last update
|
||||
*/
|
||||
|
@ -130,6 +169,19 @@ export const RuleMigration = z.object({
|
|||
updated_by: z.string().optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* The rule migration document object.
|
||||
*/
|
||||
export type RuleMigration = z.infer<typeof RuleMigration>;
|
||||
export const RuleMigration = z
|
||||
.object({
|
||||
/**
|
||||
* The rule migration id
|
||||
*/
|
||||
id: NonEmptyString,
|
||||
})
|
||||
.merge(RuleMigrationData);
|
||||
|
||||
/**
|
||||
* The rule migration task stats object.
|
||||
*/
|
||||
|
@ -177,7 +229,7 @@ export const RuleMigrationAllTaskStats = z.array(
|
|||
/**
|
||||
* The migration id
|
||||
*/
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -216,10 +268,14 @@ export const RuleMigrationResourceData = z.object({
|
|||
export type RuleMigrationResource = z.infer<typeof RuleMigrationResource>;
|
||||
export const RuleMigrationResource = RuleMigrationResourceData.merge(
|
||||
z.object({
|
||||
/**
|
||||
* The rule resource migration id
|
||||
*/
|
||||
id: NonEmptyString,
|
||||
/**
|
||||
* The migration id
|
||||
*/
|
||||
migration_id: z.string(),
|
||||
migration_id: NonEmptyString,
|
||||
/**
|
||||
* The moment of the last update
|
||||
*/
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
openapi: 3.0.3
|
||||
info:
|
||||
title: SIEM Rule Migration common components
|
||||
title: SIEM Rule Migration components
|
||||
version: 'not applicable'
|
||||
paths: {}
|
||||
components:
|
||||
x-codegen-enabled: true
|
||||
schemas:
|
||||
|
||||
OriginalRuleVendor:
|
||||
type: string
|
||||
description: The original rule vendor identifier.
|
||||
|
@ -25,9 +24,10 @@ components:
|
|||
- query_language
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: The original rule id.
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
vendor:
|
||||
description: The original rule vendor identifier.
|
||||
$ref: '#/components/schemas/OriginalRuleVendor'
|
||||
title:
|
||||
type: string
|
||||
|
@ -71,13 +71,30 @@ components:
|
|||
enum:
|
||||
- esql
|
||||
prebuilt_rule_id:
|
||||
type: string
|
||||
description: The Elastic prebuilt rule id matched.
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
id:
|
||||
type: string
|
||||
description: The Elastic rule id installed as a result.
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
|
||||
ElasticRulePartial:
|
||||
description: The partial version of the migrated elastic rule.
|
||||
$ref: '#/components/schemas/ElasticRule'
|
||||
x-modify: partial
|
||||
|
||||
RuleMigration:
|
||||
description: The rule migration document object.
|
||||
allOf:
|
||||
- type: object
|
||||
required:
|
||||
- id
|
||||
properties:
|
||||
id:
|
||||
description: The rule migration id
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
- $ref: '#/components/schemas/RuleMigrationData'
|
||||
|
||||
RuleMigrationData:
|
||||
type: object
|
||||
description: The rule migration document object.
|
||||
required:
|
||||
|
@ -91,36 +108,27 @@ components:
|
|||
type: string
|
||||
description: The moment of creation
|
||||
migration_id:
|
||||
type: string
|
||||
description: The migration id.
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
created_by:
|
||||
type: string
|
||||
description: The username of the user who created the migration.
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
original_rule:
|
||||
description: The original rule to migrate.
|
||||
$ref: '#/components/schemas/OriginalRule'
|
||||
elastic_rule:
|
||||
description: The migrated elastic rule.
|
||||
$ref: '#/components/schemas/ElasticRule'
|
||||
translation_result:
|
||||
type: string
|
||||
description: The rule translation result.
|
||||
enum: # should match SiemMigrationRuleTranslationResult enum at ../constants.ts
|
||||
- full
|
||||
- partial
|
||||
- untranslatable
|
||||
$ref: '#/components/schemas/RuleMigrationTranslationResult'
|
||||
status:
|
||||
type: string
|
||||
description: The status of the rule migration process.
|
||||
enum: # should match SiemMigrationsStatus enum at ../constants.ts
|
||||
- pending
|
||||
- processing
|
||||
- completed
|
||||
- failed
|
||||
$ref: '#/components/schemas/RuleMigrationStatus'
|
||||
default: pending
|
||||
comments:
|
||||
type: array
|
||||
description: The comments for the migration including a summary from the LLM in markdown.
|
||||
items:
|
||||
type: string
|
||||
$ref: '#/components/schemas/RuleMigrationComments'
|
||||
updated_at:
|
||||
type: string
|
||||
description: The moment of the last update
|
||||
|
@ -182,11 +190,34 @@ components:
|
|||
- migration_id
|
||||
properties:
|
||||
migration_id:
|
||||
type: string
|
||||
description: The migration id
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
|
||||
RuleMigrationTranslationResult:
|
||||
type: string
|
||||
description: The rule translation result.
|
||||
enum: # should match SiemMigrationRuleTranslationResult enum at ../constants.ts
|
||||
- full
|
||||
- partial
|
||||
- untranslatable
|
||||
|
||||
RuleMigrationStatus:
|
||||
type: string
|
||||
description: The status of the rule migration process.
|
||||
enum: # should match SiemMigrationsStatus enum at ../constants.ts
|
||||
- pending
|
||||
- processing
|
||||
- completed
|
||||
- failed
|
||||
|
||||
RuleMigrationComments:
|
||||
type: array
|
||||
description: The comments for the migration including a summary from the LLM in markdown.
|
||||
items:
|
||||
type: string
|
||||
|
||||
## Rule migration resources
|
||||
|
||||
## Rule migration resources
|
||||
|
||||
RuleMigrationResourceType:
|
||||
type: string
|
||||
description: The type of the rule migration resource.
|
||||
|
@ -220,11 +251,15 @@ components:
|
|||
- $ref: '#/components/schemas/RuleMigrationResourceData'
|
||||
- type: object
|
||||
required:
|
||||
- id
|
||||
- migration_id
|
||||
properties:
|
||||
id:
|
||||
description: The rule resource migration id
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
migration_id:
|
||||
type: string
|
||||
description: The migration id
|
||||
$ref: './common.schema.yaml#/components/schemas/NonEmptyString'
|
||||
updated_at:
|
||||
type: string
|
||||
description: The moment of the last update
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
|
||||
import { SIEM_RULE_MIGRATIONS_PATH } from '../../../../../common/siem_migrations/constants';
|
||||
import type { SecuritySolutionPluginRouter } from '../../../../types';
|
||||
import type { CreateRuleMigrationInput } from '../data/rule_migrations_data_client';
|
||||
import type { CreateRuleMigrationInput } from '../data/rule_migrations_data_rules_client';
|
||||
import { withLicense } from './util/with_license';
|
||||
|
||||
export const registerSiemRuleMigrationsCreateRoute = (
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type { Logger } from '@kbn/core/server';
|
||||
import type { SecuritySolutionPluginRouter } from '../../../../types';
|
||||
import { registerSiemRuleMigrationsCreateRoute } from './create';
|
||||
import { registerSiemRuleMigrationsUpdateRoute } from './update';
|
||||
import { registerSiemRuleMigrationsGetRoute } from './get';
|
||||
import { registerSiemRuleMigrationsStartRoute } from './start';
|
||||
import { registerSiemRuleMigrationsStatsRoute } from './stats';
|
||||
|
@ -22,6 +23,7 @@ export const registerSiemRuleMigrationsRoutes = (
|
|||
logger: Logger
|
||||
) => {
|
||||
registerSiemRuleMigrationsCreateRoute(router, logger);
|
||||
registerSiemRuleMigrationsUpdateRoute(router, logger);
|
||||
registerSiemRuleMigrationsStatsAllRoute(router, logger);
|
||||
registerSiemRuleMigrationsGetRoute(router, logger);
|
||||
registerSiemRuleMigrationsStartRoute(router, logger);
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { IKibanaResponse, Logger } from '@kbn/core/server';
|
||||
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
|
||||
import {
|
||||
UpdateRuleMigrationRequestBody,
|
||||
type UpdateRuleMigrationResponse,
|
||||
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
|
||||
import { SIEM_RULE_MIGRATIONS_PATH } from '../../../../../common/siem_migrations/constants';
|
||||
import type { SecuritySolutionPluginRouter } from '../../../../types';
|
||||
import { withLicense } from './util/with_license';
|
||||
|
||||
export const registerSiemRuleMigrationsUpdateRoute = (
|
||||
router: SecuritySolutionPluginRouter,
|
||||
logger: Logger
|
||||
) => {
|
||||
router.versioned
|
||||
.put({
|
||||
path: SIEM_RULE_MIGRATIONS_PATH,
|
||||
access: 'internal',
|
||||
security: { authz: { requiredPrivileges: ['securitySolution'] } },
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '1',
|
||||
validate: {
|
||||
request: { body: buildRouteValidationWithZod(UpdateRuleMigrationRequestBody) },
|
||||
},
|
||||
},
|
||||
withLicense(
|
||||
async (context, req, res): Promise<IKibanaResponse<UpdateRuleMigrationResponse>> => {
|
||||
const rulesToUpdate = req.body;
|
||||
try {
|
||||
const ctx = await context.resolve(['securitySolution']);
|
||||
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
|
||||
|
||||
await ruleMigrationsClient.data.rules.update(rulesToUpdate);
|
||||
|
||||
return res.ok({ body: { updated: true } });
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
return res.badRequest({ body: err.message });
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
|
@ -33,7 +33,7 @@ export class RuleMigrationsDataBaseClient {
|
|||
return hits.map(({ _id, _source }) => {
|
||||
assert(_id, 'document should have _id');
|
||||
assert(_source, 'document should have _source');
|
||||
return { ..._source, ...override, _id };
|
||||
return { ..._source, ...override, id: _id };
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -6,18 +6,10 @@
|
|||
*/
|
||||
|
||||
import type { ElasticsearchClient, Logger } from '@kbn/core/server';
|
||||
import type {
|
||||
RuleMigration,
|
||||
RuleMigrationTaskStats,
|
||||
} from '../../../../../common/siem_migrations/model/rule_migration.gen';
|
||||
import { RuleMigrationsDataRulesClient } from './rule_migrations_data_rules_client';
|
||||
import { RuleMigrationsDataResourcesClient } from './rule_migrations_data_resources_client';
|
||||
import type { AdapterId } from './rule_migrations_data_service';
|
||||
|
||||
export type CreateRuleMigrationInput = Omit<RuleMigration, '@timestamp' | 'status' | 'created_by'>;
|
||||
export type RuleMigrationDataStats = Omit<RuleMigrationTaskStats, 'status'>;
|
||||
export type RuleMigrationAllDataStats = Array<RuleMigrationDataStats & { migration_id: string }>;
|
||||
|
||||
export type IndexNameProvider = () => Promise<string>;
|
||||
export type IndexNameProviders = Record<AdapterId, IndexNameProvider>;
|
||||
|
||||
|
|
|
@ -15,12 +15,20 @@ import type {
|
|||
import type { StoredRuleMigration } from '../types';
|
||||
import { SiemMigrationStatus } from '../../../../../common/siem_migrations/constants';
|
||||
import type {
|
||||
ElasticRule,
|
||||
RuleMigration,
|
||||
RuleMigrationTaskStats,
|
||||
} from '../../../../../common/siem_migrations/model/rule_migration.gen';
|
||||
import { RuleMigrationsDataBaseClient } from './rule_migrations_data_base_client';
|
||||
|
||||
export type CreateRuleMigrationInput = Omit<RuleMigration, '@timestamp' | 'status' | 'created_by'>;
|
||||
export type CreateRuleMigrationInput = Omit<
|
||||
RuleMigration,
|
||||
'@timestamp' | 'id' | 'status' | 'created_by'
|
||||
>;
|
||||
export type UpdateRuleMigrationInput = { elastic_rule?: Partial<ElasticRule> } & Pick<
|
||||
RuleMigration,
|
||||
'id' | 'translation_result' | 'comments'
|
||||
>;
|
||||
export type RuleMigrationDataStats = Omit<RuleMigrationTaskStats, 'status'>;
|
||||
export type RuleMigrationAllDataStats = Array<RuleMigrationDataStats & { migration_id: string }>;
|
||||
|
||||
|
@ -35,6 +43,7 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
|
|||
const index = await this.getIndexName();
|
||||
|
||||
let ruleMigrationsSlice: CreateRuleMigrationInput[];
|
||||
const createdAt = new Date().toISOString();
|
||||
while ((ruleMigrationsSlice = ruleMigrations.splice(0, BULK_MAX_SIZE)).length) {
|
||||
await this.esClient
|
||||
.bulk({
|
||||
|
@ -43,9 +52,11 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
|
|||
{ create: { _index: index } },
|
||||
{
|
||||
...ruleMigration,
|
||||
'@timestamp': new Date().toISOString(),
|
||||
'@timestamp': createdAt,
|
||||
status: SiemMigrationStatus.PENDING,
|
||||
created_by: this.username,
|
||||
updated_by: this.username,
|
||||
updated_at: createdAt,
|
||||
},
|
||||
]),
|
||||
})
|
||||
|
@ -56,6 +67,37 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
|
|||
}
|
||||
}
|
||||
|
||||
/** Updates an array of rule migrations to be processed */
|
||||
async update(ruleMigrations: UpdateRuleMigrationInput[]): Promise<void> {
|
||||
const index = await this.getIndexName();
|
||||
|
||||
let ruleMigrationsSlice: UpdateRuleMigrationInput[];
|
||||
const updatedAt = new Date().toISOString();
|
||||
while ((ruleMigrationsSlice = ruleMigrations.splice(0, BULK_MAX_SIZE)).length) {
|
||||
await this.esClient
|
||||
.bulk({
|
||||
refresh: 'wait_for',
|
||||
operations: ruleMigrationsSlice.flatMap((ruleMigration) => {
|
||||
const { id, ...rest } = ruleMigration;
|
||||
return [
|
||||
{ update: { _index: index, _id: id } },
|
||||
{
|
||||
doc: {
|
||||
...rest,
|
||||
updated_by: this.username,
|
||||
updated_at: updatedAt,
|
||||
},
|
||||
},
|
||||
];
|
||||
}),
|
||||
})
|
||||
.catch((error) => {
|
||||
this.logger.error(`Error updating rule migrations: ${error.message}`);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Retrieves an array of rule documents of a specific migrations */
|
||||
async get(migrationId: string): Promise<StoredRuleMigration[]> {
|
||||
const index = await this.getIndexName();
|
||||
|
@ -94,8 +136,8 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
|
|||
await this.esClient
|
||||
.bulk({
|
||||
refresh: 'wait_for',
|
||||
operations: storedRuleMigrations.flatMap(({ _id, status }) => [
|
||||
{ update: { _id, _index: index } },
|
||||
operations: storedRuleMigrations.flatMap(({ id, status }) => [
|
||||
{ update: { _id: id, _index: index } },
|
||||
{
|
||||
doc: { status, updated_by: this.username, updated_at: new Date().toISOString() },
|
||||
},
|
||||
|
@ -112,7 +154,7 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
|
|||
}
|
||||
|
||||
/** Updates one rule migration with the provided data and sets the status to `completed` */
|
||||
async saveCompleted({ _id, ...ruleMigration }: StoredRuleMigration): Promise<void> {
|
||||
async saveCompleted({ id, ...ruleMigration }: StoredRuleMigration): Promise<void> {
|
||||
const index = await this.getIndexName();
|
||||
const doc = {
|
||||
...ruleMigration,
|
||||
|
@ -120,14 +162,14 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
|
|||
updated_by: this.username,
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
await this.esClient.update({ index, id: _id, doc, refresh: 'wait_for' }).catch((error) => {
|
||||
await this.esClient.update({ index, id, doc, refresh: 'wait_for' }).catch((error) => {
|
||||
this.logger.error(`Error updating rule migration status to completed: ${error.message}`);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
/** Updates one rule migration with the provided data and sets the status to `failed` */
|
||||
async saveError({ _id, ...ruleMigration }: StoredRuleMigration): Promise<void> {
|
||||
async saveError({ id, ...ruleMigration }: StoredRuleMigration): Promise<void> {
|
||||
const index = await this.getIndexName();
|
||||
const doc = {
|
||||
...ruleMigration,
|
||||
|
@ -135,7 +177,7 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
|
|||
updated_by: this.username,
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
await this.esClient.update({ index, id: _id, doc, refresh: 'wait_for' }).catch((error) => {
|
||||
await this.esClient.update({ index, id, doc, refresh: 'wait_for' }).catch((error) => {
|
||||
this.logger.error(`Error updating rule migration status to failed: ${error.message}`);
|
||||
throw error;
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ import type {
|
|||
RuleMigrationResource,
|
||||
} from '../../../../../common/siem_migrations/model/rule_migration.gen';
|
||||
|
||||
export const ruleMigrationsFieldMap: FieldMap<SchemaFieldMapKeys<RuleMigration>> = {
|
||||
export const ruleMigrationsFieldMap: FieldMap<SchemaFieldMapKeys<Omit<RuleMigration, 'id'>>> = {
|
||||
'@timestamp': { type: 'date', required: false },
|
||||
migration_id: { type: 'keyword', required: true },
|
||||
created_by: { type: 'keyword', required: true },
|
||||
|
@ -38,7 +38,9 @@ export const ruleMigrationsFieldMap: FieldMap<SchemaFieldMapKeys<RuleMigration>>
|
|||
updated_by: { type: 'keyword', required: false },
|
||||
};
|
||||
|
||||
export const ruleMigrationResourcesFieldMap: FieldMap<SchemaFieldMapKeys<RuleMigrationResource>> = {
|
||||
export const ruleMigrationResourcesFieldMap: FieldMap<
|
||||
SchemaFieldMapKeys<Omit<RuleMigrationResource, 'id'>>
|
||||
> = {
|
||||
migration_id: { type: 'keyword', required: true },
|
||||
type: { type: 'keyword', required: true },
|
||||
name: { type: 'keyword', required: true },
|
||||
|
|
|
@ -13,10 +13,8 @@ import type {
|
|||
RuleMigrationAllTaskStats,
|
||||
RuleMigrationTaskStats,
|
||||
} from '../../../../../common/siem_migrations/model/rule_migration.gen';
|
||||
import type {
|
||||
RuleMigrationDataStats,
|
||||
RuleMigrationsDataClient,
|
||||
} from '../data/rule_migrations_data_client';
|
||||
import type { RuleMigrationsDataClient } from '../data/rule_migrations_data_client';
|
||||
import type { RuleMigrationDataStats } from '../data/rule_migrations_data_rules_client';
|
||||
import type {
|
||||
RuleMigrationTaskStartParams,
|
||||
RuleMigrationTaskStartResult,
|
||||
|
|
|
@ -10,7 +10,7 @@ import type {
|
|||
RuleMigrationResource,
|
||||
} from '../../../../common/siem_migrations/model/rule_migration.gen';
|
||||
|
||||
export type Stored<T extends object> = T & { _id: string };
|
||||
export type Stored<T extends object> = T & { id: string };
|
||||
|
||||
export type StoredRuleMigration = Stored<RuleMigration>;
|
||||
export type StoredRuleMigrationResource = Stored<RuleMigrationResource>;
|
||||
|
|
|
@ -142,6 +142,7 @@ import { StopRuleMigrationRequestParamsInput } from '@kbn/security-solution-plug
|
|||
import { SuggestUserProfilesRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/users/suggest_user_profiles_route.gen';
|
||||
import { TriggerRiskScoreCalculationRequestBodyInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/risk_engine/entity_calculation_route.gen';
|
||||
import { UpdateRuleRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.gen';
|
||||
import { UpdateRuleMigrationRequestBodyInput } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen';
|
||||
import {
|
||||
UpsertRuleMigrationResourcesRequestParamsInput,
|
||||
UpsertRuleMigrationResourcesRequestBodyInput,
|
||||
|
@ -1413,6 +1414,17 @@ detection engine rules.
|
|||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send(props.body as object);
|
||||
},
|
||||
/**
|
||||
* Updates rules migrations attributes
|
||||
*/
|
||||
updateRuleMigration(props: UpdateRuleMigrationProps, kibanaSpace: string = 'default') {
|
||||
return supertest
|
||||
.put(routeWithNamespace('/internal/siem_migrations/rules', kibanaSpace))
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send(props.body as object);
|
||||
},
|
||||
uploadAssetCriticalityRecords(kibanaSpace: string = 'default') {
|
||||
return supertest
|
||||
.post(routeWithNamespace('/api/asset_criticality/upload_csv', kibanaSpace))
|
||||
|
@ -1712,6 +1724,9 @@ export interface TriggerRiskScoreCalculationProps {
|
|||
export interface UpdateRuleProps {
|
||||
body: UpdateRuleRequestBodyInput;
|
||||
}
|
||||
export interface UpdateRuleMigrationProps {
|
||||
body: UpdateRuleMigrationRequestBodyInput;
|
||||
}
|
||||
export interface UpsertRuleMigrationResourcesProps {
|
||||
params: UpsertRuleMigrationResourcesRequestParamsInput;
|
||||
body: UpsertRuleMigrationResourcesRequestBodyInput;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue