diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/index.ts index e0fa0d8eb6408..b74132faed031 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './set_alert_assignees/set_alert_assignees_route'; +export * from './set_alert_assignees_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/mocks.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/mocks.ts index 15b16eecb2868..ef668dc36d421 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/mocks.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/mocks.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './set_alert_assignees/set_alert_assignees_route.mock'; +export * from './set_alert_assignees_route.mock'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees/set_alert_assignees_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees/set_alert_assignees_route.ts deleted file mode 100644 index 9a8fd4f052948..0000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees/set_alert_assignees_route.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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 * as t from 'io-ts'; - -import { alert_ids, alert_assignees } from '../../model'; - -export const setAlertAssigneesRequestBody = t.exact( - t.type({ - assignees: alert_assignees, - ids: alert_ids, - }) -); - -export type SetAlertAssigneesRequestBody = t.TypeOf; -export type SetAlertAssigneesRequestBodyDecoded = SetAlertAssigneesRequestBody; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.gen.ts new file mode 100644 index 0000000000000..f2b2be478ced3 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.gen.ts @@ -0,0 +1,46 @@ +/* + * 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 { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { NonEmptyString } from '../model/rule_schema/common_attributes.gen'; + +export type AlertAssignees = z.infer; +export const AlertAssignees = z.object({ + /** + * A list of users ids to assign. + */ + add: z.array(NonEmptyString), + /** + * A list of users ids to unassign. + */ + remove: z.array(NonEmptyString), +}); + +/** + * A list of alerts ids. + */ +export type AlertIds = z.infer; +export const AlertIds = z.array(NonEmptyString).min(1); + +export type SetAlertAssigneesRequestBody = z.infer; +export const SetAlertAssigneesRequestBody = z.object({ + /** + * Details about the assignees to assign and unassign. + */ + assignees: AlertAssignees, + /** + * List of alerts ids to assign and unassign passed assignees. + */ + ids: AlertIds, +}); +export type SetAlertAssigneesRequestBodyInput = z.input; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees/set_alert_assignees_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.mock.ts similarity index 96% rename from x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees/set_alert_assignees_route.mock.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.mock.ts index 004619f169f72..9c41e2eae8058 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees/set_alert_assignees_route.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { SetAlertAssigneesRequestBody } from './set_alert_assignees_route'; +import type { SetAlertAssigneesRequestBody } from './set_alert_assignees_route.gen'; export const getSetAlertAssigneesRequestMock = ( assigneesToAdd: string[] = [], diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml new file mode 100644 index 0000000000000..6c3663402118a --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml @@ -0,0 +1,58 @@ +openapi: 3.0.0 +info: + title: Assign alerts API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/assignees: + summary: Assigns users to alerts + post: + operationId: SetAlertAssignees + x-codegen-enabled: true + description: Assigns users to alerts. + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - assignees + - ids + properties: + assignees: + $ref: '#/components/schemas/AlertAssignees' + description: Details about the assignees to assign and unassign. + ids: + $ref: '#/components/schemas/AlertIds' + description: List of alerts ids to assign and unassign passed assignees. + responses: + 200: + description: Indicates a successful call. + 400: + description: Invalid request. + +components: + schemas: + AlertAssignees: + type: object + required: + - add + - remove + properties: + add: + type: array + items: + $ref: '../model/rule_schema/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + description: A list of users ids to assign. + remove: + type: array + items: + $ref: '../model/rule_schema/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + description: A list of users ids to unassign. + + AlertIds: + type: array + items: + $ref: '../model/rule_schema/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + minItems: 1 + description: A list of alerts ids. diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts index 8691cb5b6ab4e..44d3023739446 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts @@ -8,7 +8,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import * as t from 'io-ts'; -import { NonEmptyArray, NonEmptyString, PositiveInteger } from '@kbn/securitysolution-io-ts-types'; +import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; export const file_name = t.string; export type FileName = t.TypeOf; @@ -42,9 +42,6 @@ export const signal_status_query = t.object; export const alert_tag_ids = t.array(t.string); export type AlertTagIds = t.TypeOf; -export const alert_ids = NonEmptyArray(NonEmptyString); -export type AlertIds = t.TypeOf; - export const indexRecord = t.record( t.string, t.type({ @@ -111,12 +108,5 @@ export const alert_tags = t.type({ export type AlertTags = t.TypeOf; -export const alert_assignees = t.type({ - add: t.array(NonEmptyString), - remove: t.array(NonEmptyString), -}); - -export type AlertAssignees = t.TypeOf; - export const user_search_term = t.string; export type UserSearchTerm = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/users/index.ts index f931f063971a3..b4775b77bf69f 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/users/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/users/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './suggest_user_profiles/suggest_user_profiles_route'; +export * from './suggest_user_profiles_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles/suggest_user_profiles_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles/suggest_user_profiles_route.ts deleted file mode 100644 index 12f87860fb002..0000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles/suggest_user_profiles_route.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 * as t from 'io-ts'; - -import { user_search_term } from '../../model'; - -export const suggestUserProfilesRequestQuery = t.exact( - t.partial({ - searchTerm: user_search_term, - }) -); - -export type SuggestUserProfilesRequestQuery = t.TypeOf; -export type SuggestUserProfilesRequestQueryDecoded = SuggestUserProfilesRequestQuery; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.gen.ts new file mode 100644 index 0000000000000..f403501c52ea7 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.gen.ts @@ -0,0 +1,22 @@ +/* + * 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 { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type SuggestUserProfilesRequestQuery = z.infer; +export const SuggestUserProfilesRequestQuery = z.object({ + /** + * Query string used to match name-related fields in user profiles. The following fields are treated as name-related: username, full_name and email + */ + searchTerm: z.string().optional(), +}); +export type SuggestUserProfilesRequestQueryInput = z.input; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml new file mode 100644 index 0000000000000..babaedf1486ff --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.0 +info: + title: Suggest user profiles API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/_find: + summary: Suggests user profiles based on provided search term + post: + operationId: SuggestUserProfiles + x-codegen-enabled: true + description: Suggests user profiles. + parameters: + - name: searchTerm + in: query + required: false + description: "Query string used to match name-related fields in user profiles. The following fields are treated as name-related: username, full_name and email" + schema: + type: string + responses: + 200: + description: Indicates a successful call. + 400: + description: Invalid request. diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts index c8b419a6fdbfb..dfc0603598a00 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts @@ -77,7 +77,9 @@ describe('setAlertAssigneesRoute', () => { const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Invalid value "[]" supplied to "ids"'); + expect(result.badRequest).toHaveBeenCalledWith( + 'ids: Array must contain at least 1 element(s)' + ); }); test('rejects if empty string provided as an alert id', async () => { @@ -89,7 +91,9 @@ describe('setAlertAssigneesRoute', () => { const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Invalid value "" supplied to "ids"'); + expect(result.badRequest).toHaveBeenCalledWith( + 'ids.0: String must contain at least 1 character(s), ids.0: Invalid' + ); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts index da2c7d77bb3bf..f15342a36f46c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts @@ -7,15 +7,14 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { uniq } from 'lodash/fp'; -import type { SetAlertAssigneesRequestBodyDecoded } from '../../../../../common/api/detection_engine/alert_assignees'; -import { setAlertAssigneesRequestBody } from '../../../../../common/api/detection_engine/alert_assignees'; +import { SetAlertAssigneesRequestBody } from '../../../../../common/api/detection_engine/alert_assignees'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DEFAULT_ALERTS_INDEX, DETECTION_ENGINE_ALERT_ASSIGNEES_URL, } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { validateAlertAssigneesArrays } from './helpers'; export const setAlertAssigneesRoute = (router: SecuritySolutionPluginRouter) => { @@ -32,10 +31,7 @@ export const setAlertAssigneesRoute = (router: SecuritySolutionPluginRouter) => version: '2023-10-31', validate: { request: { - body: buildRouteValidation< - typeof setAlertAssigneesRequestBody, - SetAlertAssigneesRequestBodyDecoded - >(setAlertAssigneesRequestBody), + body: buildRouteValidationWithZod(SetAlertAssigneesRequestBody), }, }, }, @@ -44,7 +40,6 @@ export const setAlertAssigneesRoute = (router: SecuritySolutionPluginRouter) => const core = await context.core; const securitySolution = await context.securitySolution; const esClient = core.elasticsearch.client.asCurrentUser; - const siemClient = securitySolution?.getAppClient(); const siemResponse = buildSiemResponse(response); const validationErrors = validateAlertAssigneesArrays(assignees); const spaceId = securitySolution?.getSpaceId() ?? 'default'; @@ -53,10 +48,6 @@ export const setAlertAssigneesRoute = (router: SecuritySolutionPluginRouter) => return siemResponse.error({ statusCode: 400, body: validationErrors }); } - if (!siemClient) { - return siemResponse.error({ statusCode: 404 }); - } - const assigneesToAdd = uniq(assignees.add); const assigneesToRemove = uniq(assignees.remove); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts index 6b48dfcf84380..fcb42d2ead7e4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts @@ -12,10 +12,8 @@ import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; import type { StartPlugins } from '../../../../plugin'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; - -import type { SuggestUserProfilesRequestQueryDecoded } from '../../../../../common/api/detection_engine/users'; -import { suggestUserProfilesRequestQuery } from '../../../../../common/api/detection_engine/users'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { SuggestUserProfilesRequestQuery } from '../../../../../common/api/detection_engine/users'; export const suggestUserProfilesRoute = ( router: SecuritySolutionPluginRouter, @@ -34,10 +32,7 @@ export const suggestUserProfilesRoute = ( version: '2023-10-31', validate: { request: { - query: buildRouteValidation< - typeof suggestUserProfilesRequestQuery, - SuggestUserProfilesRequestQueryDecoded - >(suggestUserProfilesRequestQuery), + query: buildRouteValidationWithZod(SuggestUserProfilesRequestQuery), }, }, }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments.ts index 9f4557217e0e9..b520b505e0405 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments.ts @@ -50,7 +50,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', - message: '[request body]: Invalid value "[]" supplied to "ids"', + message: '[request body]: ids: Array must contain at least 1 element(s)', statusCode: 400, }); }); @@ -64,7 +64,8 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', - message: '[request body]: Invalid value "" supplied to "ids"', + message: + '[request body]: ids.1: String must contain at least 1 character(s), ids.1: Invalid', statusCode: 400, }); });