From a636ce908b366cdd58c5dc94b5244cd4934892d9 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 31 Jul 2024 11:16:34 +0200 Subject: [PATCH 01/73] migrate delete timelines route to zod --- .../delete_timelines/delete_timelines_route.ts | 16 ---------------- .../common/api/timeline/routes.ts | 11 +++++++++++ .../routes/timelines/delete_timelines/index.ts | 12 ++++++++---- 3 files changed, 19 insertions(+), 20 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/timeline/routes.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.ts deleted file mode 100644 index c6b8f1baf6974..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.ts +++ /dev/null @@ -1,16 +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 rt from 'io-ts'; - -const searchId = rt.partial({ searchIds: rt.array(rt.string) }); - -const baseDeleteTimelinesSchema = rt.type({ - savedObjectIds: rt.array(rt.string), -}); - -export const deleteTimelinesSchema = rt.intersection([baseDeleteTimelinesSchema, searchId]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts new file mode 100644 index 0000000000000..32acc2b0fdb29 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + DeleteTimelinesRequestBody, + DeleteTimelinesResponse, +} from './delete_timelines/delete_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts index 7f6339ee25929..4eea80daa0fcd 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts @@ -6,9 +6,12 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { ConfigType } from '../../../../..'; -import { deleteTimelinesSchema } from '../../../../../../common/api/timeline'; +import { + DeleteTimelinesRequestBody, + type DeleteTimelinesResponse, +} from '../../../../../../common/api/timeline/routes'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; @@ -29,7 +32,7 @@ export const deleteTimelinesRoute = (router: SecuritySolutionPluginRouter, confi { version: '2023-10-31', validate: { - request: { body: buildRouteValidationWithExcess(deleteTimelinesSchema) }, + request: { body: buildRouteValidationWithZod(DeleteTimelinesRequestBody) }, }, }, async (context, request, response) => { @@ -40,7 +43,8 @@ export const deleteTimelinesRoute = (router: SecuritySolutionPluginRouter, confi const { savedObjectIds, searchIds } = request.body; await deleteTimeline(frameworkRequest, savedObjectIds, searchIds); - return response.ok({ body: { data: { deleteTimeline: true } } }); + const body: DeleteTimelinesResponse = { data: { deleteTimeline: true } }; + return response.ok({ body }); } catch (err) { const error = transformError(err); return siemResponse.error({ From c8c23d5eeff80a6cfc7b3d1e77559c717757ca06 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 2 Aug 2024 12:04:38 +0200 Subject: [PATCH 02/73] clean draft timeline, delete/persist note, delete timeline --- .../clean_draft_timelines_route.ts | 14 ------- .../delete_note/delete_note_route.gen.ts | 8 ++-- .../delete_note/delete_note_route.schema.yaml | 1 + .../timeline/delete_note/delete_note_route.ts | 14 ------- .../common/api/timeline/index.ts | 6 +-- .../common/api/timeline/model/api.ts | 16 +++---- .../api/timeline/model/components.gen.ts | 22 +++++++++- .../api/timeline/model/components.schema.yaml | 25 +++++++++++ .../persist_note/persist_note_route.gen.ts | 13 +++--- .../persist_note_route.schema.yaml | 22 ++++++---- .../persist_note/persist_note_route.ts | 40 ------------------ .../common/api/timeline/routes.ts | 9 ++++ .../clean_draft_timelines/index.ts | 9 ++-- .../lib/timeline/routes/notes/delete_note.ts | 42 +++++++++---------- .../lib/timeline/routes/notes/persist_note.ts | 12 ++++-- .../timelines/delete_timelines/index.ts | 2 +- .../saved_object/notes/saved_object.ts | 4 +- 17 files changed, 125 insertions(+), 134 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.ts delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.ts delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.ts deleted file mode 100644 index fd967824370ea..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.ts +++ /dev/null @@ -1,14 +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 rt from 'io-ts'; - -import { TimelineTypeLiteralRt } from '../model/api'; - -export const cleanDraftTimelineSchema = rt.type({ - timelineType: TimelineTypeLiteralRt, -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.gen.ts index eceda37016443..41ea42c927ea6 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.gen.ts @@ -23,9 +23,11 @@ export const DeleteNoteRequestBody = z.union([ noteId: z.string(), }) .nullable(), - z.object({ - noteIds: z.array(z.string()).nullable(), - }), + z + .object({ + noteIds: z.array(z.string()).nullable(), + }) + .nullable(), ]); export type DeleteNoteRequestBodyInput = z.input; diff --git a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml index b330cc82d2fdc..2fb9ecd320094 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml @@ -33,6 +33,7 @@ paths: type: string - type: object required: [noteIds] + nullable: true properties: noteIds: type: array diff --git a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.ts b/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.ts deleted file mode 100644 index 717440fa0717a..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.ts +++ /dev/null @@ -1,14 +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 runtimeTypes from 'io-ts'; -import { unionWithNullType } from '../../../utility_types'; - -export const deleteNoteSchema = runtimeTypes.partial({ - noteId: unionWithNullType(runtimeTypes.string), - noteIds: unionWithNullType(runtimeTypes.array(runtimeTypes.string)), -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 6229b07c53a9f..eb4b04bc0732c 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -6,18 +6,16 @@ */ export * from './model/api'; -export * from './clean_draft_timelines/clean_draft_timelines_route'; +export * from './routes'; + export * from './get_draft_timelines/get_draft_timelines_route'; export * from './create_timelines/create_timelines_route'; -export * from './delete_note/delete_note_route'; -export * from './delete_timelines/delete_timelines_route'; export * from './export_timelines/export_timelines_route'; export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; export * from './import_timelines/import_timelines_route'; export * from './patch_timelines/patch_timelines_schema'; export * from './persist_favorite/persist_favorite_route'; -export * from './persist_note/persist_note_route'; export * from './pinned_events/pinned_events_route'; export * from './install_prepackaged_timelines/install_prepackaged_timelines'; export * from './copy_timeline/copy_timeline_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 1e40484505d1b..2ac6bd7553435 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -17,7 +17,9 @@ import { PinnedEventRuntimeType } from '../pinned_events/pinned_events_route'; import { ErrorSchema } from './error_schema'; import type { DataProviderType } from './components.gen'; import { + BareNote, DataProviderTypeEnum, + type Note, RowRendererId, RowRendererIdEnum, SortFieldTimeline, @@ -31,8 +33,10 @@ import { } from './components.gen'; export { + BareNote, DataProviderType, DataProviderTypeEnum, + Note, RowRendererId, RowRendererIdEnum, SortFieldTimeline, @@ -83,8 +87,6 @@ export const BareNoteSchema = runtimeTypes.intersection([ }), ]); -export type BareNote = runtimeTypes.TypeOf; - /** * This type represents a note type stored in a saved object that does not include any fields that reference * other saved objects. @@ -109,15 +111,7 @@ export const NoteRuntimeType = runtimeTypes.intersection([ }), ]); -export type Note = runtimeTypes.TypeOf; - -export interface ResponseNote { - code?: Maybe; - - message?: Maybe; - - note: Note; -} +// type Note = runtimeTypes.TypeOf; /* * ColumnHeader Types diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index f0c8985241c05..79ca05b13d051 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -227,8 +227,8 @@ export const BareNote = z.object({ export type Note = z.infer; export const Note = BareNote.merge( z.object({ - noteId: z.string().optional(), - version: z.string().optional(), + noteId: z.string(), + version: z.string(), }) ); @@ -269,6 +269,24 @@ export const FavoriteTimelineResponse = z.object({ favorite: z.array(FavoriteTimelineResult).optional(), }); +export type BareNoteWithoutExternalRefs = z.infer; +export const BareNoteWithoutExternalRefs = z.object({ + eventId: z.string().nullable().optional(), + note: z.string().nullable().optional(), + timelineId: z.string().nullable().optional(), + created: z.number().nullable().optional(), + createdBy: z.string().nullable().optional(), + updated: z.number().nullable().optional(), + updatedBy: z.string().nullable().optional(), +}); + +export type ResponseNote = z.infer; +export const ResponseNote = z.object({ + code: z.number(), + message: z.string(), + note: Note, +}); + export type GlobalNote = z.infer; export const GlobalNote = z.object({ noteId: z.string().optional(), diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index d5d4af4cb1e24..61c94b8f53cdc 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -305,6 +305,30 @@ components: nullable: true queryMatch: $ref: '#/components/schemas/QueryMatchResult' + BareNoteWithoutExternalRefs: + type: object + properties: + eventId: + type: string + nullable: true + note: + type: string + nullable: true + timelineId: + type: string + nullable: true + created: + type: number + nullable: true + createdBy: + type: string + nullable: true + updated: + type: number + nullable: true + updatedBy: + type: string + nullable: true BareNote: type: object required: [timelineId] @@ -334,6 +358,7 @@ components: allOf: - $ref: '#/components/schemas/BareNote' - type: object + required: [noteId, version] properties: noteId: type: string diff --git a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.gen.ts index 5cbb0464218fb..ac191fde2aca8 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.gen.ts @@ -18,6 +18,13 @@ import { z } from 'zod'; import { BareNote, Note } from '../model/components.gen'; +export type ResponseNote = z.infer; +export const ResponseNote = z.object({ + code: z.number(), + message: z.string(), + note: Note, +}); + export type PersistNoteRouteRequestBody = z.infer; export const PersistNoteRouteRequestBody = z.object({ note: BareNote, @@ -33,10 +40,6 @@ export type PersistNoteRouteRequestBodyInput = z.input; export const PersistNoteRouteResponse = z.object({ data: z.object({ - persistNote: z.object({ - code: z.number(), - message: z.string(), - note: Note, - }), + persistNote: ResponseNote, }), }); diff --git a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml index e5de10d97e013..a74b50f4156e2 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml @@ -64,12 +64,16 @@ paths: required: [persistNote] properties: persistNote: - type: object - required: [code, message, note] - properties: - code: - type: number - message: - type: string - note: - $ref: '../model/components.schema.yaml#/components/schemas/Note' + $ref: '#/components/schemas/ResponseNote' +components: + schemas: + ResponseNote: + type: object + required: [code, message, note] + properties: + code: + type: number + message: + type: string + note: + $ref: '../model/components.schema.yaml#/components/schemas/Note' diff --git a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.ts b/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.ts deleted file mode 100644 index e6f8b9cc94fd3..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.ts +++ /dev/null @@ -1,40 +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 runtimeTypes from 'io-ts'; -import { unionWithNullType } from '../../../utility_types'; -import { BareNoteSchema, BareNoteWithoutExternalRefsSchema } from '../model/api'; - -export const persistNoteWithRefSchema = runtimeTypes.intersection([ - runtimeTypes.type({ - note: BareNoteSchema, - }), - runtimeTypes.partial({ - overrideOwner: unionWithNullType(runtimeTypes.boolean), - noteId: unionWithNullType(runtimeTypes.string), - version: unionWithNullType(runtimeTypes.string), - }), -]); - -export const persistNoteWithoutRefSchema = runtimeTypes.intersection([ - runtimeTypes.type({ - note: BareNoteWithoutExternalRefsSchema, - }), - runtimeTypes.partial({ - overrideOwner: unionWithNullType(runtimeTypes.boolean), - noteId: unionWithNullType(runtimeTypes.string), - version: unionWithNullType(runtimeTypes.string), - eventIngested: unionWithNullType(runtimeTypes.string), - eventTimestamp: unionWithNullType(runtimeTypes.string), - eventDataView: unionWithNullType(runtimeTypes.string), - }), -]); - -export const persistNoteSchema = runtimeTypes.union([ - persistNoteWithRefSchema, - persistNoteWithoutRefSchema, -]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 32acc2b0fdb29..122568a0c0e76 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -9,3 +9,12 @@ export { DeleteTimelinesRequestBody, DeleteTimelinesResponse, } from './delete_timelines/delete_timelines_route.gen'; + +export { + PersistNoteRouteRequestBody, + PersistNoteRouteResponse, + ResponseNote, +} from './persist_note/persist_note_route.gen'; +export { DeleteNoteRequestBody, DeleteNoteResponse } from './delete_note/delete_note_route.gen'; + +export { CleanDraftTimelinesRequestBody } from './clean_draft_timelines/clean_draft_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts index f8b9ad8392982..387720b4a3b4f 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts @@ -7,13 +7,13 @@ import { v4 as uuidv4 } from 'uuid'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import type { ConfigType } from '../../../../..'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { TIMELINE_DRAFT_URL } from '../../../../../../common/constants'; import { buildFrameworkRequest } from '../../../utils/common'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import { getDraftTimeline, resetTimeline, @@ -21,7 +21,10 @@ import { persistTimeline, } from '../../../saved_object/timelines'; import { draftTimelineDefaults } from '../../../utils/default_timeline'; -import { cleanDraftTimelineSchema, TimelineTypeEnum } from '../../../../../../common/api/timeline'; +import { + CleanDraftTimelinesRequestBody, + TimelineTypeEnum, +} from '../../../../../../common/api/timeline'; export const cleanDraftTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { router.versioned @@ -35,7 +38,7 @@ export const cleanDraftTimelinesRoute = (router: SecuritySolutionPluginRouter, _ .addVersion( { validate: { - request: { body: buildRouteValidationWithExcess(cleanDraftTimelineSchema) }, + request: { body: buildRouteValidationWithZod(CleanDraftTimelinesRequestBody) }, }, version: '2023-10-31', }, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts index 318d8950bc619..92be926453403 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts @@ -6,17 +6,17 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { NOTE_URL } from '../../../../../common/constants'; -import { buildRouteValidationWithExcess } from '../../../../utils/build_validation/route_validation'; import type { ConfigType } from '../../../..'; import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; -import { deleteNoteSchema } from '../../../../../common/api/timeline'; +import { DeleteNoteRequestBody, type DeleteNoteResponse } from '../../../../../common/api/timeline'; import { deleteNote } from '../../saved_object/notes'; export const deleteNoteRoute = (router: SecuritySolutionPluginRouter, config: ConfigType) => { @@ -31,7 +31,7 @@ export const deleteNoteRoute = (router: SecuritySolutionPluginRouter, config: Co .addVersion( { validate: { - request: { body: buildRouteValidationWithExcess(deleteNoteSchema) }, + request: { body: buildRouteValidationWithZod(DeleteNoteRequestBody) }, }, version: '2023-10-31', }, @@ -40,27 +40,25 @@ export const deleteNoteRoute = (router: SecuritySolutionPluginRouter, config: Co try { const frameworkRequest = await buildFrameworkRequest(context, request); - const noteId = request.body?.noteId ?? ''; - const noteIds = request.body?.noteIds ?? null; - if (noteIds != null) { - await deleteNote({ - request: frameworkRequest, - noteIds, - }); + if (!request.body) { + throw new Error('Missing request body'); + } + let noteIds: string[] = []; + if ('noteId' in request.body) { + noteIds = [request.body.noteId]; + } else if ('noteIds' in request.body && Array.isArray(request.body.noteIds)) { + noteIds = request.body.noteIds; + } - return response.ok({ - body: { data: {} }, - }); - } else { - await deleteNote({ - request: frameworkRequest, - noteIds: [noteId], - }); + await deleteNote({ + request: frameworkRequest, + noteIds, + }); - return response.ok({ - body: { data: {} }, - }); - } + const body: DeleteNoteResponse = { data: {} }; + return response.ok({ + body, + }); } catch (err) { const error = transformError(err); return siemResponse.error({ diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts index 1bd91306a7419..7ee0dc886a787 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts @@ -6,17 +6,20 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { NOTE_URL } from '../../../../../common/constants'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import type { ConfigType } from '../../../..'; import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; -import { persistNoteWithoutRefSchema } from '../../../../../common/api/timeline'; +import { + PersistNoteRouteRequestBody, + type PersistNoteRouteResponse, +} from '../../../../../common/api/timeline'; import { persistNote } from '../../saved_object/notes'; export const persistNoteRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { @@ -31,7 +34,7 @@ export const persistNoteRoute = (router: SecuritySolutionPluginRouter, _: Config .addVersion( { validate: { - request: { body: buildRouteValidation(persistNoteWithoutRefSchema) }, + request: { body: buildRouteValidationWithZod(PersistNoteRouteRequestBody) }, }, version: '2023-10-31', }, @@ -49,9 +52,10 @@ export const persistNoteRoute = (router: SecuritySolutionPluginRouter, _: Config note, overrideOwner: true, }); + const body: PersistNoteRouteResponse = { data: { persistNote: res } }; return response.ok({ - body: { data: { persistNote: res } }, + body, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts index 4eea80daa0fcd..a11b16c96fb1f 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts @@ -11,7 +11,7 @@ import type { ConfigType } from '../../../../..'; import { DeleteTimelinesRequestBody, type DeleteTimelinesResponse, -} from '../../../../../../common/api/timeline/routes'; +} from '../../../../../../common/api/timeline'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts index ff277a4bea9e0..2144cf5c420af 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts @@ -133,7 +133,7 @@ export const createNote = async ({ noteId: string | null; note: BareNote | BareNoteWithoutExternalRefs; overrideOwner?: boolean; -}) => { +}): Promise => { const savedObjectsClient = (await request.context.core).savedObjects.client; const userInfo = request.user; @@ -201,7 +201,7 @@ export const updateNote = async ({ noteId: string; note: BareNote | BareNoteWithoutExternalRefs; overrideOwner?: boolean; -}) => { +}): Promise => { const savedObjectsClient = (await request.context.core).savedObjects.client; const userInfo = request.user; From c2a5c9d76d605f48d3ad9a63daba01a530d83209 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 2 Aug 2024 13:01:09 +0200 Subject: [PATCH 03/73] export timelines --- .../export_timelines/export_timelines_route.ts | 17 ----------------- .../common/api/timeline/index.ts | 1 - .../common/api/timeline/routes.ts | 5 +++++ .../routes/timelines/export_timelines/index.ts | 10 +++++----- 4 files changed, 10 insertions(+), 23 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.ts deleted file mode 100644 index cc391a47e0b9e..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.ts +++ /dev/null @@ -1,17 +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 rt from 'io-ts'; -import { unionWithNullType } from '../../../utility_types'; - -export const exportTimelinesQuerySchema = rt.type({ - file_name: rt.string, -}); - -export const exportTimelinesRequestBodySchema = rt.partial({ - ids: unionWithNullType(rt.array(rt.string)), -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index eb4b04bc0732c..33ecf2eb4a000 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -10,7 +10,6 @@ export * from './routes'; export * from './get_draft_timelines/get_draft_timelines_route'; export * from './create_timelines/create_timelines_route'; -export * from './export_timelines/export_timelines_route'; export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; export * from './import_timelines/import_timelines_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 122568a0c0e76..5c443a89252f5 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -18,3 +18,8 @@ export { export { DeleteNoteRequestBody, DeleteNoteResponse } from './delete_note/delete_note_route.gen'; export { CleanDraftTimelinesRequestBody } from './clean_draft_timelines/clean_draft_timelines_route.gen'; + +export { + ExportTimelinesRequestQuery, + ExportTimelinesRequestBody, +} from './export_timelines/export_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.ts index 7af6b7be0cdd0..163b212840423 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.ts @@ -6,16 +6,16 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { TIMELINE_EXPORT_URL } from '../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import type { ConfigType } from '../../../../../config'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { - exportTimelinesQuerySchema, - exportTimelinesRequestBodySchema, + ExportTimelinesRequestQuery, + ExportTimelinesRequestBody, } from '../../../../../../common/api/timeline'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import { buildFrameworkRequest } from '../../../utils/common'; import { getExportTimelineByObjectIds } from './helpers'; @@ -35,8 +35,8 @@ export const exportTimelinesRoute = (router: SecuritySolutionPluginRouter, confi { validate: { request: { - query: buildRouteValidationWithExcess(exportTimelinesQuerySchema), - body: buildRouteValidationWithExcess(exportTimelinesRequestBodySchema), + query: buildRouteValidationWithZod(ExportTimelinesRequestQuery), + body: buildRouteValidationWithZod(ExportTimelinesRequestBody), }, }, version: '2023-10-31', From 96ce48affe349068a5dc80ca049525ac5b4e1538 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 2 Aug 2024 16:31:15 +0200 Subject: [PATCH 04/73] persist timeline favorite --- .../common/api/timeline/index.ts | 1 - .../common/api/timeline/model/api.ts | 24 +++---------------- .../persist_favorite_route.ts | 18 -------------- .../common/api/timeline/routes.ts | 5 ++++ .../public/timelines/containers/api.ts | 12 ++++------ .../store/middlewares/timeline_favorite.ts | 4 ++-- .../timelines/persist_favorite/index.ts | 22 ++++++++++------- .../timeline/saved_object/timelines/index.ts | 4 ++-- 8 files changed, 30 insertions(+), 60 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 33ecf2eb4a000..806c0c8539d97 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -14,7 +14,6 @@ export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; export * from './import_timelines/import_timelines_route'; export * from './patch_timelines/patch_timelines_schema'; -export * from './persist_favorite/persist_favorite_route'; export * from './pinned_events/pinned_events_route'; export * from './install_prepackaged_timelines/install_prepackaged_timelines'; export * from './copy_timeline/copy_timeline_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 2ac6bd7553435..9d66adc94a770 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -19,6 +19,8 @@ import type { DataProviderType } from './components.gen'; import { BareNote, DataProviderTypeEnum, + FavoriteTimelineResponse, + type FavoriteTimelineResult, type Note, RowRendererId, RowRendererIdEnum, @@ -36,6 +38,7 @@ export { BareNote, DataProviderType, DataProviderTypeEnum, + FavoriteTimelineResponse, Note, RowRendererId, RowRendererIdEnum, @@ -483,27 +486,6 @@ export const importTimelineResultSchema = runtimeTypes.exact( export type ImportTimelineResultSchema = runtimeTypes.TypeOf; -const favoriteTimelineResult = runtimeTypes.partial({ - fullName: unionWithNullType(runtimeTypes.string), - userName: unionWithNullType(runtimeTypes.string), - favoriteDate: unionWithNullType(runtimeTypes.number), -}); - -export type FavoriteTimelineResult = runtimeTypes.TypeOf; - -export const responseFavoriteTimeline = runtimeTypes.partial({ - savedObjectId: runtimeTypes.string, - version: runtimeTypes.string, - code: unionWithNullType(runtimeTypes.number), - message: unionWithNullType(runtimeTypes.string), - templateTimelineId: unionWithNullType(runtimeTypes.string), - templateTimelineVersion: unionWithNullType(runtimeTypes.number), - timelineType: unionWithNullType(TimelineTypeLiteralRt), - favorite: unionWithNullType(runtimeTypes.array(favoriteTimelineResult)), -}); - -export type ResponseFavoriteTimeline = runtimeTypes.TypeOf; - export const pageInfoTimeline = runtimeTypes.type({ pageIndex: runtimeTypes.number, pageSize: runtimeTypes.number, diff --git a/x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.ts b/x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.ts deleted file mode 100644 index 0f4adff41c910..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.ts +++ /dev/null @@ -1,18 +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 rt from 'io-ts'; - -import { TimelineTypeLiteralRt } from '../model/api'; -import { unionWithNullType } from '../../../utility_types'; - -export const persistFavoriteSchema = rt.type({ - timelineId: unionWithNullType(rt.string), - templateTimelineId: unionWithNullType(rt.string), - templateTimelineVersion: unionWithNullType(rt.number), - timelineType: unionWithNullType(TimelineTypeLiteralRt), -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 5c443a89252f5..5f27f59131c3d 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -23,3 +23,8 @@ export { ExportTimelinesRequestQuery, ExportTimelinesRequestBody, } from './export_timelines/export_timelines_route.gen'; + +export { + PersistFavoriteRouteResponse, + PersistFavoriteRouteRequestBody, +} from './persist_favorite/persist_favorite_route.gen'; diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index a6e1f448f5191..155d95c5acef2 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -17,7 +17,6 @@ import type { TimelineResponse, TimelineErrorResponse, ImportTimelineResultSchema, - ResponseFavoriteTimeline, AllTimelinesResponse, SingleTimelineResponse, SingleTimelineResolveResponse, @@ -29,7 +28,7 @@ import { TimelineErrorResponseType, importTimelineResultSchema, allTimelinesResponse, - responseFavoriteTimeline, + PersistFavoriteRouteResponse, SingleTimelineResponseType, type TimelineType, TimelineTypeEnum, @@ -105,11 +104,8 @@ const decodePrepackedTimelineResponse = (respTimeline?: ImportTimelineResultSche fold(throwErrors(createToasterPlainError), identity) ); -const decodeResponseFavoriteTimeline = (respTimeline?: ResponseFavoriteTimeline) => - pipe( - responseFavoriteTimeline.decode(respTimeline), - fold(throwErrors(createToasterPlainError), identity) - ); +const decodeResponseFavoriteTimeline = (respTimeline?: PersistFavoriteRouteResponse) => + PersistFavoriteRouteResponse.parse(respTimeline); const postTimeline = async ({ timeline, @@ -469,7 +465,7 @@ export const persistFavorite = async ({ return Promise.reject(new Error(`Failed to stringify query: ${JSON.stringify(err)}`)); } - const response = await KibanaServices.get().http.patch( + const response = await KibanaServices.get().http.patch( TIMELINE_FAVORITE_URL, { method: 'PATCH', diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_favorite.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_favorite.ts index 17fd55ee194c1..bf4854e60666b 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_favorite.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_favorite.ts @@ -17,7 +17,7 @@ import { startTimelineSaving, showCallOutUnauthorizedMsg, } from '../actions'; -import type { ResponseFavoriteTimeline } from '../../../../common/api/timeline'; +import type { FavoriteTimelineResponse } from '../../../../common/api/timeline'; import { TimelineTypeEnum } from '../../../../common/api/timeline'; import { persistFavorite } from '../../containers/api'; import { selectTimelineById } from '../selectors'; @@ -49,7 +49,7 @@ export const favoriteTimelineMiddleware: (kibana: CoreStart) => Middleware<{}, S timelineType: timeline.timelineType ?? TimelineTypeEnum.default, }); - const response: ResponseFavoriteTimeline = get('data.persistFavorite', result); + const response: FavoriteTimelineResponse = get('data.persistFavorite', result); if (response.code === 403) { store.dispatch(showCallOutUnauthorizedMsg()); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts index f53acf25803a8..b8416b9ffe7bc 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts @@ -6,18 +6,22 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_FAVORITE_URL } from '../../../../../../common/constants'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import type { ConfigType } from '../../../../..'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; import { persistFavorite } from '../../../saved_object/timelines'; -import { TimelineTypeEnum, persistFavoriteSchema } from '../../../../../../common/api/timeline'; +import { + type PersistFavoriteRouteResponse, + PersistFavoriteRouteRequestBody, + TimelineTypeEnum, +} from '../../../../../../common/api/timeline'; export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { router.versioned @@ -32,7 +36,7 @@ export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter, _: Co { version: '2023-10-31', validate: { - request: { body: buildRouteValidationWithExcess(persistFavoriteSchema) }, + request: { body: buildRouteValidationWithZod(PersistFavoriteRouteRequestBody) }, }, }, async (context, request, response) => { @@ -51,12 +55,14 @@ export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter, _: Co timelineType || TimelineTypeEnum.default ); - return response.ok({ - body: { - data: { - persistFavorite: timeline, - }, + const body: PersistFavoriteRouteResponse = { + data: { + persistFavorite: timeline, }, + }; + + return response.ok({ + body, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts index 71d61c22ab33c..08eeda3d8ab56 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts @@ -23,7 +23,7 @@ import type { ExportTimelineNotFoundError, PageInfoTimeline, ResponseTimelines, - ResponseFavoriteTimeline, + FavoriteTimelineResponse, ResponseTimeline, SortTimeline, TimelineResult, @@ -312,7 +312,7 @@ export const persistFavorite = async ( templateTimelineId: string | null, templateTimelineVersion: number | null, timelineType: TimelineType -): Promise => { +): Promise => { const userName = request.user?.username ?? UNAUTHENTICATED_USER; const fullName = request.user?.full_name ?? ''; try { From cb64f0e8329157fb9c782772de5fda6b4b4ee3dc Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 6 Aug 2024 14:47:49 +0200 Subject: [PATCH 05/73] other routes --- .../import_timelines_route.ts | 2 +- .../common/api/timeline/model/api.ts | 5 +++- .../api/timeline/model/components.gen.ts | 21 +++++++------ .../api/timeline/model/components.schema.yaml | 18 +++++++---- .../pinned_events/pinned_events_route.gen.ts | 19 ++++++++---- .../pinned_events_route.schema.yaml | 26 +++++++++++----- .../pinned_events/pinned_events_route.ts | 30 ++----------------- .../common/api/timeline/routes.ts | 6 ++++ .../timelines/containers/pinned_event/api.ts | 15 ++++++---- .../middlewares/timeline_pinned_event.ts | 9 +++--- .../pinned_events/persist_pinned_event.ts | 16 +++++++--- .../saved_object/pinned_events/index.ts | 28 +++++++---------- 12 files changed, 103 insertions(+), 92 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts index ecd40bab9476b..2ad6f3f8c7333 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts @@ -10,7 +10,7 @@ import * as rt from 'io-ts'; import { BareNoteSchema, SavedTimelineRuntimeType } from '../model/api'; import { unionWithNullType } from '../../../utility_types'; -import { pinnedEventIds } from '../pinned_events/pinned_events_route'; +const pinnedEventIds = unionWithNullType(rt.array(rt.string)); export const eventNotes = unionWithNullType(rt.array(BareNoteSchema)); export const globalNotes = unionWithNullType(rt.array(BareNoteSchema)); diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 9d66adc94a770..7268070a2fa1f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -12,16 +12,17 @@ import { stringEnum, unionWithNullType } from '../../../utility_types'; import type { Maybe } from '../../../search_strategy'; import { Direction } from '../../../search_strategy'; -import type { PinnedEvent } from '../pinned_events/pinned_events_route'; import { PinnedEventRuntimeType } from '../pinned_events/pinned_events_route'; import { ErrorSchema } from './error_schema'; import type { DataProviderType } from './components.gen'; import { BareNote, + BarePinnedEvent, DataProviderTypeEnum, FavoriteTimelineResponse, type FavoriteTimelineResult, type Note, + PinnedEvent, RowRendererId, RowRendererIdEnum, SortFieldTimeline, @@ -36,10 +37,12 @@ import { export { BareNote, + BarePinnedEvent, DataProviderType, DataProviderTypeEnum, FavoriteTimelineResponse, Note, + PinnedEvent, RowRendererId, RowRendererIdEnum, SortFieldTimeline, diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index 79ca05b13d051..c56d5dbd1c192 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -232,18 +232,24 @@ export const Note = BareNote.merge( }) ); -export type PinnedEvent = z.infer; -export const PinnedEvent = z.object({ - pinnedEventId: z.string(), +export type BarePinnedEvent = z.infer; +export const BarePinnedEvent = z.object({ eventId: z.string(), timelineId: z.string(), created: z.number().nullable().optional(), createdBy: z.string().nullable().optional(), updated: z.number().nullable().optional(), updatedBy: z.string().nullable().optional(), - version: z.string(), }); +export type PinnedEvent = z.infer; +export const PinnedEvent = BarePinnedEvent.merge( + z.object({ + pinnedEventId: z.string(), + version: z.string(), + }) +); + export type TimelineResponse = z.infer; export const TimelineResponse = SavedTimeline.merge( z.object({ @@ -280,13 +286,6 @@ export const BareNoteWithoutExternalRefs = z.object({ updatedBy: z.string().nullable().optional(), }); -export type ResponseNote = z.infer; -export const ResponseNote = z.object({ - code: z.number(), - message: z.string(), - note: Note, -}); - export type GlobalNote = z.infer; export const GlobalNote = z.object({ noteId: z.string().optional(), diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index 61c94b8f53cdc..85cc2cfdbb32e 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -476,12 +476,10 @@ components: serializedQuery: type: string nullable: true - PinnedEvent: + BarePinnedEvent: type: object - required: [eventId, pinnedEventId, timelineId, version] + required: [eventId, timelineId] properties: - pinnedEventId: - type: string eventId: type: string timelineId: @@ -498,8 +496,16 @@ components: updatedBy: type: string nullable: true - version: - type: string + PinnedEvent: + allOf: + - $ref: '#/components/schemas/BarePinnedEvent' + - type: object + required: [pinnedEventId, version] + properties: + pinnedEventId: + type: string + version: + type: string Sort: oneOf: - $ref: '#/components/schemas/SortObject' diff --git a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts index 20556779db7c4..f1da70b48f80f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts @@ -18,6 +18,18 @@ import { z } from 'zod'; import { PinnedEvent } from '../model/components.gen'; +export type PinnedEventBaseResponseBody = z.infer; +export const PinnedEventBaseResponseBody = z.object({ + code: z.number(), + message: z.string().optional(), +}); + +export type PersistPinnedEventResponse = z.infer; +export const PersistPinnedEventResponse = z.union([ + PinnedEvent.merge(PinnedEventBaseResponseBody), + PinnedEventBaseResponseBody, +]); + export type PersistPinnedEventRouteRequestBody = z.infer; export const PersistPinnedEventRouteRequestBody = z.object({ eventId: z.string(), @@ -31,11 +43,6 @@ export type PersistPinnedEventRouteRequestBodyInput = z.input< export type PersistPinnedEventRouteResponse = z.infer; export const PersistPinnedEventRouteResponse = z.object({ data: z.object({ - persistPinnedEventOnTimeline: PinnedEvent.merge( - z.object({ - code: z.number().optional(), - message: z.string().optional(), - }) - ), + persistPinnedEventOnTimeline: PersistPinnedEventResponse, }), }); diff --git a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml index dd16dda4f273c..a6c90ad3e2553 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml @@ -51,11 +51,21 @@ paths: required: [persistPinnedEventOnTimeline] properties: persistPinnedEventOnTimeline: - allOf: - - $ref: '../model/components.schema.yaml#/components/schemas/PinnedEvent' - - type: object - properties: - code: - type: number - message: - type: string + $ref: '#/components/schemas/PersistPinnedEventResponse' + +components: + schemas: + PersistPinnedEventResponse: + oneOf: + - allOf: + - $ref: '../model/components.schema.yaml#/components/schemas/PinnedEvent' + - $ref: '#/components/schemas/PinnedEventBaseResponseBody' + - $ref: '#/components/schemas/PinnedEventBaseResponseBody' + PinnedEventBaseResponseBody: + type: object + required: [code] + properties: + code: + type: number + message: + type: string diff --git a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts index 369cc6cc57089..31c3233e9b8ca 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts @@ -5,26 +5,14 @@ * 2.0. */ -/* eslint-disable @typescript-eslint/no-empty-interface */ - import * as runtimeTypes from 'io-ts'; import { unionWithNullType } from '../../../utility_types'; -export const pinnedEventIds = unionWithNullType(runtimeTypes.array(runtimeTypes.string)); -export const persistPinnedEventSchema = runtimeTypes.intersection([ - runtimeTypes.type({ - eventId: runtimeTypes.string, - timelineId: runtimeTypes.string, - }), - runtimeTypes.partial({ - pinnedEventId: unionWithNullType(runtimeTypes.string), - }), -]); - /* - * Note Types + * Pinned Event Types + * TODO: remove these when the timeline types are moved to zod */ -export const BarePinnedEventType = runtimeTypes.intersection([ +const BarePinnedEventType = runtimeTypes.intersection([ runtimeTypes.type({ timelineId: runtimeTypes.string, eventId: runtimeTypes.string, @@ -37,14 +25,6 @@ export const BarePinnedEventType = runtimeTypes.intersection([ }), ]); -export interface BarePinnedEvent extends runtimeTypes.TypeOf {} - -/** - * This type represents a pinned event type stored in a saved object that does not include any fields that reference - * other saved objects. - */ -export type BarePinnedEventWithoutExternalRefs = Omit; - export const PinnedEventRuntimeType = runtimeTypes.intersection([ runtimeTypes.type({ pinnedEventId: runtimeTypes.string, @@ -52,7 +32,3 @@ export const PinnedEventRuntimeType = runtimeTypes.intersection([ }), BarePinnedEventType, ]); - -export interface PinnedEvent extends runtimeTypes.TypeOf {} - -export type PinnedEventResponse = PinnedEvent & { code: number; message?: string }; diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 5f27f59131c3d..f4246c584f30b 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -28,3 +28,9 @@ export { PersistFavoriteRouteResponse, PersistFavoriteRouteRequestBody, } from './persist_favorite/persist_favorite_route.gen'; + +export { + PersistPinnedEventRouteRequestBody, + PersistPinnedEventResponse, + PersistPinnedEventRouteResponse, +} from './pinned_events/pinned_events_route.gen'; diff --git a/x-pack/plugins/security_solution/public/timelines/containers/pinned_event/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/pinned_event/api.ts index 8eb149f0f43fb..7df7fb7c62b62 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/pinned_event/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/pinned_event/api.ts @@ -5,7 +5,7 @@ * 2.0. */ import { PINNED_EVENT_URL } from '../../../../common/constants'; -import type { PinnedEvent } from '../../../../common/api/timeline'; +import type { PersistPinnedEventRouteResponse } from '../../../../common/api/timeline'; import { KibanaServices } from '../../../common/lib/kibana'; export const persistPinnedEvent = async ({ @@ -23,10 +23,13 @@ export const persistPinnedEvent = async ({ } catch (err) { return Promise.reject(new Error(`Failed to stringify query: ${JSON.stringify(err)}`)); } - const response = await KibanaServices.get().http.patch(PINNED_EVENT_URL, { - method: 'PATCH', - body: requestBody, - version: '2023-10-31', - }); + const response = await KibanaServices.get().http.patch( + PINNED_EVENT_URL, + { + method: 'PATCH', + body: requestBody, + version: '2023-10-31', + } + ); return response; }; diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts index c26c458042dad..83c8351a6dc06 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts @@ -5,14 +5,13 @@ * 2.0. */ -import { get, omit } from 'lodash/fp'; +import { omit } from 'lodash/fp'; import type { Action, Middleware } from 'redux'; import type { CoreStart } from '@kbn/core/public'; import type { State } from '../../../common/store/types'; import { selectTimelineById } from '../selectors'; import * as i18n from '../../pages/translations'; -import type { PinnedEventResponse } from '../../../../common/api/timeline'; import { pinEvent, endTimelineSaving, @@ -65,7 +64,7 @@ export const addPinnedEventToTimelineMiddleware: (kibana: CoreStart) => Middlewa timelineId: timeline.savedObjectId, }); - const response: PinnedEventResponse = get('data.persistPinnedEventOnTimeline', result); + const response = result.data.persistPinnedEventOnTimeline; if (response && response.code === 403) { store.dispatch(showCallOutUnauthorizedMsg()); } @@ -73,9 +72,9 @@ export const addPinnedEventToTimelineMiddleware: (kibana: CoreStart) => Middlewa refreshTimelines(store.getState()); const currentTimeline = selectTimelineById(store.getState(), action.payload.id); - // The response is null in case we unpinned an event. + // The response does not contain the eventId when we unpinned the event. // In that case we want to remove the locally pinned event. - if (!response) { + if (!('eventId' in response)) { return store.dispatch( updateTimeline({ id: action.payload.id, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts index a5739c49a34ea..c1e245cda40fb 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts @@ -6,17 +6,21 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; + import type { SecuritySolutionPluginRouter } from '../../../../types'; import { PINNED_EVENT_URL } from '../../../../../common/constants'; -import { buildRouteValidationWithExcess } from '../../../../utils/build_validation/route_validation'; import type { ConfigType } from '../../../..'; import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; -import { persistPinnedEventSchema } from '../../../../../common/api/timeline'; +import { + type PersistPinnedEventRouteResponse, + PersistPinnedEventRouteRequestBody, +} from '../../../../../common/api/timeline'; import { persistPinnedEventOnTimeline } from '../../saved_object/pinned_events'; export const persistPinnedEventRoute = ( @@ -34,7 +38,7 @@ export const persistPinnedEventRoute = ( .addVersion( { validate: { - request: { body: buildRouteValidationWithExcess(persistPinnedEventSchema) }, + request: { body: buildRouteValidationWithZod(PersistPinnedEventRouteRequestBody) }, }, version: '2023-10-31', }, @@ -54,8 +58,12 @@ export const persistPinnedEventRoute = ( timelineId ); + const body: PersistPinnedEventRouteResponse = { + data: { persistPinnedEventOnTimeline: res }, + }; + return response.ok({ - body: { data: { persistPinnedEventOnTimeline: res } }, + body, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts index 4cb37fd6d6d89..6cb800f00c51c 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts @@ -17,8 +17,7 @@ import { UNAUTHENTICATED_USER } from '../../../../../common/constants'; import type { BarePinnedEvent, PinnedEvent, - PinnedEventResponse, - BarePinnedEventWithoutExternalRefs, + PersistPinnedEventResponse, } from '../../../../../common/api/timeline'; import { SavedObjectPinnedEventRuntimeType } from '../../../../../common/types/timeline/pinned_event/saved_object'; import type { SavedObjectPinnedEventWithoutExternalRefs } from '../../../../../common/types/timeline/pinned_event/saved_object'; @@ -77,12 +76,12 @@ export const persistPinnedEventOnTimeline = async ( pinnedEventId: string | null, // pinned event saved object id eventId: string, timelineId: string -): Promise => { +): Promise => { try { if (pinnedEventId != null) { // Delete Pinned Event on Timeline await deletePinnedEventOnTimeline(request, [pinnedEventId]); - return null; + return { code: 200 }; } const pinnedEvents = await getPinnedEventsInTimelineWithEventId(request, timelineId, eventId); @@ -103,19 +102,14 @@ export const persistPinnedEventOnTimeline = async ( * Why we are doing that, because if it is not found for sure that it will be unpinned * There is no need to bring back this error since we can assume that it is unpinned */ - return null; + return { code: 200 }; } if (getOr(null, 'output.statusCode', err) === 403) { - return pinnedEventId != null - ? { - code: 403, - message: err.message, - pinnedEventId: eventId, - timelineId: '', - version: '', - eventId: '', - } - : null; + return { + code: 403, + message: err.message, + pinnedEventId: eventId, + }; } throw err; } @@ -140,7 +134,7 @@ const createPinnedEvent = async ({ request: FrameworkRequest; eventId: string; timelineId: string; -}): Promise => { +}): Promise => { const savedObjectsClient = (await request.context.core).savedObjects.client; const savedPinnedEvent: BarePinnedEvent = { @@ -151,7 +145,7 @@ const createPinnedEvent = async ({ const pinnedEventWithCreator = pickSavedPinnedEvent(null, savedPinnedEvent, request.user); const { transformedFields: migratedAttributes, references } = - pinnedEventFieldsMigrator.extractFieldsToReferences({ + pinnedEventFieldsMigrator.extractFieldsToReferences>({ data: pinnedEventWithCreator, }); From 3df3a2edee522447b8fc5a76b4c7efbf6017cef1 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 6 Aug 2024 15:29:20 +0200 Subject: [PATCH 06/73] clean up types --- .../common/api/timeline/model/api.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 7268070a2fa1f..afee07ae38719 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -99,16 +99,6 @@ export const BareNoteSchema = runtimeTypes.intersection([ */ export type BareNoteWithoutExternalRefs = Omit; -export const BareNoteWithoutExternalRefsSchema = runtimeTypes.partial({ - timelineId: unionWithNullType(runtimeTypes.string), - eventId: unionWithNullType(runtimeTypes.string), - note: unionWithNullType(runtimeTypes.string), - created: unionWithNullType(runtimeTypes.number), - createdBy: unionWithNullType(runtimeTypes.string), - updated: unionWithNullType(runtimeTypes.number), - updatedBy: unionWithNullType(runtimeTypes.string), -}); - export const NoteRuntimeType = runtimeTypes.intersection([ BareNoteSchema, runtimeTypes.type({ @@ -117,8 +107,6 @@ export const NoteRuntimeType = runtimeTypes.intersection([ }), ]); -// type Note = runtimeTypes.TypeOf; - /* * ColumnHeader Types */ From 8a6c833e6d00dfa4e145e331f6f32bf895763cad Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 6 Aug 2024 21:18:19 +0200 Subject: [PATCH 07/73] get notes route --- .../timeline/get_notes/get_notes_route.gen.ts | 17 ++++++++++++--- .../get_notes/get_notes_route.schema.yaml | 21 ++++++++++++++++--- .../api/timeline/get_notes/get_notes_route.ts | 19 ----------------- .../common/api/timeline/index.ts | 1 - .../common/api/timeline/routes.ts | 6 ++++++ .../timeline/routes/notes/get_notes.test.ts | 4 ++-- .../lib/timeline/routes/notes/get_notes.ts | 17 ++++++++------- .../saved_object/notes/saved_object.ts | 3 ++- 8 files changed, 51 insertions(+), 37 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts index f97db62d24797..bb754d488d57b 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.gen.ts @@ -16,17 +16,28 @@ import { z } from 'zod'; +import { Note } from '../model/components.gen'; + export type DocumentIds = z.infer; export const DocumentIds = z.union([z.array(z.string()), z.string()]); +export type GetNotesResult = z.infer; +export const GetNotesResult = z.object({ + totalCount: z.number(), + notes: z.array(Note), +}); + export type GetNotesRequestQuery = z.infer; export const GetNotesRequestQuery = z.object({ - documentIds: DocumentIds, - page: z.coerce.number().optional(), - perPage: z.coerce.number().optional(), + documentIds: DocumentIds.optional(), + page: z.string().nullable().optional(), + perPage: z.string().nullable().optional(), search: z.string().nullable().optional(), sortField: z.string().nullable().optional(), sortOrder: z.string().nullable().optional(), filter: z.string().nullable().optional(), }); export type GetNotesRequestQueryInput = z.input; + +export type GetNotesResponse = z.infer; +export const GetNotesResponse = z.union([GetNotesResult, z.object({})]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml index f2e58e2b4e729..ebf517c447aa9 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml @@ -22,18 +22,17 @@ paths: parameters: - name: documentIds in: query - required: true schema: $ref: '#/components/schemas/DocumentIds' - name: page in: query schema: - type: number + type: string nullable: true - name: perPage in: query schema: - type: number + type: string nullable: true - name: search in: query @@ -58,6 +57,12 @@ paths: responses: '200': description: Indicates the requested notes were returned. + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/GetNotesResult' + - type: object components: schemas: @@ -67,3 +72,13 @@ components: items: type: string - type: string + GetNotesResult: + type: object + required: [totalCount, notes] + properties: + totalCount: + type: number + notes: + type: array + items: + $ref: '../model/components.schema.yaml#/components/schemas/Note' diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.ts b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.ts deleted file mode 100644 index 219632fc522e9..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_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 runtimeTypes from 'io-ts'; -import { unionWithNullType } from '../../../utility_types'; - -export const getNotesSchema = runtimeTypes.partial({ - documentIds: runtimeTypes.union([runtimeTypes.array(runtimeTypes.string), runtimeTypes.string]), - page: unionWithNullType(runtimeTypes.string), - perPage: unionWithNullType(runtimeTypes.string), - search: unionWithNullType(runtimeTypes.string), - sortField: unionWithNullType(runtimeTypes.string), - sortOrder: unionWithNullType(runtimeTypes.string), - filter: unionWithNullType(runtimeTypes.string), -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 403154e33d8b5..806c0c8539d97 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -17,4 +17,3 @@ export * from './patch_timelines/patch_timelines_schema'; export * from './pinned_events/pinned_events_route'; export * from './install_prepackaged_timelines/install_prepackaged_timelines'; export * from './copy_timeline/copy_timeline_route'; -export * from './get_notes/get_notes_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index f4246c584f30b..9d3aec839a5c1 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -34,3 +34,9 @@ export { PersistPinnedEventResponse, PersistPinnedEventRouteResponse, } from './pinned_events/pinned_events_route.gen'; + +export { + GetNotesRequestQuery, + GetNotesResponse, + GetNotesResult, +} from './get_notes/get_notes_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.test.ts index db62235ea592f..30ae41c1da820 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.test.ts @@ -13,10 +13,10 @@ import { requestMock, } from '../../../detection_engine/routes/__mocks__'; import { NOTE_URL } from '../../../../../common/constants'; -import type { getNotesSchema } from '../../../../../common/api/timeline'; +import type { GetNotesRequestQuery } from '../../../../../common/api/timeline'; import { mockGetCurrentUser } from '../../__mocks__/import_timelines'; -const getAllNotesRequest = (query?: typeof getNotesSchema) => +const getAllNotesRequest = (query?: GetNotesRequestQuery) => requestMock.create({ method: 'get', path: NOTE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts index 8e8a88a4a6aa9..9cc8435d6aae0 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts @@ -7,6 +7,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import type { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { NOTE_URL } from '../../../../../common/constants'; @@ -14,10 +15,9 @@ import type { ConfigType } from '../../../..'; import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; -import { getNotesSchema } from '../../../../../common/api/timeline'; -import { buildRouteValidationWithExcess } from '../../../../utils/build_validation/route_validation'; import { getAllSavedNote, MAX_UNASSOCIATED_NOTES } from '../../saved_object/notes'; import { noteSavedObjectType } from '../../saved_object_mappings/notes'; +import { GetNotesRequestQuery, type GetNotesResponse } from '../../../../../common/api/timeline'; export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { router.versioned @@ -31,7 +31,7 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp .addVersion( { validate: { - request: { query: buildRouteValidationWithExcess(getNotesSchema) }, + request: { query: buildRouteValidationWithZod(GetNotesRequestQuery) }, }, version: '2023-10-31', }, @@ -50,8 +50,8 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp perPage: MAX_UNASSOCIATED_NOTES, }; const res = await getAllSavedNote(frameworkRequest, options); - - return response.ok({ body: res ?? {} }); + const body: GetNotesResponse = res ?? {}; + return response.ok({ body }); } else { const options = { type: noteSavedObjectType, @@ -60,8 +60,8 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp perPage: MAX_UNASSOCIATED_NOTES, }; const res = await getAllSavedNote(frameworkRequest, options); - - return response.ok({ body: res ?? {} }); + const body: GetNotesResponse = res ?? {}; + return response.ok({ body }); } } else { const perPage = queryParams?.perPage ? parseInt(queryParams.perPage, 10) : 10; @@ -80,7 +80,8 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp filter, }; const res = await getAllSavedNote(frameworkRequest, options); - return response.ok({ body: res ?? {} }); + const body: GetNotesResponse = res ?? {}; + return response.ok({ body }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts index 2144cf5c420af..300903f8b22ee 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts @@ -22,6 +22,7 @@ import type { BareNote, BareNoteWithoutExternalRefs, ResponseNote, + GetNotesResult, } from '../../../../../common/api/timeline'; import { SavedObjectNoteRuntimeType } from '../../../../../common/types/timeline/note/saved_object'; import type { SavedObjectNoteWithoutExternalRefs } from '../../../../../common/types/timeline/note/saved_object'; @@ -261,7 +262,7 @@ const getSavedNote = async (request: FrameworkRequest, NoteId: string) => { export const getAllSavedNote = async ( request: FrameworkRequest, options: SavedObjectsFindOptions -) => { +): Promise => { const savedObjectsClient = (await request.context.core).savedObjects.client; const savedObjects = await savedObjectsClient.find(options); From 3bc8d839184e40ed115fb97aebf6c52d890e130a Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 6 Aug 2024 21:33:36 +0200 Subject: [PATCH 08/73] `timelineId` is not nullabled --- .../common/api/timeline/model/components.gen.ts | 2 +- .../common/api/timeline/model/components.schema.yaml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index c56d5dbd1c192..102ca64b0fc50 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -217,7 +217,7 @@ export type BareNote = z.infer; export const BareNote = z.object({ eventId: z.string().nullable().optional(), note: z.string().nullable().optional(), - timelineId: z.string().nullable(), + timelineId: z.string(), created: z.number().nullable().optional(), createdBy: z.string().nullable().optional(), updated: z.number().nullable().optional(), diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index 85cc2cfdbb32e..c8ba2e6019f16 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -341,7 +341,6 @@ components: nullable: true timelineId: type: string - nullable: true created: type: number nullable: true From 093c41f5c331a1eae542cce6469c3ba2dd085e78 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:19:51 +0000 Subject: [PATCH 09/73] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...imeline_api_2023_10_31.bundled.schema.yaml | 128 +++++++++++------- ...imeline_api_2023_10_31.bundled.schema.yaml | 128 +++++++++++------- 2 files changed, 164 insertions(+), 92 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index e658a2df0284c..c05fd43f759d8 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -28,7 +28,8 @@ paths: type: string required: - noteId - - type: object + - nullable: true + type: object properties: noteIds: items: @@ -59,19 +60,18 @@ paths: parameters: - in: query name: documentIds - required: true schema: $ref: '#/components/schemas/DocumentIds' - in: query name: page schema: nullable: true - type: number + type: string - in: query name: perPage schema: nullable: true - type: number + type: string - in: query name: search schema: @@ -94,6 +94,12 @@ paths: type: string responses: '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/GetNotesResult' + - type: object description: Indicates the requested notes were returned. summary: Get all notes for a given document. tags: @@ -142,18 +148,7 @@ paths: type: object properties: persistNote: - type: object - properties: - code: - type: number - message: - type: string - note: - $ref: '#/components/schemas/Note' - required: - - code - - message - - note + $ref: '#/components/schemas/ResponseNote' required: - persistNote required: @@ -195,14 +190,7 @@ paths: type: object properties: persistPinnedEventOnTimeline: - allOf: - - $ref: '#/components/schemas/PinnedEvent' - - type: object - properties: - code: - type: number - message: - type: string + $ref: '#/components/schemas/PersistPinnedEventResponse' required: - persistPinnedEventOnTimeline required: @@ -989,8 +977,28 @@ components: nullable: true type: string timelineId: + type: string + updated: + nullable: true + type: number + updatedBy: nullable: true type: string + required: + - timelineId + BarePinnedEvent: + type: object + properties: + created: + nullable: true + type: number + createdBy: + nullable: true + type: string + eventId: + type: string + timelineId: + type: string updated: nullable: true type: number @@ -998,6 +1006,7 @@ components: nullable: true type: string required: + - eventId - timelineId ColumnHeaderResult: type: object @@ -1171,6 +1180,18 @@ components: type: string script: type: string + GetNotesResult: + type: object + properties: + notes: + items: + $ref: '#/components/schemas/Note' + type: array + totalCount: + type: number + required: + - totalCount + - notes ImportTimelineResult: type: object properties: @@ -1231,34 +1252,36 @@ components: type: string version: type: string + required: + - noteId + - version + PersistPinnedEventResponse: + oneOf: + - allOf: + - $ref: '#/components/schemas/PinnedEvent' + - $ref: '#/components/schemas/PinnedEventBaseResponseBody' + - $ref: '#/components/schemas/PinnedEventBaseResponseBody' PinnedEvent: + allOf: + - $ref: '#/components/schemas/BarePinnedEvent' + - type: object + properties: + pinnedEventId: + type: string + version: + type: string + required: + - pinnedEventId + - version + PinnedEventBaseResponseBody: type: object properties: - created: - nullable: true - type: number - createdBy: - nullable: true - type: string - eventId: - type: string - pinnedEventId: - type: string - timelineId: - type: string - updated: - nullable: true + code: type: number - updatedBy: - nullable: true - type: string - version: + message: type: string required: - - eventId - - pinnedEventId - - timelineId - - version + - code QueryMatchResult: type: object properties: @@ -1303,6 +1326,19 @@ components: type: object readable: type: boolean + ResponseNote: + type: object + properties: + code: + type: number + message: + type: string + note: + $ref: '#/components/schemas/Note' + required: + - code + - message + - note RowRendererId: enum: - alert diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index d3b079e0551ab..396b9a62d72d1 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -28,7 +28,8 @@ paths: type: string required: - noteId - - type: object + - nullable: true + type: object properties: noteIds: items: @@ -59,19 +60,18 @@ paths: parameters: - in: query name: documentIds - required: true schema: $ref: '#/components/schemas/DocumentIds' - in: query name: page schema: nullable: true - type: number + type: string - in: query name: perPage schema: nullable: true - type: number + type: string - in: query name: search schema: @@ -94,6 +94,12 @@ paths: type: string responses: '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/GetNotesResult' + - type: object description: Indicates the requested notes were returned. summary: Get all notes for a given document. tags: @@ -142,18 +148,7 @@ paths: type: object properties: persistNote: - type: object - properties: - code: - type: number - message: - type: string - note: - $ref: '#/components/schemas/Note' - required: - - code - - message - - note + $ref: '#/components/schemas/ResponseNote' required: - persistNote required: @@ -195,14 +190,7 @@ paths: type: object properties: persistPinnedEventOnTimeline: - allOf: - - $ref: '#/components/schemas/PinnedEvent' - - type: object - properties: - code: - type: number - message: - type: string + $ref: '#/components/schemas/PersistPinnedEventResponse' required: - persistPinnedEventOnTimeline required: @@ -989,8 +977,28 @@ components: nullable: true type: string timelineId: + type: string + updated: + nullable: true + type: number + updatedBy: nullable: true type: string + required: + - timelineId + BarePinnedEvent: + type: object + properties: + created: + nullable: true + type: number + createdBy: + nullable: true + type: string + eventId: + type: string + timelineId: + type: string updated: nullable: true type: number @@ -998,6 +1006,7 @@ components: nullable: true type: string required: + - eventId - timelineId ColumnHeaderResult: type: object @@ -1171,6 +1180,18 @@ components: type: string script: type: string + GetNotesResult: + type: object + properties: + notes: + items: + $ref: '#/components/schemas/Note' + type: array + totalCount: + type: number + required: + - totalCount + - notes ImportTimelineResult: type: object properties: @@ -1231,34 +1252,36 @@ components: type: string version: type: string + required: + - noteId + - version + PersistPinnedEventResponse: + oneOf: + - allOf: + - $ref: '#/components/schemas/PinnedEvent' + - $ref: '#/components/schemas/PinnedEventBaseResponseBody' + - $ref: '#/components/schemas/PinnedEventBaseResponseBody' PinnedEvent: + allOf: + - $ref: '#/components/schemas/BarePinnedEvent' + - type: object + properties: + pinnedEventId: + type: string + version: + type: string + required: + - pinnedEventId + - version + PinnedEventBaseResponseBody: type: object properties: - created: - nullable: true - type: number - createdBy: - nullable: true - type: string - eventId: - type: string - pinnedEventId: - type: string - timelineId: - type: string - updated: - nullable: true + code: type: number - updatedBy: - nullable: true - type: string - version: + message: type: string required: - - eventId - - pinnedEventId - - timelineId - - version + - code QueryMatchResult: type: object properties: @@ -1303,6 +1326,19 @@ components: type: object readable: type: boolean + ResponseNote: + type: object + properties: + code: + type: number + message: + type: string + note: + $ref: '#/components/schemas/Note' + required: + - code + - message + - note RowRendererId: enum: - alert From e86eaf748d576a25aeb2c3b9fd957275c6450b79 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 7 Aug 2024 13:45:17 +0200 Subject: [PATCH 10/73] re-introduce BarePinnedEventWithoutExternalRefs --- .../plugins/security_solution/common/api/timeline/model/api.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index afee07ae38719..ff6707b700626 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -55,6 +55,8 @@ export { TimelineTypeEnum, }; +export type BarePinnedEventWithoutExternalRefs = Omit; + /** * Outcome is a property of the saved object resolve api * will tell us info about the rule after 8.0 migrations From e808a9e694519a5c316b8e9b84254f5ac49d0c7b Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 7 Aug 2024 13:51:55 +0200 Subject: [PATCH 11/73] fix tests --- .../timelines/store/middlewares/timeline_pinned_event.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.test.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.test.ts index 4c303b1414515..67374a66019db 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.test.ts @@ -66,6 +66,7 @@ describe('Timeline pinned event middleware', () => { data: { persistPinnedEventOnTimeline: { code: 200, + eventId: testEventId, }, }, }); From b29f60a186550ef9e046dc4ef01443757ab70c2c Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 7 Aug 2024 14:04:29 +0200 Subject: [PATCH 12/73] fix tests --- .../routes/timelines/export_timelines/index.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.test.ts index 13b6e0f68fefc..ade95ba75c837 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.test.ts @@ -93,9 +93,7 @@ describe('export timelines', () => { }); const result = server.validate(request); - expect(result.badRequest.mock.calls[0][0]).toEqual( - 'Invalid value {"id":"someId"}, excess properties: ["id"]' - ); + expect(result.badRequest.mock.calls[0][0]).toEqual('file_name: Required'); }); test('return validation error for request params', async () => { @@ -107,9 +105,7 @@ describe('export timelines', () => { }); const result = server.validate(request); - expect(result.badRequest.mock.calls[0][0]).toEqual( - 'Invalid value "someId" supplied to "ids"' - ); + expect(result.badRequest.mock.calls[0][0]).toEqual('ids: Expected array, received string'); }); }); }); From 829d4659f6f96adb1550ce1fd5719fe749348d86 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 7 Aug 2024 14:07:17 +0200 Subject: [PATCH 13/73] fix tests --- .../trial_license_complete_tier/pinned_events.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts index 9273a5d6c6a5e..95c960f975e31 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts @@ -39,7 +39,7 @@ export default function ({ getService }: FtrProviderContext) { }); describe('Unpinned an event', () => { - it('return null', async () => { + it('returns {code: 200}', async () => { const response = await supertest .patch('/api/pinned_event') .set('elastic-api-version', '2023-10-31') @@ -61,7 +61,7 @@ export default function ({ getService }: FtrProviderContext) { eventId, timelineId, }); - expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.be(null); + expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.be({ code: 200 }); }); }); }); From 12a46460da713c6fd50f51fa55406223003b59e1 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 7 Aug 2024 15:28:57 +0200 Subject: [PATCH 14/73] be -> equal --- .../saved_objects/trial_license_complete_tier/pinned_events.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts index 95c960f975e31..ab2bb75554eb8 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts @@ -61,7 +61,7 @@ export default function ({ getService }: FtrProviderContext) { eventId, timelineId, }); - expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.be({ code: 200 }); + expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.equal({ code: 200 }); }); }); }); From 210888b375fd7ca07447ec8dec986a002df95534 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 7 Aug 2024 21:24:11 +0200 Subject: [PATCH 15/73] fix tests --- .../saved_objects/trial_license_complete_tier/pinned_events.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts index ab2bb75554eb8..937f688683897 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts @@ -61,7 +61,7 @@ export default function ({ getService }: FtrProviderContext) { eventId, timelineId, }); - expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.equal({ code: 200 }); + expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.eql({ code: 200 }); }); }); }); From 6afe200fba08b9d055301463d3e42e3457def737 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 8 Aug 2024 09:50:59 +0200 Subject: [PATCH 16/73] prevent API breaking change --- .../pinned_events/pinned_events_route.gen.ts | 2 +- .../pinned_events_route.schema.yaml | 3 ++- .../store/middlewares/timeline_pinned_event.ts | 6 +++--- .../timeline/saved_object/pinned_events/index.ts | 16 +++++++++------- .../trial_license_complete_tier/pinned_events.ts | 2 +- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts index f1da70b48f80f..92d9904e5dbdb 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.gen.ts @@ -27,7 +27,7 @@ export const PinnedEventBaseResponseBody = z.object({ export type PersistPinnedEventResponse = z.infer; export const PersistPinnedEventResponse = z.union([ PinnedEvent.merge(PinnedEventBaseResponseBody), - PinnedEventBaseResponseBody, + z.object({}).nullable(), ]); export type PersistPinnedEventRouteRequestBody = z.infer; diff --git a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml index a6c90ad3e2553..fc54c7aaeb1b2 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml @@ -60,7 +60,8 @@ components: - allOf: - $ref: '../model/components.schema.yaml#/components/schemas/PinnedEvent' - $ref: '#/components/schemas/PinnedEventBaseResponseBody' - - $ref: '#/components/schemas/PinnedEventBaseResponseBody' + - type: object + nullable: true PinnedEventBaseResponseBody: type: object required: [code] diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts index 83c8351a6dc06..38e00af3f5f8e 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_pinned_event.ts @@ -65,16 +65,16 @@ export const addPinnedEventToTimelineMiddleware: (kibana: CoreStart) => Middlewa }); const response = result.data.persistPinnedEventOnTimeline; - if (response && response.code === 403) { + if (response && 'code' in response && response.code === 403) { store.dispatch(showCallOutUnauthorizedMsg()); } refreshTimelines(store.getState()); const currentTimeline = selectTimelineById(store.getState(), action.payload.id); - // The response does not contain the eventId when we unpinned the event. + // The response is null or empty in case we unpinned an event. // In that case we want to remove the locally pinned event. - if (!('eventId' in response)) { + if (!response || !('eventId' in response)) { return store.dispatch( updateTimeline({ id: action.payload.id, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts index 6cb800f00c51c..5181a099ae7fb 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts @@ -81,7 +81,7 @@ export const persistPinnedEventOnTimeline = async ( if (pinnedEventId != null) { // Delete Pinned Event on Timeline await deletePinnedEventOnTimeline(request, [pinnedEventId]); - return { code: 200 }; + return null; } const pinnedEvents = await getPinnedEventsInTimelineWithEventId(request, timelineId, eventId); @@ -102,14 +102,16 @@ export const persistPinnedEventOnTimeline = async ( * Why we are doing that, because if it is not found for sure that it will be unpinned * There is no need to bring back this error since we can assume that it is unpinned */ - return { code: 200 }; + return null; } if (getOr(null, 'output.statusCode', err) === 403) { - return { - code: 403, - message: err.message, - pinnedEventId: eventId, - }; + return pinnedEventId != null + ? { + code: 403, + message: err.message, + pinnedEventId: eventId, + } + : null; } throw err; } diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts index 937f688683897..091d47514eb10 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts @@ -61,7 +61,7 @@ export default function ({ getService }: FtrProviderContext) { eventId, timelineId, }); - expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.eql({ code: 200 }); + expect(responseToTest.body.data!.persistPinnedEventOnTimeline).to.be(null); }); }); }); From c8e1786181549e41d34d20a980182af4a5f99f80 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 8 Aug 2024 11:59:17 +0200 Subject: [PATCH 17/73] copy timeline route --- .../copy_timeline/copy_timeline_route.gen.ts | 35 +++++++++ .../copy_timeline_route.schema.yaml | 53 +++++++++++++ .../copy_timeline/copy_timeline_route.ts | 15 ---- .../common/api/timeline/index.ts | 1 - .../common/api/timeline/model/api.ts | 6 +- .../api/timeline/model/components.gen.ts | 75 ++++++++++--------- .../api/timeline/model/components.schema.yaml | 54 +++++++++++-- .../common/api/timeline/routes.ts | 5 ++ .../routes/timelines/copy_timeline/index.ts | 13 ++-- .../services/security_solution_api.gen.ts | 16 ++++ 10 files changed, 206 insertions(+), 67 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts new file mode 100644 index 0000000000000..798e5fa1a2656 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Elastic Security - Timeline - Copy Timeline API + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { SavedTimeline, TimelineResponse } from '../model/components.gen'; + +export type CopyTimelineRequestBody = z.infer; +export const CopyTimelineRequestBody = z.object({ + timeline: SavedTimeline, + timelineIdToCopy: z.string(), +}); +export type CopyTimelineRequestBodyInput = z.input; + +export type CopyTimelineResponse = z.infer; +export const CopyTimelineResponse = z.object({ + data: z.object({ + persistTimeline: z.object({ + timeline: TimelineResponse, + }), + }), +}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml new file mode 100644 index 0000000000000..217c856493827 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml @@ -0,0 +1,53 @@ +openapi: 3.0.0 +info: + title: Elastic Security - Timeline - Copy Timeline API + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/timeline/_copy: + post: + x-labels: [serverless, ess] + x-codegen-enabled: true + operationId: CopyTimeline + summary: Copies timeline or timeline template. + description: | + Copies and returns a timeline or timeline template. + tags: + - access:securitySolution + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [timeline, timelineIdToCopy] + properties: + timeline: + $ref: '../model/components.schema.yaml#/components/schemas/SavedTimeline' + timelineIdToCopy: + type: string + responses: + '200': + description: Indicates that the timeline has been successfully copied. + content: + application/json: + schema: + type: object + required: [data] + properties: + data: + type: object + required: [persistTimeline] + properties: + persistTimeline: + type: object + required: [timeline] + properties: + timeline: + $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.ts b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.ts deleted file mode 100644 index 1b7dc1d4c3566..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.ts +++ /dev/null @@ -1,15 +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 rt from 'io-ts'; - -import { SavedTimelineRuntimeType } from '../model/api'; - -export const copyTimelineSchema = rt.type({ - timeline: SavedTimelineRuntimeType, - timelineIdToCopy: rt.string, -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 806c0c8539d97..fcb4e54bf6469 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -16,4 +16,3 @@ export * from './import_timelines/import_timelines_route'; export * from './patch_timelines/patch_timelines_schema'; export * from './pinned_events/pinned_events_route'; export * from './install_prepackaged_timelines/install_prepackaged_timelines'; -export * from './copy_timeline/copy_timeline_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index ff6707b700626..a7aff47f38ef0 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -25,6 +25,7 @@ import { PinnedEvent, RowRendererId, RowRendererIdEnum, + SavedTimeline, SortFieldTimeline, SortFieldTimelineEnum, TemplateTimelineType, @@ -45,6 +46,7 @@ export { PinnedEvent, RowRendererId, RowRendererIdEnum, + SavedTimeline, SortFieldTimeline, SortFieldTimelineEnum, TemplateTimelineType, @@ -314,8 +316,6 @@ export const SavedTimelineRuntimeType = runtimeTypes.partial({ savedSearchId: unionWithNullType(runtimeTypes.string), }); -export type SavedTimeline = runtimeTypes.TypeOf; - export type SavedTimelineWithSavedObjectId = SavedTimeline & { savedObjectId?: string | null; }; @@ -505,7 +505,7 @@ export interface ColumnHeaderResult { category?: Maybe; columnHeaderType?: Maybe; description?: Maybe; - example?: Maybe; + example?: Maybe; indexes?: Maybe; id?: Maybe; name?: Maybe; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index 102ca64b0fc50..cf6972c0a821c 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -42,24 +42,24 @@ export const TemplateTimelineTypeEnum = TemplateTimelineType.enum; export type ColumnHeaderResult = z.infer; export const ColumnHeaderResult = z.object({ - aggregatable: z.boolean().optional(), - category: z.string().optional(), - columnHeaderType: z.string().optional(), - description: z.string().optional(), - example: z.union([z.string(), z.number()]).optional(), - indexes: z.array(z.string()).optional(), - id: z.string().optional(), - name: z.string().optional(), - placeholder: z.string().optional(), - searchable: z.boolean().optional(), - type: z.string().optional(), + aggregatable: z.boolean().nullable().optional(), + category: z.string().nullable().optional(), + columnHeaderType: z.string().nullable().optional(), + description: z.string().nullable().optional(), + example: z.string().nullable().optional(), + indexes: z.array(z.string()).nullable().optional(), + id: z.string().nullable().optional(), + name: z.string().nullable().optional(), + placeholder: z.string().nullable().optional(), + searchable: z.boolean().nullable().optional(), + type: z.string().nullable().optional(), }); export type QueryMatchResult = z.infer; export const QueryMatchResult = z.object({ field: z.string().nullable().optional(), displayField: z.string().nullable().optional(), - value: z.string().nullable().optional(), + value: z.union([z.string().nullable(), z.array(z.string()).nullable()]).optional(), displayValue: z.string().nullable().optional(), operator: z.string().nullable().optional(), }); @@ -71,7 +71,7 @@ export const DataProviderQueryMatch = z.object({ id: z.string().nullable().optional(), kqlQuery: z.string().nullable().optional(), name: z.string().nullable().optional(), - queryMatch: QueryMatchResult.optional(), + queryMatch: QueryMatchResult.nullable().optional(), }); export type DataProviderResult = z.infer; @@ -119,27 +119,28 @@ export const FavoriteTimelineResult = z.object({ export type FilterTimelineResult = z.infer; export const FilterTimelineResult = z.object({ - exists: z.boolean().optional(), + exists: z.string().nullable().optional(), meta: z .object({ - alias: z.string().optional(), - controlledBy: z.string().optional(), - disabled: z.boolean().optional(), - field: z.string().optional(), - formattedValue: z.string().optional(), - index: z.string().optional(), - key: z.string().optional(), - negate: z.boolean().optional(), - params: z.string().optional(), - type: z.string().optional(), - value: z.string().optional(), + alias: z.string().nullable().optional(), + controlledBy: z.string().nullable().optional(), + disabled: z.boolean().nullable().optional(), + field: z.string().nullable().optional(), + formattedValue: z.string().nullable().optional(), + index: z.string().nullable().optional(), + key: z.string().nullable().optional(), + negate: z.boolean().nullable().optional(), + params: z.string().nullable().optional(), + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), }) + .nullable() .optional(), - match_all: z.string().optional(), - missing: z.string().optional(), - query: z.string().optional(), - range: z.string().optional(), - script: z.string().optional(), + match_all: z.string().nullable().optional(), + missing: z.string().nullable().optional(), + query: z.string().nullable().optional(), + range: z.string().nullable().optional(), + script: z.string().nullable().optional(), }); export type SerializedFilterQueryResult = z.infer; @@ -178,8 +179,8 @@ export const SavedTimeline = z.object({ dataViewId: z.string().nullable().optional(), dateRange: z .object({ - end: z.union([z.string(), z.number()]).optional(), - start: z.union([z.string(), z.number()]).optional(), + end: z.union([z.string().nullable(), z.number().nullable()]).optional(), + start: z.union([z.string().nullable(), z.number().nullable()]).optional(), }) .nullable() .optional(), @@ -253,11 +254,11 @@ export const PinnedEvent = BarePinnedEvent.merge( export type TimelineResponse = z.infer; export const TimelineResponse = SavedTimeline.merge( z.object({ - eventIdToNoteIds: z.array(Note).optional(), - notes: z.array(Note).optional(), - noteIds: z.array(z.string()).optional(), - pinnedEventIds: z.array(z.string()).optional(), - pinnedEventsSaveObject: z.array(PinnedEvent).optional(), + eventIdToNoteIds: z.array(Note).nullable().optional(), + notes: z.array(Note).nullable().optional(), + noteIds: z.array(z.string()).nullable().optional(), + pinnedEventIds: z.array(z.string()).nullable().optional(), + pinnedEventsSaveObject: z.array(PinnedEvent).nullable().optional(), savedObjectId: z.string(), version: z.string(), }) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index c8ba2e6019f16..5d8167bc012db 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -56,11 +56,15 @@ components: end: oneOf: - type: string + nullable: true - type: number + nullable: true start: oneOf: - type: string + nullable: true - type: number + nullable: true description: type: string nullable: true @@ -159,22 +163,27 @@ components: properties: eventIdToNoteIds: type: array + nullable: true items: $ref: '#/components/schemas/Note' notes: type: array + nullable: true items: $ref: '#/components/schemas/Note' noteIds: type: array + nullable: true items: type: string pinnedEventIds: type: array + nullable: true items: type: string pinnedEventsSaveObject: type: array + nullable: true items: $ref: '#/components/schemas/PinnedEvent' savedObjectId: @@ -214,30 +223,39 @@ components: properties: aggregatable: type: boolean + nullable: true category: type: string + nullable: true columnHeaderType: type: string + nullable: true description: type: string + nullable: true example: - oneOf: - - type: string - - type: number + type: string + nullable: true indexes: type: array + nullable: true items: type: string id: type: string + nullable: true name: type: string + nullable: true placeholder: type: string + nullable: true searchable: type: boolean + nullable: true type: type: string + nullable: true QueryMatchResult: type: object properties: @@ -248,8 +266,13 @@ components: type: string nullable: true value: - type: string - nullable: true + oneOf: + - type: string + nullable: true + - type: array + nullable: true + items: + type: string displayValue: type: string nullable: true @@ -305,6 +328,7 @@ components: nullable: true queryMatch: $ref: '#/components/schemas/QueryMatchResult' + nullable: true BareNoteWithoutExternalRefs: type: object properties: @@ -419,42 +443,60 @@ components: type: object properties: exists: - type: boolean + type: string + nullable: true meta: type: object + nullable: true properties: alias: type: string + nullable: true controlledBy: type: string + nullable: true disabled: type: boolean + nullable: true field: type: string + nullable: true formattedValue: type: string + nullable: true index: type: string + nullable: true key: type: string + nullable: true negate: type: boolean + nullable: true params: type: string + nullable: true type: type: string + nullable: true value: type: string + nullable: true match_all: type: string + nullable: true missing: type: string + nullable: true query: type: string + nullable: true range: type: string + nullable: true script: type: string + nullable: true SerializedFilterQueryResult: type: object properties: diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 9d3aec839a5c1..c7efce924164e 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -40,3 +40,8 @@ export { GetNotesResponse, GetNotesResult, } from './get_notes/get_notes_route.gen'; + +export { + CopyTimelineRequestBody, + CopyTimelineResponse, +} from './copy_timeline/copy_timeline_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts index 5bdb4e0f93d67..ad5565da5f088 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts @@ -6,9 +6,12 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { ConfigType } from '../../../../..'; -import { copyTimelineSchema } from '../../../../../../common/api/timeline'; +import { + CopyTimelineRequestBody, + type CopyTimelineResponse, +} from '../../../../../../common/api/timeline'; import { copyTimeline } from '../../../saved_object/timelines'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_COPY_URL } from '../../../../../../common/constants'; @@ -29,7 +32,7 @@ export const copyTimelineRoute = (router: SecuritySolutionPluginRouter, _: Confi { version: '1', validate: { - request: { body: buildRouteValidationWithExcess(copyTimelineSchema) }, + request: { body: buildRouteValidationWithZod(CopyTimelineRequestBody) }, }, }, async (context, request, response) => { @@ -39,9 +42,9 @@ export const copyTimelineRoute = (router: SecuritySolutionPluginRouter, _: Confi const frameworkRequest = await buildFrameworkRequest(context, request); const { timeline, timelineIdToCopy } = request.body; const copiedTimeline = await copyTimeline(frameworkRequest, timeline, timelineIdToCopy); - + const body: CopyTimelineResponse = { data: { persistTimeline: copiedTimeline } }; return response.ok({ - body: { data: { persistTimeline: copiedTimeline } }, + body, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index ef706d2aca2cd..b8fd92bd25ab0 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -28,6 +28,7 @@ import { BulkPatchRulesRequestBodyInput } from '@kbn/security-solution-plugin/co import { BulkUpdateRulesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.gen'; import { BulkUpsertAssetCriticalityRecordsRequestBodyInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.gen'; import { CleanDraftTimelinesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.gen'; +import { CopyTimelineRequestBodyInput } from '@kbn/security-solution-plugin/common/api/timeline/copy_timeline/copy_timeline_route.gen'; import { CreateAlertsMigrationRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.gen'; import { CreateAssetCriticalityRecordRequestBodyInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/asset_criticality/create_asset_criticality.gen'; import { CreateRuleRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.gen'; @@ -232,6 +233,18 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(props.body as object); }, + /** + * Copies and returns a timeline or timeline template. + + */ + copyTimeline(props: CopyTimelineProps) { + return supertest + .post('/api/timeline/_copy') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, createAlertsIndex() { return supertest .post('/api/detection_engine/index') @@ -1054,6 +1067,9 @@ export interface BulkUpsertAssetCriticalityRecordsProps { export interface CleanDraftTimelinesProps { body: CleanDraftTimelinesRequestBodyInput; } +export interface CopyTimelineProps { + body: CopyTimelineRequestBodyInput; +} export interface CreateAlertsMigrationProps { body: CreateAlertsMigrationRequestBodyInput; } From 31bc0e19ed3e0ec5f844d3bcce34a95d6134447b Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 8 Aug 2024 12:49:33 +0200 Subject: [PATCH 18/73] create timelines routes --- .../create_timelines_route.gen.ts | 6 ++-- .../create_timelines_route.schema.yaml | 8 ++--- .../create_timelines_route.ts | 36 ------------------- .../common/api/timeline/index.ts | 1 - .../common/api/timeline/routes.ts | 5 +++ .../timeline/__mocks__/request_responses.ts | 4 +-- .../timelines/create_timelines/index.ts | 10 +++--- .../services/security_solution_api.gen.ts | 2 +- 8 files changed, 21 insertions(+), 51 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts index 9b5775ca81617..be334ac8288c1 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts @@ -17,21 +17,21 @@ import { z } from 'zod'; import { + SavedTimeline, TimelineStatus, TimelineType, - SavedTimeline, TimelineResponse, } from '../model/components.gen'; export type CreateTimelinesRequestBody = z.infer; export const CreateTimelinesRequestBody = z.object({ + timeline: SavedTimeline, status: TimelineStatus.nullable().optional(), timelineId: z.string().nullable().optional(), templateTimelineId: z.string().nullable().optional(), templateTimelineVersion: z.number().nullable().optional(), timelineType: TimelineType.nullable().optional(), version: z.string().nullable().optional(), - timeline: SavedTimeline, }); export type CreateTimelinesRequestBodyInput = z.input; @@ -39,7 +39,7 @@ export type CreateTimelinesResponse = z.infer; export const CreateTimelinesResponse = z.object({ data: z.object({ persistTimeline: z.object({ - timeline: TimelineResponse.optional(), + timeline: TimelineResponse, }), }), }); diff --git a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml index 561ce75c84fe2..321feef64eb5a 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml @@ -28,9 +28,10 @@ paths: application/json: schema: type: object - required: - - timeline + required: [timeline] properties: + timeline: + $ref: '../model/components.schema.yaml#/components/schemas/SavedTimeline' status: $ref: '../model/components.schema.yaml#/components/schemas/TimelineStatus' nullable: true @@ -49,8 +50,6 @@ paths: version: type: string nullable: true - timeline: - $ref: '../model/components.schema.yaml#/components/schemas/SavedTimeline' responses: '200': description: Indicates the timeline was successfully created. @@ -66,6 +65,7 @@ paths: properties: persistTimeline: type: object + required: [timeline] properties: timeline: $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' diff --git a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.ts deleted file mode 100644 index 1911df3941a35..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.ts +++ /dev/null @@ -1,36 +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 rt from 'io-ts'; - -import type { ResponseTimeline } from '../model/api'; -import { - SavedTimelineRuntimeType, - TimelineStatusLiteralRt, - TimelineTypeLiteralRt, -} from '../model/api'; -import { unionWithNullType } from '../../../utility_types'; - -export const createTimelineSchema = rt.intersection([ - rt.type({ - timeline: SavedTimelineRuntimeType, - }), - rt.partial({ - status: unionWithNullType(TimelineStatusLiteralRt), - timelineId: unionWithNullType(rt.string), - templateTimelineId: unionWithNullType(rt.string), - templateTimelineVersion: unionWithNullType(rt.number), - timelineType: unionWithNullType(TimelineTypeLiteralRt), - version: unionWithNullType(rt.string), - }), -]); - -export interface CreateTimelinesResponse { - data: { - persistTimeline: ResponseTimeline; - }; -} diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index fcb4e54bf6469..68382e1e07cdd 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -9,7 +9,6 @@ export * from './model/api'; export * from './routes'; export * from './get_draft_timelines/get_draft_timelines_route'; -export * from './create_timelines/create_timelines_route'; export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; export * from './import_timelines/import_timelines_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index c7efce924164e..9233c956b1e3f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -45,3 +45,8 @@ export { CopyTimelineRequestBody, CopyTimelineResponse, } from './copy_timeline/copy_timeline_route.gen'; + +export { + CreateTimelinesRequestBody, + CreateTimelinesResponse, +} from './create_timelines/create_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts index eb4649f941d11..6dd2c82319058 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts @@ -18,7 +18,7 @@ import { import type { SavedTimeline, patchTimelineSchema, - createTimelineSchema, + CreateTimelinesRequestBody, GetTimelineQuery, } from '../../../../common/api/timeline'; import { @@ -135,7 +135,7 @@ export const updateTemplateTimelineWithTimelineId = { version: 'WzEyMjUsMV0=', }; -export const getCreateTimelinesRequest = (mockBody: rt.TypeOf) => +export const getCreateTimelinesRequest = (mockBody: CreateTimelinesRequestBody) => requestMock.create({ method: 'post', path: TIMELINE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts index 0fcf286661b96..888669b7e6c88 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts @@ -7,16 +7,15 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import type { IKibanaResponse } from '@kbn/core/server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; import type { ConfigType } from '../../../../..'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; -import { createTimelineSchema } from '../../../../../../common/api/timeline'; import { buildFrameworkRequest, CompareTimelinesStatus, @@ -24,7 +23,10 @@ import { } from '../../../utils/common'; import { DEFAULT_ERROR } from '../../../utils/failure_cases'; import { createTimelines } from './helpers'; -import type { CreateTimelinesResponse } from '../../../../../../common/api/timeline'; +import { + CreateTimelinesRequestBody, + type CreateTimelinesResponse, +} from '../../../../../../common/api/timeline'; export * from './helpers'; @@ -42,7 +44,7 @@ export const createTimelinesRoute = (router: SecuritySolutionPluginRouter, _: Co version: '2023-10-31', validate: { request: { - body: buildRouteValidationWithExcess(createTimelineSchema), + body: buildRouteValidationWithZod(CreateTimelinesRequestBody), }, }, }, diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index b8fd92bd25ab0..7a167c3dadd2e 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -239,7 +239,7 @@ after 30 days. It also deletes other artifacts specific to the migration impleme */ copyTimeline(props: CopyTimelineProps) { return supertest - .post('/api/timeline/_copy') + .get('/api/timeline/_copy') .set('kbn-xsrf', 'true') .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') From 402c1d048ed82a8e833a6b6eba8a4d0457376b2f Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 8 Aug 2024 13:03:11 +0200 Subject: [PATCH 19/73] properly type routes --- .../lib/timeline/routes/notes/delete_note.ts | 10 ++++---- .../lib/timeline/routes/notes/get_notes.ts | 12 ++++------ .../lib/timeline/routes/notes/persist_note.ts | 6 ++--- .../pinned_events/persist_pinned_event.ts | 22 ++++++++---------- .../routes/timelines/copy_timeline/index.ts | 6 ++--- .../timelines/delete_timelines/index.ts | 6 ++--- .../timelines/persist_favorite/index.ts | 23 ++++++++++--------- 7 files changed, 40 insertions(+), 45 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts index 92be926453403..9e6aeb5473fc2 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/delete_note.ts @@ -5,21 +5,20 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { NOTE_URL } from '../../../../../common/constants'; -import type { ConfigType } from '../../../..'; - import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; import { DeleteNoteRequestBody, type DeleteNoteResponse } from '../../../../../common/api/timeline'; import { deleteNote } from '../../saved_object/notes'; -export const deleteNoteRoute = (router: SecuritySolutionPluginRouter, config: ConfigType) => { +export const deleteNoteRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .delete({ path: NOTE_URL, @@ -35,7 +34,7 @@ export const deleteNoteRoute = (router: SecuritySolutionPluginRouter, config: Co }, version: '2023-10-31', }, - async (context, request, response) => { + async (context, request, response): Promise> => { const siemResponse = buildSiemResponse(response); try { @@ -55,9 +54,8 @@ export const deleteNoteRoute = (router: SecuritySolutionPluginRouter, config: Co noteIds, }); - const body: DeleteNoteResponse = { data: {} }; return response.ok({ - body, + body: { data: {} }, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts index 9cc8435d6aae0..3a26f0b1d02d0 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; @@ -35,7 +36,7 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp }, version: '2023-10-31', }, - async (context, request, response) => { + async (context, request, response): Promise> => { try { const queryParams = request.query; const frameworkRequest = await buildFrameworkRequest(context, request); @@ -50,8 +51,7 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp perPage: MAX_UNASSOCIATED_NOTES, }; const res = await getAllSavedNote(frameworkRequest, options); - const body: GetNotesResponse = res ?? {}; - return response.ok({ body }); + return response.ok({ body: res ?? {} }); } else { const options = { type: noteSavedObjectType, @@ -60,8 +60,7 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp perPage: MAX_UNASSOCIATED_NOTES, }; const res = await getAllSavedNote(frameworkRequest, options); - const body: GetNotesResponse = res ?? {}; - return response.ok({ body }); + return response.ok({ body: res ?? {} }); } } else { const perPage = queryParams?.perPage ? parseInt(queryParams.perPage, 10) : 10; @@ -80,8 +79,7 @@ export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigTyp filter, }; const res = await getAllSavedNote(frameworkRequest, options); - const body: GetNotesResponse = res ?? {}; - return response.ok({ body }); + return response.ok({ body: res ?? {} }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts index 7ee0dc886a787..9cc7d801aa733 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../types'; @@ -38,7 +39,7 @@ export const persistNoteRoute = (router: SecuritySolutionPluginRouter, _: Config }, version: '2023-10-31', }, - async (context, request, response) => { + async (context, request, response): Promise> => { const siemResponse = buildSiemResponse(response); try { @@ -52,10 +53,9 @@ export const persistNoteRoute = (router: SecuritySolutionPluginRouter, _: Config note, overrideOwner: true, }); - const body: PersistNoteRouteResponse = { data: { persistNote: res } }; return response.ok({ - body, + body: { data: { persistNote: res } }, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts index c1e245cda40fb..74db9e58d904b 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; @@ -12,8 +13,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../types'; import { PINNED_EVENT_URL } from '../../../../../common/constants'; -import type { ConfigType } from '../../../..'; - import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; @@ -23,10 +22,7 @@ import { } from '../../../../../common/api/timeline'; import { persistPinnedEventOnTimeline } from '../../saved_object/pinned_events'; -export const persistPinnedEventRoute = ( - router: SecuritySolutionPluginRouter, - config: ConfigType -) => { +export const persistPinnedEventRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .patch({ path: PINNED_EVENT_URL, @@ -42,7 +38,11 @@ export const persistPinnedEventRoute = ( }, version: '2023-10-31', }, - async (context, request, response) => { + async ( + context, + request, + response + ): Promise> => { const siemResponse = buildSiemResponse(response); try { @@ -58,12 +58,10 @@ export const persistPinnedEventRoute = ( timelineId ); - const body: PersistPinnedEventRouteResponse = { - data: { persistPinnedEventOnTimeline: res }, - }; - return response.ok({ - body, + body: { + data: { persistPinnedEventOnTimeline: res }, + }, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts index ad5565da5f088..ff9c7ac22d608 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { ConfigType } from '../../../../..'; @@ -35,16 +36,15 @@ export const copyTimelineRoute = (router: SecuritySolutionPluginRouter, _: Confi request: { body: buildRouteValidationWithZod(CopyTimelineRequestBody) }, }, }, - async (context, request, response) => { + async (context, request, response): Promise> => { const siemResponse = buildSiemResponse(response); try { const frameworkRequest = await buildFrameworkRequest(context, request); const { timeline, timelineIdToCopy } = request.body; const copiedTimeline = await copyTimeline(frameworkRequest, timeline, timelineIdToCopy); - const body: CopyTimelineResponse = { data: { persistTimeline: copiedTimeline } }; return response.ok({ - body, + body: { data: { persistTimeline: copiedTimeline } }, }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts index a11b16c96fb1f..4542485ae70d3 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { ConfigType } from '../../../../..'; @@ -35,7 +36,7 @@ export const deleteTimelinesRoute = (router: SecuritySolutionPluginRouter, confi request: { body: buildRouteValidationWithZod(DeleteTimelinesRequestBody) }, }, }, - async (context, request, response) => { + async (context, request, response): Promise> => { const siemResponse = buildSiemResponse(response); try { @@ -43,8 +44,7 @@ export const deleteTimelinesRoute = (router: SecuritySolutionPluginRouter, confi const { savedObjectIds, searchIds } = request.body; await deleteTimeline(frameworkRequest, savedObjectIds, searchIds); - const body: DeleteTimelinesResponse = { data: { deleteTimeline: true } }; - return response.ok({ body }); + return response.ok({ body: { data: { deleteTimeline: true } } }); } catch (err) { const error = transformError(err); return siemResponse.error({ diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts index b8416b9ffe7bc..a846abacc5242 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts @@ -5,14 +5,13 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_FAVORITE_URL } from '../../../../../../common/constants'; -import type { ConfigType } from '../../../../..'; - import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; @@ -23,7 +22,7 @@ import { TimelineTypeEnum, } from '../../../../../../common/api/timeline'; -export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .patch({ path: TIMELINE_FAVORITE_URL, @@ -39,7 +38,11 @@ export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter, _: Co request: { body: buildRouteValidationWithZod(PersistFavoriteRouteRequestBody) }, }, }, - async (context, request, response) => { + async ( + context, + request, + response + ): Promise> => { const siemResponse = buildSiemResponse(response); try { @@ -55,14 +58,12 @@ export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter, _: Co timelineType || TimelineTypeEnum.default ); - const body: PersistFavoriteRouteResponse = { - data: { - persistFavorite: timeline, - }, - }; - return response.ok({ - body, + body: { + data: { + persistFavorite: timeline, + }, + }, }); } catch (err) { const error = transformError(err); From 5f15e272e3a07a4d43d0c710f898a1ca382acf57 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 8 Aug 2024 13:03:21 +0200 Subject: [PATCH 20/73] post -> get --- .../api/timeline/copy_timeline/copy_timeline_route.schema.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml index 217c856493827..8e26439440bf1 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml @@ -11,7 +11,7 @@ servers: default: '5601' paths: /api/timeline/_copy: - post: + get: x-labels: [serverless, ess] x-codegen-enabled: true operationId: CopyTimeline From 1dfa46a9721357652a0487f7446c23bc537941b1 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 8 Aug 2024 13:54:24 +0200 Subject: [PATCH 21/73] patch timeline route --- .../common/api/timeline/index.ts | 1 - .../patch_timelines/patch_timelines_schema.ts | 24 ------------------- .../common/api/timeline/routes.ts | 5 ++++ .../timeline/__mocks__/request_responses.ts | 5 ++-- .../routes/timelines/patch_timelines/index.ts | 12 ++++++---- 5 files changed, 14 insertions(+), 33 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timelines_schema.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 68382e1e07cdd..198f3e4a74ae9 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -12,6 +12,5 @@ export * from './get_draft_timelines/get_draft_timelines_route'; export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; export * from './import_timelines/import_timelines_route'; -export * from './patch_timelines/patch_timelines_schema'; export * from './pinned_events/pinned_events_route'; export * from './install_prepackaged_timelines/install_prepackaged_timelines'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timelines_schema.ts b/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timelines_schema.ts deleted file mode 100644 index 149dc24480d2d..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timelines_schema.ts +++ /dev/null @@ -1,24 +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 rt from 'io-ts'; - -import type { ResponseTimeline } from '../model/api'; -import { SavedTimelineRuntimeType } from '../model/api'; -import { unionWithNullType } from '../../../utility_types'; - -export const patchTimelineSchema = rt.type({ - timeline: SavedTimelineRuntimeType, - timelineId: unionWithNullType(rt.string), - version: unionWithNullType(rt.string), -}); - -export interface PatchTimelinesResponse { - data: { - persistTimeline: ResponseTimeline; - }; -} diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 9233c956b1e3f..5b6c04b9bfbe4 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -50,3 +50,8 @@ export { CreateTimelinesRequestBody, CreateTimelinesResponse, } from './create_timelines/create_timelines_route.gen'; + +export { + PatchTimelineRequestBody, + PatchTimelineResponse, +} from './patch_timelines/patch_timeline_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts index 6dd2c82319058..cde74c095487b 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts @@ -6,7 +6,6 @@ */ import path, { join, resolve } from 'path'; -import type * as rt from 'io-ts'; import { TIMELINE_DRAFT_URL, @@ -17,7 +16,7 @@ import { } from '../../../../common/constants'; import type { SavedTimeline, - patchTimelineSchema, + PatchTimelineRequestBody, CreateTimelinesRequestBody, GetTimelineQuery, } from '../../../../common/api/timeline'; @@ -142,7 +141,7 @@ export const getCreateTimelinesRequest = (mockBody: CreateTimelinesRequestBody) body: mockBody, }); -export const getUpdateTimelinesRequest = (mockBody: rt.TypeOf) => +export const getUpdateTimelinesRequest = (mockBody: PatchTimelineRequestBody) => requestMock.create({ method: 'patch', path: TIMELINE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts index 1c3cba9fdcb91..5554c34305512 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts @@ -7,20 +7,22 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import type { IKibanaResponse } from '@kbn/core/server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import type { ConfigType } from '../../../../..'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; -import { patchTimelineSchema } from '../../../../../../common/api/timeline'; +import { + PatchTimelineRequestBody, + type PatchTimelineResponse, +} from '../../../../../../common/api/timeline'; import { buildFrameworkRequest, TimelineStatusActions } from '../../../utils/common'; import { createTimelines } from '../create_timelines'; import { CompareTimelinesStatus } from '../../../utils/compare_timelines_status'; -import type { PatchTimelinesResponse } from '../../../../../../common/api/timeline'; export const patchTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { router.versioned @@ -34,11 +36,11 @@ export const patchTimelinesRoute = (router: SecuritySolutionPluginRouter, _: Con .addVersion( { validate: { - request: { body: buildRouteValidationWithExcess(patchTimelineSchema) }, + request: { body: buildRouteValidationWithZod(PatchTimelineRequestBody) }, }, version: '2023-10-31', }, - async (context, request, response): Promise> => { + async (context, request, response): Promise> => { const siemResponse = buildSiemResponse(response); try { From ff183d9cde84400431afacfbc5f7f9d2f5e01970 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 8 Aug 2024 17:19:33 +0200 Subject: [PATCH 22/73] import timeline route --- .../import_timelines_route.gen.ts | 6 ++-- .../import_timelines_route.schema.yaml | 11 +++---- .../import_timelines_route.ts | 29 ------------------- .../common/api/timeline/routes.ts | 5 ++++ .../timelines/import_timelines/index.ts | 21 ++++++++++---- 5 files changed, 28 insertions(+), 44 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts index d1bad2e075c86..f4be880d79193 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts @@ -20,12 +20,12 @@ import { Readable, ImportTimelineResult } from '../model/components.gen'; export type ImportTimelinesRequestBody = z.infer; export const ImportTimelinesRequestBody = z.object({ + isImmutable: z.enum(['true', 'false']).optional(), file: Readable.merge( z.object({ hapi: z.object({ filename: z.string(), headers: z.object({}), - isImmutable: z.enum(['true', 'false']).optional(), }), }) ), @@ -33,6 +33,4 @@ export const ImportTimelinesRequestBody = z.object({ export type ImportTimelinesRequestBodyInput = z.input; export type ImportTimelinesResponse = z.infer; -export const ImportTimelinesResponse = z.object({ - data: ImportTimelineResult, -}); +export const ImportTimelinesResponse = ImportTimelineResult; diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml index 9925ae10322e6..73bfaaf322cff 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml @@ -28,7 +28,13 @@ paths: application/json: schema: type: object + required: [file] properties: + isImmutable: + type: string + enum: + - 'true' + - 'false' file: allOf: - $ref: '../model/components.schema.yaml#/components/schemas/Readable' @@ -43,11 +49,6 @@ paths: type: string headers: type: object - isImmutable: - type: string - enum: - - 'true' - - 'false' responses: '200': description: Indicates the import of timelines was successful. diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts index 2ad6f3f8c7333..5dedb6b755c2a 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts @@ -29,32 +29,3 @@ export const ImportTimelinesSchemaRt = rt.intersection([ ]); export type ImportTimelinesSchema = rt.TypeOf; - -const ReadableRt = rt.partial({ - _maxListeners: rt.unknown, - _readableState: rt.unknown, - _read: rt.unknown, - readable: rt.boolean, - _events: rt.unknown, - _eventsCount: rt.number, - _data: rt.unknown, - _position: rt.number, - _encoding: rt.string, -}); - -const booleanInString = rt.union([rt.literal('true'), rt.literal('false')]); - -export const ImportTimelinesPayloadSchemaRt = rt.intersection([ - rt.type({ - file: rt.intersection([ - ReadableRt, - rt.type({ - hapi: rt.type({ - filename: rt.string, - headers: rt.unknown, - }), - }), - ]), - }), - rt.partial({ isImmutable: booleanInString }), -]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 5b6c04b9bfbe4..d448c0466b573 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -55,3 +55,8 @@ export { PatchTimelineRequestBody, PatchTimelineResponse, } from './patch_timelines/patch_timeline_route.gen'; + +export { + ImportTimelinesRequestBody, + ImportTimelinesResponse, +} from './import_timelines/import_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts index be5ebc44e7faa..39c2fbd6738b1 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts @@ -8,17 +8,21 @@ import { extname } from 'path'; import type { Readable } from 'stream'; +import type { IKibanaResponse } from '@kbn/core-http-server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_IMPORT_URL } from '../../../../../../common/constants'; import type { ConfigType } from '../../../../../config'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { importTimelines } from './helpers'; -import { ImportTimelinesPayloadSchemaRt } from '../../../../../../common/api/timeline'; +import { + ImportTimelinesRequestBody, + type ImportTimelinesResponse, +} from '../../../../../../common/api/timeline'; import { buildFrameworkRequest } from '../../../utils/common'; export { importTimelines } from './helpers'; @@ -39,11 +43,13 @@ export const importTimelinesRoute = (router: SecuritySolutionPluginRouter, confi .addVersion( { validate: { - request: { body: buildRouteValidationWithExcess(ImportTimelinesPayloadSchemaRt) }, + request: { + body: buildRouteValidationWithZod(ImportTimelinesRequestBody), + }, }, version: '2023-10-31', }, - async (context, request, response) => { + async (context, request, response): Promise> => { try { const siemResponse = buildSiemResponse(response); const savedObjectsClient = (await context.core).savedObjects.client; @@ -69,8 +75,11 @@ export const importTimelinesRoute = (router: SecuritySolutionPluginRouter, confi frameworkRequest, isImmutable === 'true' ); - if (typeof res !== 'string') return response.ok({ body: res ?? {} }); - else throw res; + if (res instanceof Error || typeof res === 'string') { + throw res; + } else { + return response.ok({ body: res ?? {} }); + } } catch (err) { const error = transformError(err); const siemResponse = buildSiemResponse(response); From a8096b72a1b5fef812342b3195415ff8129f2326 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 13:16:12 +0200 Subject: [PATCH 23/73] import / install timelines --- .../import_timelines_route.gen.ts | 11 +-- .../import_timelines_route.schema.yaml | 21 +----- .../import_timelines_route.ts | 31 -------- .../common/api/timeline/index.ts | 2 - .../install_prepackaged_timelines.ts | 19 ----- ...install_prepackaged_timelines_route.gen.ts | 12 +-- ...ll_prepackaged_timelines_route.schema.yaml | 9 +-- .../common/api/timeline/model/api.ts | 4 + .../api/timeline/model/components.gen.ts | 36 ++++----- .../api/timeline/model/components.schema.yaml | 73 ++++++++++--------- .../common/api/timeline/routes.ts | 5 ++ ...ebuilt_rules_and_timelines_status_route.ts | 9 +-- .../install_prepackaged_timelines/index.ts | 32 ++++---- .../create_timelines_stream_from_ndjson.ts | 29 +++++--- .../timelines/import_timelines/index.test.ts | 46 +----------- .../timelines/import_timelines/index.ts | 11 ++- .../timeline/utils/check_timelines_status.ts | 16 ++-- .../server/lib/timeline/utils/common.ts | 10 ++- 18 files changed, 142 insertions(+), 234 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts index f4be880d79193..90aa71c1ed87f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.gen.ts @@ -16,19 +16,12 @@ import { z } from 'zod'; -import { Readable, ImportTimelineResult } from '../model/components.gen'; +import { ImportTimelineResult } from '../model/components.gen'; export type ImportTimelinesRequestBody = z.infer; export const ImportTimelinesRequestBody = z.object({ isImmutable: z.enum(['true', 'false']).optional(), - file: Readable.merge( - z.object({ - hapi: z.object({ - filename: z.string(), - headers: z.object({}), - }), - }) - ), + file: z.unknown(), }); export type ImportTimelinesRequestBodyInput = z.input; diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml index 73bfaaf322cff..0d495efae8c66 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml @@ -35,31 +35,14 @@ paths: enum: - 'true' - 'false' - file: - allOf: - - $ref: '../model/components.schema.yaml#/components/schemas/Readable' - - type: object - required: [hapi] - properties: - hapi: - type: object - required: [filename, headers] - properties: - filename: - type: string - headers: - type: object + file: {} responses: '200': description: Indicates the import of timelines was successful. content: application/json: schema: - type: object - required: [data] - properties: - data: - $ref: '../model/components.schema.yaml#/components/schemas/ImportTimelineResult' + $ref: '../model/components.schema.yaml#/components/schemas/ImportTimelineResult' '400': description: Indicates the import of timelines was unsuccessful because of an invalid file extension. diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts deleted file mode 100644 index 5dedb6b755c2a..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts +++ /dev/null @@ -1,31 +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 rt from 'io-ts'; - -import { BareNoteSchema, SavedTimelineRuntimeType } from '../model/api'; -import { unionWithNullType } from '../../../utility_types'; - -const pinnedEventIds = unionWithNullType(rt.array(rt.string)); - -export const eventNotes = unionWithNullType(rt.array(BareNoteSchema)); -export const globalNotes = unionWithNullType(rt.array(BareNoteSchema)); - -export const ImportTimelinesSchemaRt = rt.intersection([ - SavedTimelineRuntimeType, - rt.type({ - savedObjectId: unionWithNullType(rt.string), - version: unionWithNullType(rt.string), - }), - rt.type({ - globalNotes, - eventNotes, - pinnedEventIds, - }), -]); - -export type ImportTimelinesSchema = rt.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 198f3e4a74ae9..79438fcbd7d77 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -11,6 +11,4 @@ export * from './routes'; export * from './get_draft_timelines/get_draft_timelines_route'; export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; -export * from './import_timelines/import_timelines_route'; export * from './pinned_events/pinned_events_route'; -export * from './install_prepackaged_timelines/install_prepackaged_timelines'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines.ts b/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines.ts deleted file mode 100644 index 0d9b2d3e81121..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines.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 rt from 'io-ts'; - -import { unionWithNullType } from '../../../utility_types'; -import { ImportTimelinesSchemaRt, TimelineSavedToReturnObjectRuntimeType } from '..'; - -export const checkTimelineStatusRt = rt.type({ - timelinesToInstall: rt.array(unionWithNullType(ImportTimelinesSchemaRt)), - timelinesToUpdate: rt.array(unionWithNullType(ImportTimelinesSchemaRt)), - prepackagedTimelines: rt.array(unionWithNullType(TimelineSavedToReturnObjectRuntimeType)), -}); - -export type CheckTimelineStatusRt = rt.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.gen.ts index befdf84f496e4..f2679fa407d6e 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.gen.ts @@ -16,7 +16,11 @@ import { z } from 'zod'; -import { ImportTimelines, SavedTimeline, ImportTimelineResult } from '../model/components.gen'; +import { + ImportTimelines, + TimelineSavedToReturnObject, + ImportTimelineResult, +} from '../model/components.gen'; export type InstallPrepackedTimelinesRequestBody = z.infer< typeof InstallPrepackedTimelinesRequestBody @@ -24,13 +28,11 @@ export type InstallPrepackedTimelinesRequestBody = z.infer< export const InstallPrepackedTimelinesRequestBody = z.object({ timelinesToInstall: z.array(ImportTimelines.nullable()), timelinesToUpdate: z.array(ImportTimelines.nullable()), - prepackagedTimelines: z.array(SavedTimeline), + prepackagedTimelines: z.array(TimelineSavedToReturnObject.nullable()), }); export type InstallPrepackedTimelinesRequestBodyInput = z.input< typeof InstallPrepackedTimelinesRequestBody >; export type InstallPrepackedTimelinesResponse = z.infer; -export const InstallPrepackedTimelinesResponse = z.object({ - data: ImportTimelineResult, -}); +export const InstallPrepackedTimelinesResponse = ImportTimelineResult; diff --git a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml index af96bbeb9c6d2..e25f6889702b4 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml @@ -40,18 +40,15 @@ paths: prepackagedTimelines: type: array items: - $ref: '../model/components.schema.yaml#/components/schemas/SavedTimeline' + $ref: '../model/components.schema.yaml#/components/schemas/TimelineSavedToReturnObject' + nullable: true responses: '200': description: Indicates the installation of prepackaged timelines was successful. content: application/json: schema: - type: object - required: [data] - properties: - data: - $ref: '../model/components.schema.yaml#/components/schemas/ImportTimelineResult' + $ref: '../model/components.schema.yaml#/components/schemas/ImportTimelineResult' '500': description: Indicates the installation of prepackaged timelines was unsuccessful. content: diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index a7aff47f38ef0..6069a62c4196a 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -21,6 +21,7 @@ import { DataProviderTypeEnum, FavoriteTimelineResponse, type FavoriteTimelineResult, + ImportTimelines, type Note, PinnedEvent, RowRendererId, @@ -30,6 +31,7 @@ import { SortFieldTimelineEnum, TemplateTimelineType, TemplateTimelineTypeEnum, + TimelineSavedToReturnObject, TimelineStatus, TimelineStatusEnum, TimelineType, @@ -42,6 +44,7 @@ export { DataProviderType, DataProviderTypeEnum, FavoriteTimelineResponse, + ImportTimelines, Note, PinnedEvent, RowRendererId, @@ -51,6 +54,7 @@ export { SortFieldTimelineEnum, TemplateTimelineType, TemplateTimelineTypeEnum, + TimelineSavedToReturnObject, TimelineStatus, TimelineStatusEnum, TimelineType, diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index cf6972c0a821c..ece9749735237 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -318,11 +318,24 @@ export const TimelineStatusEnum = TimelineStatus.enum; export type ImportTimelines = z.infer; export const ImportTimelines = SavedTimeline.merge( z.object({ - savedObjectId: z.string().nullable().optional(), - version: z.string().nullable().optional(), - globalNotes: z.array(BareNote).nullable().optional(), - eventNotes: z.array(BareNote).nullable().optional(), - pinnedEventIds: z.array(z.string()).nullable().optional(), + savedObjectId: z.string().nullable(), + version: z.string().nullable(), + pinnedEventIds: z.array(z.string()).nullable(), + eventNotes: z.array(BareNote).nullable(), + globalNotes: z.array(BareNote).nullable(), + }) +); + +export type TimelineSavedToReturnObject = z.infer; +export const TimelineSavedToReturnObject = SavedTimeline.merge( + z.object({ + savedObjectId: z.string(), + version: z.string(), + eventIdToNoteIds: z.array(Note).optional(), + notes: z.array(Note).optional(), + noteIds: z.array(z.string()).optional(), + pinnedEventIds: z.array(z.string()).optional(), + pinnedEventsSaveObject: z.array(PinnedEvent).optional(), }) ); @@ -355,16 +368,3 @@ export const ExportedTimelines = SavedTimeline.merge( pinnedEventIds: z.array(z.string()).optional(), }) ); - -export type Readable = z.infer; -export const Readable = z.object({ - _maxListeners: z.object({}).catchall(z.unknown()).optional(), - _readableState: z.object({}).catchall(z.unknown()).optional(), - _read: z.object({}).catchall(z.unknown()).optional(), - readable: z.boolean().optional(), - _events: z.object({}).catchall(z.unknown()).optional(), - _eventsCount: z.number().optional(), - _data: z.object({}).catchall(z.unknown()).optional(), - _position: z.number().optional(), - _encoding: z.string().optional(), -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index 5d8167bc012db..0ae622ef6b52c 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -157,9 +157,7 @@ components: allOf: - $ref: '#/components/schemas/SavedTimeline' - type: object - required: - - savedObjectId - - version + required: [savedObjectId, version] properties: eventIdToNoteIds: type: array @@ -192,9 +190,7 @@ components: type: string FavoriteTimelineResponse: type: object - required: - - savedObjectId - - version + required: [savedObjectId, version] properties: savedObjectId: type: string @@ -586,6 +582,7 @@ components: allOf: - $ref: '#/components/schemas/SavedTimeline' - type: object + required: [savedObjectId, version, pinnedEventIds, eventNotes, globalNotes] properties: savedObjectId: type: string @@ -593,21 +590,51 @@ components: version: type: string nullable: true - globalNotes: - nullable: true + pinnedEventIds: type: array + nullable: true items: - $ref: '#/components/schemas/BareNote' + type: string eventNotes: + type: array nullable: true + items: + $ref: '#/components/schemas/BareNote' + globalNotes: type: array + nullable: true items: $ref: '#/components/schemas/BareNote' + TimelineSavedToReturnObject: + allOf: + - $ref: '#/components/schemas/SavedTimeline' + - type: object + required: [savedObjectId, version] + properties: + savedObjectId: + type: string + version: + type: string + eventIdToNoteIds: + type: array + items: + $ref: '#/components/schemas/Note' + notes: + type: array + items: + $ref: '#/components/schemas/Note' + noteIds: + type: array + items: + type: string pinnedEventIds: - nullable: true type: array items: type: string + pinnedEventsSaveObject: + type: array + items: + $ref: '#/components/schemas/PinnedEvent' ImportTimelineResult: type: object properties: @@ -650,29 +677,3 @@ components: type: array items: type: string - Readable: - type: object - properties: - _maxListeners: - type: object - additionalProperties: true - _readableState: - type: object - additionalProperties: true - _read: - type: object - additionalProperties: true - readable: - type: boolean - _events: - type: object - additionalProperties: true - _eventsCount: - type: number - _data: - type: object - additionalProperties: true - _position: - type: number - _encoding: - type: string diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index d448c0466b573..8f975a6c95439 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -60,3 +60,8 @@ export { ImportTimelinesRequestBody, ImportTimelinesResponse, } from './import_timelines/import_timelines_route.gen'; + +export { + InstallPrepackedTimelinesRequestBody, + InstallPrepackedTimelinesResponse, +} from './install_prepackaged_timelines/install_prepackaged_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts index 6b88ec1923d0d..3713176e919c5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts @@ -6,8 +6,7 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; -import { checkTimelineStatusRt } from '../../../../../../common/api/timeline'; +import { InstallPrepackedTimelinesRequestBody } from '../../../../../../common/api/timeline'; import { buildSiemResponse } from '../../../routes/utils'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; @@ -69,10 +68,8 @@ export const getPrebuiltRulesAndTimelinesStatusRoute = (router: SecuritySolution const frameworkRequest = await buildFrameworkRequest(context, request); const prebuiltTimelineStatus = await checkTimelinesStatus(frameworkRequest); - const [validatedPrebuiltTimelineStatus] = validate( - prebuiltTimelineStatus, - checkTimelineStatusRt - ); + const validatedPrebuiltTimelineStatus = + InstallPrepackedTimelinesRequestBody.parse(prebuiltTimelineStatus); const responseBody: ReadPrebuiltRulesAndTimelinesStatusResponse = { rules_custom_installed: customRules.total, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/index.ts index 0b150b4e47f56..b1a6e2f781f45 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/index.ts @@ -6,14 +6,17 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; -import { checkTimelineStatusRt } from '../../../../../../common/api/timeline'; +import type { IKibanaResponse } from '@kbn/core-http-server'; + import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_PREPACKAGED_URL } from '../../../../../../common/constants'; import type { ConfigType } from '../../../../../config'; - +import { + InstallPrepackedTimelinesRequestBody, + type InstallPrepackedTimelinesResponse, +} from '../../../../../../common/api/timeline'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { installPrepackagedTimelines } from './helpers'; @@ -45,23 +48,24 @@ export const installPrepackedTimelinesRoute = ( validate: {}, version: '2023-10-31', }, - async (context, request, response) => { + async ( + context, + request, + response + ): Promise> => { try { const frameworkRequest = await buildFrameworkRequest(context, request); const prepackagedTimelineStatus = await checkTimelinesStatus(frameworkRequest); - const [validatedprepackagedTimelineStatus, prepackagedTimelineStatusError] = validate( - prepackagedTimelineStatus, - checkTimelineStatusRt - ); - if (prepackagedTimelineStatusError != null) { - throw prepackagedTimelineStatusError; + const installResult = + InstallPrepackedTimelinesRequestBody.safeParse(prepackagedTimelineStatus); + + if (installResult.error) { + throw installResult.error; } - const timelinesToInstalled = - validatedprepackagedTimelineStatus?.timelinesToInstall.length ?? 0; - const timelinesNotUpdated = - validatedprepackagedTimelineStatus?.timelinesToUpdate.length ?? 0; + const timelinesToInstalled = installResult.data.timelinesToInstall.length ?? 0; + const timelinesNotUpdated = installResult.data.timelinesToUpdate.length ?? 0; let res = null; if (timelinesToInstalled > 0 || timelinesNotUpdated > 0) { diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts index 65f3510c75f8c..8c1a1cf35d9e4 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts @@ -5,10 +5,10 @@ * 2.0. */ -import type * as rt from 'io-ts'; +import type { ZodError, ZodType } from 'zod'; import type { Transform } from 'stream'; import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; +import { type Either, fold, left, right } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { createConcatStream, createSplitStream, createMapStream } from '@kbn/utils'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; @@ -19,23 +19,28 @@ import { } from '../../../../../utils/read_stream/create_stream_from_ndjson'; import type { ImportTimelineResponse } from './types'; -import { ImportTimelinesSchemaRt } from '../../../../../../common/api/timeline'; +import { ImportTimelines } from '../../../../../../common/api/timeline'; import { throwErrors } from '../../../utils/common'; type ErrorFactory = (message: string) => Error; -export const createPlainError = (message: string) => new Error(message); +const createPlainError = (message: string) => new Error(message); -export const decodeOrThrow = - (runtimeType: rt.Type, createError: ErrorFactory = createPlainError) => - (inputValue: I) => - pipe(runtimeType.decode(inputValue), fold(throwErrors(createError), identity)); +const parseRuntimeType = + (zodType: ZodType) => + (v: unknown): Either, T> => { + const result = zodType.safeParse(v); + return result.success ? right(result.data) : left(result.error); + }; -export const validateTimelines = (): Transform => +const decodeOrThrow = + (runtimeType: ZodType, createError: ErrorFactory = createPlainError) => + (inputValue: unknown) => + pipe(parseRuntimeType(runtimeType)(inputValue), fold(throwErrors(createError), identity)); + +const validateTimelines = (): Transform => createMapStream((obj: ImportTimelineResponse) => - obj instanceof Error - ? new BadRequestError(obj.message) - : decodeOrThrow(ImportTimelinesSchemaRt)(obj) + obj instanceof Error ? new BadRequestError(obj.message) : decodeOrThrow(ImportTimelines)(obj) ); export const createTimelinesStreamFromNdJson = (ruleLimit: number) => { return [ diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts index 3415df46e9ac4..74e76dcf38a90 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts @@ -452,48 +452,6 @@ describe('import timelines', () => { }); }); }); - - describe('request validation', () => { - beforeEach(() => { - jest.doMock('../../../saved_object/timelines', () => { - return { - getTimelineOrNull: mockGetTimeline.mockReturnValue(null), - persistTimeline: mockPersistTimeline.mockReturnValue({ - timeline: { savedObjectId: '79deb4c0-6bc1-11ea-9999-f5341fb7a189' }, - }), - }; - }); - - jest.doMock('../../../saved_object/pinned_events', () => { - return { - savePinnedEvents: mockPersistPinnedEventOnTimeline.mockReturnValue( - new Error('Test error') - ), - }; - }); - - jest.doMock('../../../saved_object/notes/saved_object', () => { - return { - persistNote: mockPersistNote, - }; - }); - }); - test('disallows invalid query', async () => { - request = requestMock.create({ - method: 'post', - path: TIMELINE_EXPORT_URL, - body: { id: 'someId' }, - }); - const importTimelinesRoute = jest.requireActual('.').importTimelinesRoute; - - importTimelinesRoute(server.router, createMockConfig(), securitySetup); - const result = server.validate(request); - - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value {"id":"someId"}, excess properties: ["id"]' - ); - }); - }); }); describe('import timeline templates', () => { @@ -904,7 +862,7 @@ describe('import timeline templates', () => { request = requestMock.create({ method: 'post', path: TIMELINE_EXPORT_URL, - body: { id: 'someId' }, + body: { isImmutable: 1 }, }); const importTimelinesRoute = jest.requireActual('.').importTimelinesRoute; @@ -912,7 +870,7 @@ describe('import timeline templates', () => { const result = server.validate(request); expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value {"id":"someId"}, excess properties: ["id"]' + "isImmutable: Expected 'true' | 'false', received number" ); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts index 39c2fbd6738b1..59a86238941ab 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.ts @@ -7,6 +7,7 @@ import { extname } from 'path'; import type { Readable } from 'stream'; +import { get } from 'lodash/fp'; import type { IKibanaResponse } from '@kbn/core-http-server'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; @@ -58,7 +59,7 @@ export const importTimelinesRoute = (router: SecuritySolutionPluginRouter, confi } const { file, isImmutable } = request.body; - const { filename } = file.hapi; + const filename = extractFilename(file); const fileExtension = extname(filename).toLowerCase(); if (fileExtension !== '.ndjson') { @@ -91,3 +92,11 @@ export const importTimelinesRoute = (router: SecuritySolutionPluginRouter, confi } ); }; + +function extractFilename(fileObj: unknown) { + const filename = get('hapi.filename', fileObj); + if (filename && typeof filename === 'string') { + return filename; + } + throw new Error('`filename` missing in file'); +} diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts index a5e88a3ea04d5..34f94594e29cb 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts @@ -7,9 +7,9 @@ import path, { join, resolve } from 'path'; import type { - CheckTimelineStatusRt, TimelineSavedObject, - ImportTimelinesSchema, + ImportTimelines, + InstallPrepackedTimelinesRequestBody, } from '../../../../common/api/timeline'; import type { FrameworkRequest } from '../../framework'; @@ -19,9 +19,9 @@ import { getExistingPrepackagedTimelines } from '../saved_object/timelines'; import { loadData, getReadables } from './common'; export const getTimelinesToUpdate = ( - timelinesFromFileSystem: ImportTimelinesSchema[], + timelinesFromFileSystem: ImportTimelines[], installedTimelines: TimelineSavedObject[] -): ImportTimelinesSchema[] => { +): ImportTimelines[] => { return timelinesFromFileSystem.filter((timeline) => installedTimelines.some((installedTimeline) => { return ( @@ -34,9 +34,9 @@ export const getTimelinesToUpdate = ( }; export const getTimelinesToInstall = ( - timelinesFromFileSystem: ImportTimelinesSchema[], + timelinesFromFileSystem: ImportTimelines[], installedTimelines: TimelineSavedObject[] -): ImportTimelinesSchema[] => { +): ImportTimelines[] => { return timelinesFromFileSystem.filter( (timeline) => !installedTimelines.some( @@ -49,7 +49,7 @@ export const checkTimelinesStatus = async ( frameworkRequest: FrameworkRequest, filePath?: string, fileName?: string -): Promise => { +): Promise => { let readStream; let timeline: { totalCount: number; @@ -75,7 +75,7 @@ export const checkTimelinesStatus = async ( }; } - return loadData<'utf-8', CheckTimelineStatusRt>( + return loadData<'utf-8', InstallPrepackedTimelinesRequestBody>( readStream, (timelinesFromFileSystem: T) => { if (Array.isArray(timelinesFromFileSystem)) { diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts index edee5ee4cd912..a15cbb95326eb 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts @@ -4,7 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type * as rt from 'io-ts'; + +import type { ZodError } from 'zod'; +import { stringifyZodError } from '@kbn/zod-helpers'; + import { set } from '@kbn/safer-lodash-set/fp'; import readline from 'readline'; import fs from 'fs'; @@ -13,7 +16,6 @@ import { createListStream } from '@kbn/utils'; import { schema } from '@kbn/config-schema'; import type { KibanaRequest, RequestHandlerContext } from '@kbn/core/server'; -import { formatErrors } from '@kbn/securitysolution-io-ts-utils'; import type { FrameworkRequest } from '../../framework'; @@ -40,8 +42,8 @@ export const escapeHatch = schema.object({}, { unknowns: 'allow' }); type ErrorFactory = (message: string) => Error; -export const throwErrors = (createError: ErrorFactory) => (errors: rt.Errors) => { - throw createError(formatErrors(errors).join('\n')); +export const throwErrors = (createError: ErrorFactory) => (errors: ZodError) => { + throw createError(stringifyZodError(errors)); }; export const getReadables = (dataPath: string): Promise => From c63cdab9fa98a7b2501d19d69deb382bc78d4e28 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 13:49:53 +0200 Subject: [PATCH 24/73] draft timeline --- .../get_draft_timelines_route.ts | 14 -------------- .../common/api/timeline/routes.ts | 5 +++++ .../draft_timelines/get_draft_timelines/index.ts | 12 ++++++++---- 3 files changed, 13 insertions(+), 18 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.ts deleted file mode 100644 index 13625715289f6..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.ts +++ /dev/null @@ -1,14 +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 rt from 'io-ts'; - -import { TimelineTypeLiteralRt } from '../model/api'; - -export const getDraftTimelineSchema = rt.type({ - timelineType: TimelineTypeLiteralRt, -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 8f975a6c95439..657cdf42adfe9 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -65,3 +65,8 @@ export { InstallPrepackedTimelinesRequestBody, InstallPrepackedTimelinesResponse, } from './install_prepackaged_timelines/install_prepackaged_timelines_route.gen'; + +export { + GetDraftTimelinesRequestQuery, + GetDraftTimelinesResponse, +} from './get_draft_timelines/get_draft_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts index 6619e4a0eb18b..b07130dfcad87 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts @@ -5,17 +5,21 @@ * 2.0. */ +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import type { ConfigType } from '../../../../..'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { TIMELINE_DRAFT_URL } from '../../../../../../common/constants'; import { buildFrameworkRequest } from '../../../utils/common'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import { getDraftTimeline, persistTimeline } from '../../../saved_object/timelines'; import { draftTimelineDefaults } from '../../../utils/default_timeline'; -import { getDraftTimelineSchema } from '../../../../../../common/api/timeline'; +import { + GetDraftTimelinesRequestQuery, + type GetDraftTimelinesResponse, +} from '../../../../../../common/api/timeline'; export const getDraftTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { router.versioned @@ -29,11 +33,11 @@ export const getDraftTimelinesRoute = (router: SecuritySolutionPluginRouter, _: .addVersion( { validate: { - request: { query: buildRouteValidationWithExcess(getDraftTimelineSchema) }, + request: { query: buildRouteValidationWithZod(GetDraftTimelinesRequestQuery) }, }, version: '2023-10-31', }, - async (context, request, response) => { + async (context, request, response): Promise> => { const frameworkRequest = await buildFrameworkRequest(context, request); const siemResponse = buildSiemResponse(response); From feab218d5f01e909a2467e68d5e96eee3bbf88e6 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 13:50:27 +0200 Subject: [PATCH 25/73] fix brooken export --- x-pack/plugins/security_solution/common/api/timeline/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 79438fcbd7d77..aaea60e46b039 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -8,7 +8,6 @@ export * from './model/api'; export * from './routes'; -export * from './get_draft_timelines/get_draft_timelines_route'; export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; export * from './pinned_events/pinned_events_route'; From a8e7b548c76a1418fbab7fcb72a68fb57f1130f4 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 14:06:55 +0200 Subject: [PATCH 26/73] resolve timeline --- .../resolve_timeline/resolve_timeline_route.gen.ts | 9 +++++---- .../resolve_timeline_route.schema.yaml | 14 ++++++-------- .../common/api/timeline/routes.ts | 5 +++++ .../routes/timelines/resolve_timeline/index.ts | 13 +++++++++---- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts index 4db6738dc0b87..20190f561e224 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts @@ -32,8 +32,9 @@ export const ResolveTimelineRequestQuery = z.object({ export type ResolveTimelineRequestQueryInput = z.input; export type ResolveTimelineResponse = z.infer; -export const ResolveTimelineResponse = z.object({ - data: z.object({ - getOneTimeline: TimelineResponse.nullable(), +export const ResolveTimelineResponse = z.union([ + z.object({ + data: TimelineResponse, }), -}); + z.object({}), +]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml index 6c2b0d309f01f..3425f354e8117 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml @@ -35,16 +35,14 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object - required: [getOneTimeline] + oneOf: + - type: object + required: [data] properties: - getOneTimeline: + data: $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' - nullable: true + - type: object + '400': description: The request is missing parameters '404': diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 657cdf42adfe9..6db44579969bc 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -70,3 +70,8 @@ export { GetDraftTimelinesRequestQuery, GetDraftTimelinesResponse, } from './get_draft_timelines/get_draft_timelines_route.gen'; + +export { + ResolveTimelineRequestQuery, + ResolveTimelineResponse, +} from './resolve_timeline/resolve_timeline_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts index 09549f9b9034f..60ffb07752fd2 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts @@ -6,17 +6,22 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import type { IKibanaResponse } from '@kbn/core-http-server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; + import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_RESOLVE_URL } from '../../../../../../common/constants'; import type { ConfigType } from '../../../../..'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; -import { getTimelineQuerySchema } from '../../../../../../common/api/timeline'; +import { + ResolveTimelineRequestQuery, + type ResolveTimelineResponse, +} from '../../../../../../common/api/timeline'; import { getTimelineTemplateOrNull, resolveTimelineOrNull } from '../../../saved_object/timelines'; import type { SavedTimeline, @@ -36,10 +41,10 @@ export const resolveTimelineRoute = (router: SecuritySolutionPluginRouter, _: Co { version: '2023-10-31', validate: { - request: { query: buildRouteValidationWithExcess(getTimelineQuerySchema) }, + request: { query: buildRouteValidationWithZod(ResolveTimelineRequestQuery) }, }, }, - async (context, request, response) => { + async (context, request, response): Promise> => { try { const frameworkRequest = await buildFrameworkRequest(context, request); const query = request.query ?? {}; From 55aef91c39f5fe1f998cfb439f6784c87d6ecd0f Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 14:15:58 +0200 Subject: [PATCH 27/73] get timeline route --- .../get_timeline/get_timeline_route.gen.ts | 11 +++++++---- .../get_timeline_route.schema.yaml | 19 ++++++++++--------- .../get_timeline/get_timeline_route.ts | 15 --------------- .../common/api/timeline/index.ts | 1 - .../common/api/timeline/routes.ts | 5 +++++ .../timeline/__mocks__/request_responses.ts | 4 ++-- .../routes/timelines/get_timeline/index.ts | 12 ++++++++---- 7 files changed, 32 insertions(+), 35 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts index d178b80e35b7f..d9ed2aa51fd4b 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts @@ -32,8 +32,11 @@ export const GetTimelineRequestQuery = z.object({ export type GetTimelineRequestQueryInput = z.input; export type GetTimelineResponse = z.infer; -export const GetTimelineResponse = z.object({ - data: z.object({ - getOneTimeline: TimelineResponse.nullable(), +export const GetTimelineResponse = z.union([ + z.object({ + data: z.object({ + getOneTimeline: TimelineResponse, + }), }), -}); + z.object({}), +]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml index 9a94bafb63a76..a16d9a6423289 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml @@ -38,13 +38,14 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object - required: [getOneTimeline] + oneOf: + - type: object + required: [data] properties: - getOneTimeline: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' - nullable: true + data: + type: object + required: [getOneTimeline] + properties: + getOneTimeline: + $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' + - type: object diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.ts b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.ts deleted file mode 100644 index cca6886f42025..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.ts +++ /dev/null @@ -1,15 +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 rt from 'io-ts'; - -export const getTimelineQuerySchema = rt.partial({ - template_timeline_id: rt.string, - id: rt.string, -}); - -export type GetTimelineQuery = rt.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index aaea60e46b039..288dcd0115eda 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -8,6 +8,5 @@ export * from './model/api'; export * from './routes'; -export * from './get_timeline/get_timeline_route'; export * from './get_timelines/get_timelines_route'; export * from './pinned_events/pinned_events_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 6db44579969bc..44789a140018a 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -75,3 +75,8 @@ export { ResolveTimelineRequestQuery, ResolveTimelineResponse, } from './resolve_timeline/resolve_timeline_route.gen'; + +export { + GetTimelineRequestQuery, + GetTimelineResponse, +} from './get_timeline/get_timeline_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts index cde74c095487b..70187dc9bf40a 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/request_responses.ts @@ -18,7 +18,7 @@ import type { SavedTimeline, PatchTimelineRequestBody, CreateTimelinesRequestBody, - GetTimelineQuery, + GetTimelineRequestQuery, } from '../../../../common/api/timeline'; import { type TimelineType, @@ -166,7 +166,7 @@ export const cleanDraftTimelinesRequest = (timelineType: TimelineType) => }, }); -export const getTimelineRequest = (query?: GetTimelineQuery) => +export const getTimelineRequest = (query?: GetTimelineRequestQuery) => requestMock.create({ method: 'get', path: TIMELINE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts index 321e6aafe4903..2500cbea5bb50 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts @@ -5,18 +5,22 @@ * 2.0. */ +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; import type { ConfigType } from '../../../../..'; -import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; -import { getTimelineQuerySchema } from '../../../../../../common/api/timeline'; +import { + GetTimelineRequestQuery, + type GetTimelineResponse, +} from '../../../../../../common/api/timeline'; import { getTimelineTemplateOrNull, getTimelineOrNull } from '../../../saved_object/timelines'; import type { TimelineSavedObject, @@ -36,10 +40,10 @@ export const getTimelineRoute = (router: SecuritySolutionPluginRouter, _: Config { version: '2023-10-31', validate: { - request: { query: buildRouteValidationWithExcess(getTimelineQuerySchema) }, + request: { query: buildRouteValidationWithZod(GetTimelineRequestQuery) }, }, }, - async (context, request, response) => { + async (context, request, response): Promise> => { try { const frameworkRequest = await buildFrameworkRequest(context, request); const query = request.query ?? {}; From 59fae7b99e82ffd8576cd0efe17c763a801733dc Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 14:33:28 +0200 Subject: [PATCH 28/73] get timelines route --- .../get_timelines/get_timelines_route.gen.ts | 9 ++-- .../get_timelines_route.schema.yaml | 12 +++--- .../get_timelines/get_timelines_route.ts | 28 ------------- .../common/api/timeline/index.ts | 1 - .../common/api/timeline/model/api.ts | 6 ++- .../api/timeline/model/components.gen.ts | 5 +++ .../api/timeline/model/components.schema.yaml | 5 +++ .../common/api/timeline/routes.ts | 5 +++ .../routes/timelines/get_timelines/index.ts | 41 +++++++++---------- 9 files changed, 49 insertions(+), 63 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts index 58b5683a89bf3..820ff8a494568 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts @@ -40,9 +40,9 @@ export const GetTimelinesRequestQuery = z.object({ export type GetTimelinesRequestQueryInput = z.input; export type GetTimelinesResponse = z.infer; -export const GetTimelinesResponse = z.object({ - data: z.object({ - timelines: z.array(TimelineResponse), +export const GetTimelinesResponse = z.union([ + z.object({ + timeline: z.array(TimelineResponse), totalCount: z.number(), defaultTimelineCount: z.number(), templateTimelineCount: z.number(), @@ -50,4 +50,5 @@ export const GetTimelinesResponse = z.object({ elasticTemplateTimelineCount: z.number(), customTemplateTimelineCount: z.number(), }), -}); + z.object({}), +]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml index 189865a9344d4..124578c8c0313 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml @@ -73,14 +73,11 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object + oneOf: + - type: object required: [ - timelines, + timeline, totalCount, defaultTimelineCount, templateTimelineCount, @@ -89,7 +86,7 @@ paths: customTemplateTimelineCount, ] properties: - timelines: + timeline: type: array items: $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' @@ -105,6 +102,7 @@ paths: type: number customTemplateTimelineCount: type: number + - type: object '400': description: Bad request. The user supplied invalid data. content: diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.ts deleted file mode 100644 index 9f35197358aea..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.ts +++ /dev/null @@ -1,28 +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 rt from 'io-ts'; -import { - direction, - sortFieldTimeline, - TimelineStatusLiteralRt, - TimelineTypeLiteralRt, -} from '../model/api'; -import { unionWithNullType } from '../../../utility_types'; - -const BoolFromString = rt.union([rt.literal('true'), rt.literal('false')]); - -export const getTimelinesQuerySchema = rt.partial({ - only_user_favorite: unionWithNullType(BoolFromString), - page_index: unionWithNullType(rt.string), - page_size: unionWithNullType(rt.string), - search: unionWithNullType(rt.string), - sort_field: sortFieldTimeline, - sort_order: direction, - status: unionWithNullType(TimelineStatusLiteralRt), - timeline_type: unionWithNullType(TimelineTypeLiteralRt), -}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 288dcd0115eda..efca50791c0ac 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -8,5 +8,4 @@ export * from './model/api'; export * from './routes'; -export * from './get_timelines/get_timelines_route'; export * from './pinned_events/pinned_events_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 6069a62c4196a..80f097214eb1f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -27,6 +27,7 @@ import { RowRendererId, RowRendererIdEnum, SavedTimeline, + SortDirection, SortFieldTimeline, SortFieldTimelineEnum, TemplateTimelineType, @@ -50,6 +51,7 @@ export { RowRendererId, RowRendererIdEnum, SavedTimeline, + SortDirection, SortFieldTimeline, SortFieldTimelineEnum, TemplateTimelineType, @@ -439,11 +441,13 @@ export const sortFieldTimeline = runtimeTypes.union([ runtimeTypes.literal(SortFieldTimelineEnum.created), ]); +// TODO: remove export const direction = runtimeTypes.union([ runtimeTypes.literal(Direction.asc), runtimeTypes.literal(Direction.desc), ]); +// TODO: remove export const sortTimeline = runtimeTypes.type({ sortField: sortFieldTimeline, sortOrder: direction, @@ -634,7 +638,7 @@ export interface ResponseTimeline { export interface SortTimeline { sortField: SortFieldTimeline; - sortOrder: Direction; + sortOrder: SortDirection; } export interface GetAllTimelineVariables { diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index ece9749735237..e654e3f0dbf5a 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -307,6 +307,11 @@ export const SortFieldTimeline = z.enum(['title', 'description', 'updated', 'cre export type SortFieldTimelineEnum = typeof SortFieldTimeline.enum; export const SortFieldTimelineEnum = SortFieldTimeline.enum; +export type SortDirection = z.infer; +export const SortDirection = z.enum(['asc', 'desc']); +export type SortDirectionEnum = typeof SortDirection.enum; +export const SortDirectionEnum = SortDirection.enum; + /** * The status of the timeline. Valid values are `active`, `draft`, and `immutable`. */ diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index 0ae622ef6b52c..c9692a29b2b92 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -569,6 +569,11 @@ components: - description - updated - created + SortDirection: + type: string + enum: + - asc + - desc TimelineStatus: type: string enum: diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index 44789a140018a..a27c42b865f42 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -80,3 +80,8 @@ export { GetTimelineRequestQuery, GetTimelineResponse, } from './get_timeline/get_timeline_route.gen'; + +export { + GetTimelinesRequestQuery, + GetTimelinesResponse, +} from './get_timelines/get_timelines_route.gen'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts index 97d9bf51a0876..5772ed443dd17 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; +import type { IKibanaResponse } from '@kbn/core-http-server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; @@ -17,10 +16,12 @@ import type { ConfigType } from '../../../../..'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; -import { CustomHttpRequestError } from '../../../../../utils/custom_http_request_error'; -import { buildFrameworkRequest, escapeHatch, throwErrors } from '../../../utils/common'; +import { buildFrameworkRequest } from '../../../utils/common'; import { getAllTimeline } from '../../../saved_object/timelines'; -import { getTimelinesQuerySchema } from '../../../../../../common/api/timeline'; +import { + GetTimelinesRequestQuery, + type GetTimelinesResponse, +} from '../../../../../../common/api/timeline'; export const getTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { router.versioned @@ -34,27 +35,23 @@ export const getTimelinesRoute = (router: SecuritySolutionPluginRouter, _: Confi .addVersion( { validate: { - request: { query: escapeHatch }, + request: { query: buildRouteValidationWithZod(GetTimelinesRequestQuery) }, }, version: '2023-10-31', }, - async (context, request, response) => { - const customHttpRequestError = (message: string) => - new CustomHttpRequestError(message, 400); + async (context, request, response): Promise> => { try { const frameworkRequest = await buildFrameworkRequest(context, request); - const queryParams = pipe( - getTimelinesQuerySchema.decode(request.query), - fold(throwErrors(customHttpRequestError), identity) - ); - const onlyUserFavorite = queryParams?.only_user_favorite === 'true' ? true : false; - const pageSize = queryParams?.page_size ? parseInt(queryParams.page_size, 10) : null; - const pageIndex = queryParams?.page_index ? parseInt(queryParams.page_index, 10) : null; - const search = queryParams?.search ?? null; - const sortField = queryParams?.sort_field ?? null; - const sortOrder = queryParams?.sort_order ?? null; - const status = queryParams?.status ?? null; - const timelineType = queryParams?.timeline_type ?? null; + const onlyUserFavorite = request.query?.only_user_favorite === 'true' ? true : false; + const pageSize = request.query?.page_size ? parseInt(request.query.page_size, 10) : null; + const pageIndex = request.query?.page_index + ? parseInt(request.query.page_index, 10) + : null; + const search = request.query?.search ?? null; + const sortField = request.query?.sort_field ?? null; + const sortOrder = request.query?.sort_order ?? null; + const status = request.query?.status ?? null; + const timelineType = request.query?.timeline_type ?? null; const sort = sortField && sortOrder ? { From d4c56b8a6edcc14f402c62d496b10ccf5c8305f9 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 14:51:30 +0200 Subject: [PATCH 29/73] remove some types --- .../common/api/timeline/model/api.ts | 31 ------------------- .../public/timelines/containers/api.ts | 4 +-- 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 80f097214eb1f..6d7c888f21027 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -11,7 +11,6 @@ import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; import { stringEnum, unionWithNullType } from '../../../utility_types'; import type { Maybe } from '../../../search_strategy'; -import { Direction } from '../../../search_strategy'; import { PinnedEventRuntimeType } from '../pinned_events/pinned_events_route'; import { ErrorSchema } from './error_schema'; import type { DataProviderType } from './components.gen'; @@ -434,25 +433,6 @@ export const TimelineErrorResponseType = runtimeTypes.union([ export type TimelineErrorResponse = runtimeTypes.TypeOf; export type TimelineResponse = runtimeTypes.TypeOf; -export const sortFieldTimeline = runtimeTypes.union([ - runtimeTypes.literal(SortFieldTimelineEnum.title), - runtimeTypes.literal(SortFieldTimelineEnum.description), - runtimeTypes.literal(SortFieldTimelineEnum.updated), - runtimeTypes.literal(SortFieldTimelineEnum.created), -]); - -// TODO: remove -export const direction = runtimeTypes.union([ - runtimeTypes.literal(Direction.asc), - runtimeTypes.literal(Direction.desc), -]); - -// TODO: remove -export const sortTimeline = runtimeTypes.type({ - sortField: sortFieldTimeline, - sortOrder: direction, -}); - /** * Import/export timelines */ @@ -497,17 +477,6 @@ export interface PageInfoTimeline { pageSize: number; } -export const getTimelinesArgs = runtimeTypes.partial({ - onlyUserFavorite: unionWithNullType(runtimeTypes.boolean), - pageInfo: unionWithNullType(pageInfoTimeline), - search: unionWithNullType(runtimeTypes.string), - sort: unionWithNullType(sortTimeline), - status: unionWithNullType(TimelineStatusLiteralRt), - timelineType: unionWithNullType(TimelineTypeLiteralRt), -}); - -export type GetTimelinesArgs = runtimeTypes.TypeOf; - export interface ColumnHeaderResult { aggregatable?: Maybe; category?: Maybe; diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 155d95c5acef2..5f9ed27bddaad 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -20,7 +20,7 @@ import type { AllTimelinesResponse, SingleTimelineResponse, SingleTimelineResolveResponse, - GetTimelinesArgs, + GetAllTimelineVariables, } from '../../../common/api/timeline'; import { TimelineResponseType, @@ -421,7 +421,7 @@ export const getTimelineTemplate = async (templateTimelineId: string) => { return decodeSingleTimelineResponse(response); }; -export const getAllTimelines = async (args: GetTimelinesArgs, abortSignal: AbortSignal) => { +export const getAllTimelines = async (args: GetAllTimelineVariables, abortSignal: AbortSignal) => { const response = await KibanaServices.get().http.fetch(TIMELINES_URL, { method: 'GET', query: { From f693470501286a7987c97e79d1c8d00ea7835a71 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:58:44 +0000 Subject: [PATCH 30/73] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...imeline_api_2023_10_31.bundled.schema.yaml | 271 +++++++++++------- ...imeline_api_2023_10_31.bundled.schema.yaml | 271 +++++++++++------- 2 files changed, 344 insertions(+), 198 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index c05fd43f759d8..918cf8bf47a03 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -263,18 +263,19 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: - $ref: '#/components/schemas/TimelineResponse' - nullable: true + data: + type: object + properties: + getOneTimeline: + $ref: '#/components/schemas/TimelineResponse' + required: + - getOneTimeline required: - - getOneTimeline - required: - - data + - data + - type: object description: Indicates that the (template) timeline was found and returned. summary: >- Get an existing saved timeline or timeline template. This API is used to @@ -399,6 +400,8 @@ paths: properties: timeline: $ref: '#/components/schemas/TimelineResponse' + required: + - timeline required: - persistTimeline required: @@ -419,6 +422,51 @@ paths: tags: - Security Solution Timeline API - 'access:securitySolution' + /api/timeline/_copy: + get: + description: | + Copies and returns a timeline or timeline template. + operationId: CopyTimeline + requestBody: + content: + application/json: + schema: + type: object + properties: + timeline: + $ref: '#/components/schemas/SavedTimeline' + timelineIdToCopy: + type: string + required: + - timeline + - timelineIdToCopy + required: true + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: '#/components/schemas/TimelineResponse' + required: + - timeline + required: + - persistTimeline + required: + - data + description: Indicates that the timeline has been successfully copied. + summary: Copies timeline or timeline template. + tags: + - Security Solution Timeline API + - 'access:securitySolution' /api/timeline/_draft: get: operationId: GetDraftTimelines @@ -675,28 +723,14 @@ paths: schema: type: object properties: - file: - allOf: - - $ref: '#/components/schemas/Readable' - - type: object - properties: - hapi: - type: object - properties: - filename: - type: string - headers: - type: object - isImmutable: - enum: - - 'true' - - 'false' - type: string - required: - - filename - - headers - required: - - hapi + file: {} + isImmutable: + enum: + - 'true' + - 'false' + type: string + required: + - file description: The timelines to import as a readable stream. required: true responses: @@ -704,12 +738,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - $ref: '#/components/schemas/ImportTimelineResult' - required: - - data + $ref: '#/components/schemas/ImportTimelineResult' description: Indicates the import of timelines was successful. '400': content: @@ -767,7 +796,8 @@ paths: properties: prepackagedTimelines: items: - $ref: '#/components/schemas/SavedTimeline' + $ref: '#/components/schemas/TimelineSavedToReturnObject' + nullable: true type: array timelinesToInstall: items: @@ -790,12 +820,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - $ref: '#/components/schemas/ImportTimelineResult' - required: - - data + $ref: '#/components/schemas/ImportTimelineResult' description: Indicates the installation of prepackaged timelines was successful. '500': content: @@ -833,18 +858,14 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: + data: $ref: '#/components/schemas/TimelineResponse' - nullable: true required: - - getOneTimeline - required: - - data + - data + - type: object description: The (template) timeline has been found '400': description: The request is missing parameters @@ -910,10 +931,8 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: customTemplateTimelineCount: type: number @@ -925,22 +944,21 @@ paths: type: number templateTimelineCount: type: number - timelines: + timeline: items: $ref: '#/components/schemas/TimelineResponse' type: array totalCount: type: number required: - - timelines + - timeline - totalCount - defaultTimelineCount - templateTimelineCount - favoriteCount - elasticTemplateTimelineCount - customTemplateTimelineCount - required: - - data + - type: object description: Indicates that the (template) timelines were found and returned. '400': content: @@ -1012,30 +1030,39 @@ components: type: object properties: aggregatable: + nullable: true type: boolean category: + nullable: true type: string columnHeaderType: + nullable: true type: string description: + nullable: true type: string example: - oneOf: - - type: string - - type: number + nullable: true + type: string id: + nullable: true type: string indexes: items: type: string + nullable: true type: array name: + nullable: true type: string placeholder: + nullable: true type: string searchable: + nullable: true type: boolean type: + nullable: true type: string DataProviderQueryMatch: type: object @@ -1057,6 +1084,7 @@ components: type: string queryMatch: $ref: '#/components/schemas/QueryMatchResult' + nullable: true DataProviderResult: type: object properties: @@ -1144,41 +1172,59 @@ components: type: object properties: exists: - type: boolean + nullable: true + type: string match_all: + nullable: true type: string meta: + nullable: true type: object properties: alias: + nullable: true type: string controlledBy: + nullable: true type: string disabled: + nullable: true type: boolean field: + nullable: true type: string formattedValue: + nullable: true type: string index: + nullable: true type: string key: + nullable: true type: string negate: + nullable: true type: boolean params: + nullable: true type: string type: + nullable: true type: string value: + nullable: true type: string missing: + nullable: true type: string query: + nullable: true type: string range: + nullable: true type: string script: + nullable: true type: string GetNotesResult: type: object @@ -1243,6 +1289,12 @@ components: version: nullable: true type: string + required: + - savedObjectId + - version + - pinnedEventIds + - eventNotes + - globalNotes Note: allOf: - $ref: '#/components/schemas/BareNote' @@ -1260,7 +1312,8 @@ components: - allOf: - $ref: '#/components/schemas/PinnedEvent' - $ref: '#/components/schemas/PinnedEventBaseResponseBody' - - $ref: '#/components/schemas/PinnedEventBaseResponseBody' + - nullable: true + type: object PinnedEvent: allOf: - $ref: '#/components/schemas/BarePinnedEvent' @@ -1298,34 +1351,13 @@ components: nullable: true type: string value: - nullable: true - type: string - Readable: - type: object - properties: - _data: - additionalProperties: true - type: object - _encoding: - type: string - _events: - additionalProperties: true - type: object - _eventsCount: - type: number - _maxListeners: - additionalProperties: true - type: object - _position: - type: number - _read: - additionalProperties: true - type: object - _readableState: - additionalProperties: true - type: object - readable: - type: boolean + oneOf: + - nullable: true + type: string + - items: + type: string + nullable: true + type: array ResponseNote: type: object properties: @@ -1388,12 +1420,16 @@ components: properties: end: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number start: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number description: nullable: true type: string @@ -1529,6 +1565,43 @@ components: nullable: true type: string TimelineResponse: + allOf: + - $ref: '#/components/schemas/SavedTimeline' + - type: object + properties: + eventIdToNoteIds: + items: + $ref: '#/components/schemas/Note' + nullable: true + type: array + noteIds: + items: + type: string + nullable: true + type: array + notes: + items: + $ref: '#/components/schemas/Note' + nullable: true + type: array + pinnedEventIds: + items: + type: string + nullable: true + type: array + pinnedEventsSaveObject: + items: + $ref: '#/components/schemas/PinnedEvent' + nullable: true + type: array + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version + TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/SavedTimeline' - type: object diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 396b9a62d72d1..73e5ff59e202d 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -263,18 +263,19 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: - $ref: '#/components/schemas/TimelineResponse' - nullable: true + data: + type: object + properties: + getOneTimeline: + $ref: '#/components/schemas/TimelineResponse' + required: + - getOneTimeline required: - - getOneTimeline - required: - - data + - data + - type: object description: Indicates that the (template) timeline was found and returned. summary: >- Get an existing saved timeline or timeline template. This API is used to @@ -399,6 +400,8 @@ paths: properties: timeline: $ref: '#/components/schemas/TimelineResponse' + required: + - timeline required: - persistTimeline required: @@ -419,6 +422,51 @@ paths: tags: - Security Solution Timeline API - 'access:securitySolution' + /api/timeline/_copy: + get: + description: | + Copies and returns a timeline or timeline template. + operationId: CopyTimeline + requestBody: + content: + application/json: + schema: + type: object + properties: + timeline: + $ref: '#/components/schemas/SavedTimeline' + timelineIdToCopy: + type: string + required: + - timeline + - timelineIdToCopy + required: true + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: '#/components/schemas/TimelineResponse' + required: + - timeline + required: + - persistTimeline + required: + - data + description: Indicates that the timeline has been successfully copied. + summary: Copies timeline or timeline template. + tags: + - Security Solution Timeline API + - 'access:securitySolution' /api/timeline/_draft: get: operationId: GetDraftTimelines @@ -675,28 +723,14 @@ paths: schema: type: object properties: - file: - allOf: - - $ref: '#/components/schemas/Readable' - - type: object - properties: - hapi: - type: object - properties: - filename: - type: string - headers: - type: object - isImmutable: - enum: - - 'true' - - 'false' - type: string - required: - - filename - - headers - required: - - hapi + file: {} + isImmutable: + enum: + - 'true' + - 'false' + type: string + required: + - file description: The timelines to import as a readable stream. required: true responses: @@ -704,12 +738,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - $ref: '#/components/schemas/ImportTimelineResult' - required: - - data + $ref: '#/components/schemas/ImportTimelineResult' description: Indicates the import of timelines was successful. '400': content: @@ -767,7 +796,8 @@ paths: properties: prepackagedTimelines: items: - $ref: '#/components/schemas/SavedTimeline' + $ref: '#/components/schemas/TimelineSavedToReturnObject' + nullable: true type: array timelinesToInstall: items: @@ -790,12 +820,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - $ref: '#/components/schemas/ImportTimelineResult' - required: - - data + $ref: '#/components/schemas/ImportTimelineResult' description: Indicates the installation of prepackaged timelines was successful. '500': content: @@ -833,18 +858,14 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: + data: $ref: '#/components/schemas/TimelineResponse' - nullable: true required: - - getOneTimeline - required: - - data + - data + - type: object description: The (template) timeline has been found '400': description: The request is missing parameters @@ -910,10 +931,8 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: customTemplateTimelineCount: type: number @@ -925,22 +944,21 @@ paths: type: number templateTimelineCount: type: number - timelines: + timeline: items: $ref: '#/components/schemas/TimelineResponse' type: array totalCount: type: number required: - - timelines + - timeline - totalCount - defaultTimelineCount - templateTimelineCount - favoriteCount - elasticTemplateTimelineCount - customTemplateTimelineCount - required: - - data + - type: object description: Indicates that the (template) timelines were found and returned. '400': content: @@ -1012,30 +1030,39 @@ components: type: object properties: aggregatable: + nullable: true type: boolean category: + nullable: true type: string columnHeaderType: + nullable: true type: string description: + nullable: true type: string example: - oneOf: - - type: string - - type: number + nullable: true + type: string id: + nullable: true type: string indexes: items: type: string + nullable: true type: array name: + nullable: true type: string placeholder: + nullable: true type: string searchable: + nullable: true type: boolean type: + nullable: true type: string DataProviderQueryMatch: type: object @@ -1057,6 +1084,7 @@ components: type: string queryMatch: $ref: '#/components/schemas/QueryMatchResult' + nullable: true DataProviderResult: type: object properties: @@ -1144,41 +1172,59 @@ components: type: object properties: exists: - type: boolean + nullable: true + type: string match_all: + nullable: true type: string meta: + nullable: true type: object properties: alias: + nullable: true type: string controlledBy: + nullable: true type: string disabled: + nullable: true type: boolean field: + nullable: true type: string formattedValue: + nullable: true type: string index: + nullable: true type: string key: + nullable: true type: string negate: + nullable: true type: boolean params: + nullable: true type: string type: + nullable: true type: string value: + nullable: true type: string missing: + nullable: true type: string query: + nullable: true type: string range: + nullable: true type: string script: + nullable: true type: string GetNotesResult: type: object @@ -1243,6 +1289,12 @@ components: version: nullable: true type: string + required: + - savedObjectId + - version + - pinnedEventIds + - eventNotes + - globalNotes Note: allOf: - $ref: '#/components/schemas/BareNote' @@ -1260,7 +1312,8 @@ components: - allOf: - $ref: '#/components/schemas/PinnedEvent' - $ref: '#/components/schemas/PinnedEventBaseResponseBody' - - $ref: '#/components/schemas/PinnedEventBaseResponseBody' + - nullable: true + type: object PinnedEvent: allOf: - $ref: '#/components/schemas/BarePinnedEvent' @@ -1298,34 +1351,13 @@ components: nullable: true type: string value: - nullable: true - type: string - Readable: - type: object - properties: - _data: - additionalProperties: true - type: object - _encoding: - type: string - _events: - additionalProperties: true - type: object - _eventsCount: - type: number - _maxListeners: - additionalProperties: true - type: object - _position: - type: number - _read: - additionalProperties: true - type: object - _readableState: - additionalProperties: true - type: object - readable: - type: boolean + oneOf: + - nullable: true + type: string + - items: + type: string + nullable: true + type: array ResponseNote: type: object properties: @@ -1388,12 +1420,16 @@ components: properties: end: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number start: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number description: nullable: true type: string @@ -1529,6 +1565,43 @@ components: nullable: true type: string TimelineResponse: + allOf: + - $ref: '#/components/schemas/SavedTimeline' + - type: object + properties: + eventIdToNoteIds: + items: + $ref: '#/components/schemas/Note' + nullable: true + type: array + noteIds: + items: + type: string + nullable: true + type: array + notes: + items: + $ref: '#/components/schemas/Note' + nullable: true + type: array + pinnedEventIds: + items: + type: string + nullable: true + type: array + pinnedEventsSaveObject: + items: + $ref: '#/components/schemas/PinnedEvent' + nullable: true + type: array + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version + TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/SavedTimeline' - type: object From 6e9dd483be474d00ec246d50f9f6f834bb516613 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 16:17:31 +0200 Subject: [PATCH 31/73] clean up route parameters --- .../clean_draft_timelines/index.ts | 3 +- .../get_draft_timelines/index.ts | 3 +- .../server/lib/timeline/routes/index.ts | 28 +++++++++---------- .../lib/timeline/routes/notes/get_notes.ts | 4 +-- .../lib/timeline/routes/notes/persist_note.ts | 4 +-- .../routes/timelines/copy_timeline/index.ts | 3 +- .../timelines/create_timelines/index.ts | 4 +-- .../timelines/delete_timelines/index.ts | 3 +- .../routes/timelines/get_timeline/index.ts | 4 +-- .../timelines/get_timelines/index.test.ts | 8 ++---- .../routes/timelines/get_timelines/index.ts | 4 +-- .../routes/timelines/patch_timelines/index.ts | 4 +-- .../timelines/resolve_timeline/index.ts | 4 +-- 13 files changed, 27 insertions(+), 49 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts index 387720b4a3b4f..6c3e82805ca26 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts @@ -9,7 +9,6 @@ import { v4 as uuidv4 } from 'uuid'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; -import type { ConfigType } from '../../../../..'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { TIMELINE_DRAFT_URL } from '../../../../../../common/constants'; @@ -26,7 +25,7 @@ import { TimelineTypeEnum, } from '../../../../../../common/api/timeline'; -export const cleanDraftTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const cleanDraftTimelinesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .post({ path: TIMELINE_DRAFT_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts index b07130dfcad87..1ba3167cdefae 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts @@ -9,7 +9,6 @@ import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; -import type { ConfigType } from '../../../../..'; import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { TIMELINE_DRAFT_URL } from '../../../../../../common/constants'; @@ -21,7 +20,7 @@ import { type GetDraftTimelinesResponse, } from '../../../../../../common/api/timeline'; -export const getDraftTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const getDraftTimelinesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .get({ path: TIMELINE_DRAFT_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts index 6b44496b6c3c4..905e28872a5a4 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts @@ -28,25 +28,25 @@ import { persistNoteRoute, deleteNoteRoute, getNotesRoute } from './notes'; import { persistPinnedEventRoute } from './pinned_events'; export function registerTimelineRoutes(router: SecuritySolutionPluginRouter, config: ConfigType) { - createTimelinesRoute(router, config); - patchTimelinesRoute(router, config); + createTimelinesRoute(router); + patchTimelinesRoute(router); importTimelinesRoute(router, config); exportTimelinesRoute(router, config); - getDraftTimelinesRoute(router, config); - getTimelineRoute(router, config); - resolveTimelineRoute(router, config); - getTimelinesRoute(router, config); - cleanDraftTimelinesRoute(router, config); - deleteTimelinesRoute(router, config); - persistFavoriteRoute(router, config); - copyTimelineRoute(router, config); + getDraftTimelinesRoute(router); + getTimelineRoute(router); + resolveTimelineRoute(router); + getTimelinesRoute(router); + cleanDraftTimelinesRoute(router); + deleteTimelinesRoute(router); + persistFavoriteRoute(router); + copyTimelineRoute(router); installPrepackedTimelinesRoute(router, config); - persistNoteRoute(router, config); - deleteNoteRoute(router, config); - getNotesRoute(router, config); + persistNoteRoute(router); + deleteNoteRoute(router); + getNotesRoute(router); - persistPinnedEventRoute(router, config); + persistPinnedEventRoute(router); } diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts index 3a26f0b1d02d0..54170e9059177 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/get_notes.ts @@ -12,15 +12,13 @@ import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { NOTE_URL } from '../../../../../common/constants'; -import type { ConfigType } from '../../../..'; - import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; import { getAllSavedNote, MAX_UNASSOCIATED_NOTES } from '../../saved_object/notes'; import { noteSavedObjectType } from '../../saved_object_mappings/notes'; import { GetNotesRequestQuery, type GetNotesResponse } from '../../../../../common/api/timeline'; -export const getNotesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const getNotesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .get({ path: NOTE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts index 9cc7d801aa733..7d0940503b363 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/notes/persist_note.ts @@ -12,8 +12,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../types'; import { NOTE_URL } from '../../../../../common/constants'; -import type { ConfigType } from '../../../..'; - import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../utils/common'; @@ -23,7 +21,7 @@ import { } from '../../../../../common/api/timeline'; import { persistNote } from '../../saved_object/notes'; -export const persistNoteRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const persistNoteRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .patch({ path: NOTE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts index ff9c7ac22d608..e795ec89dd926 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts @@ -8,7 +8,6 @@ import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; -import type { ConfigType } from '../../../../..'; import { CopyTimelineRequestBody, type CopyTimelineResponse, @@ -20,7 +19,7 @@ import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; -export const copyTimelineRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const copyTimelineRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .post({ path: TIMELINE_COPY_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts index 888669b7e6c88..95fb09fb28e56 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/index.ts @@ -12,8 +12,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; -import type { ConfigType } from '../../../../..'; - import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { @@ -30,7 +28,7 @@ import { export * from './helpers'; -export const createTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const createTimelinesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .post({ path: TIMELINE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts index 4542485ae70d3..2720fbb9f7fed 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts @@ -8,7 +8,6 @@ import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; -import type { ConfigType } from '../../../../..'; import { DeleteTimelinesRequestBody, type DeleteTimelinesResponse, @@ -20,7 +19,7 @@ import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; import { deleteTimeline } from '../../../saved_object/timelines'; -export const deleteTimelinesRoute = (router: SecuritySolutionPluginRouter, config: ConfigType) => { +export const deleteTimelinesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .delete({ path: TIMELINE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts index 2500cbea5bb50..1880694b2b3ca 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts @@ -12,8 +12,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; -import type { ConfigType } from '../../../../..'; - import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; @@ -27,7 +25,7 @@ import type { ResolvedTimelineWithOutcomeSavedObject, } from '../../../../../../common/api/timeline'; -export const getTimelineRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const getTimelineRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .get({ path: TIMELINE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.test.ts index b006b77c9a595..753ac1eb15aea 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.test.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - serverMock, - requestContextMock, - createMockConfig, -} from '../../../../detection_engine/routes/__mocks__'; +import { serverMock, requestContextMock } from '../../../../detection_engine/routes/__mocks__'; import { getAllTimeline } from '../../../saved_object/timelines'; import { getTimelineRequest } from '../../../__mocks__/request_responses'; import { getTimelinesRoute } from '.'; @@ -29,7 +25,7 @@ describe('get all timelines', () => { server = serverMock.create(); context = requestContextMock.createTools().context; - getTimelinesRoute(server.router, createMockConfig()); + getTimelinesRoute(server.router); }); test('should get the total count', async () => { diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts index 5772ed443dd17..7fcb8824b5b32 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts @@ -12,8 +12,6 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINES_URL } from '../../../../../../common/constants'; -import type { ConfigType } from '../../../../..'; - import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; @@ -23,7 +21,7 @@ import { type GetTimelinesResponse, } from '../../../../../../common/api/timeline'; -export const getTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const getTimelinesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .get({ path: TIMELINES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts index 5554c34305512..1297f0cb1a829 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/patch_timelines/index.ts @@ -12,8 +12,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_URL } from '../../../../../../common/constants'; -import type { ConfigType } from '../../../../..'; - import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { @@ -24,7 +22,7 @@ import { buildFrameworkRequest, TimelineStatusActions } from '../../../utils/com import { createTimelines } from '../create_timelines'; import { CompareTimelinesStatus } from '../../../utils/compare_timelines_status'; -export const patchTimelinesRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const patchTimelinesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .patch({ path: TIMELINE_URL, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts index 60ffb07752fd2..d3a677133f7c5 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts @@ -13,8 +13,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { TIMELINE_RESOLVE_URL } from '../../../../../../common/constants'; -import type { ConfigType } from '../../../../..'; - import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../utils/common'; @@ -28,7 +26,7 @@ import type { ResolvedTimelineWithOutcomeSavedObject, } from '../../../../../../common/api/timeline'; -export const resolveTimelineRoute = (router: SecuritySolutionPluginRouter, _: ConfigType) => { +export const resolveTimelineRoute = (router: SecuritySolutionPluginRouter) => { router.versioned .get({ path: TIMELINE_RESOLVE_URL, From a863c4b4d7a4a97ac6b5a64fa5ddc3b21909afd7 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 16:27:34 +0200 Subject: [PATCH 32/73] fix errors --- .../public/common/mock/timeline_results.ts | 5 ++++- .../components/open_timeline/helpers.test.ts | 12 ++++++++---- .../routes/timelines/import_timelines/index.test.ts | 1 - 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts index 427285c5f9233..a97be122e8a6a 100644 --- a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts +++ b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts @@ -12,6 +12,7 @@ import { VIEW_SELECTION } from '../../../common/constants'; import type { TimelineResult } from '../../../common/api/timeline'; import { TimelineId, TimelineTabs } from '../../../common/types/timeline'; import { + type ColumnHeaderResult, RowRendererIdEnum, TimelineTypeEnum, TimelineStatusEnum, @@ -1988,7 +1989,9 @@ export const mockDataTableModel: DataTableModel = { export const mockGetOneTimelineResult: TimelineResult = { savedObjectId: 'ef579e40-jibber-jabber', - columns: timelineDefaults.columns.filter((column) => column.id !== 'event.action'), + columns: timelineDefaults.columns.filter( + (column) => column.id !== 'event.action' + ) as ColumnHeaderResult[], dateRange: { start: '2020-03-18T13:46:38.929Z', end: '2020-03-18T13:52:38.929Z' }, description: 'This is a sample rule description', eventType: 'all', diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts index d2151d8bff509..ca93237ebd9e7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts @@ -24,7 +24,11 @@ import { } from './helpers'; import type { OpenTimelineResult } from './types'; import { TimelineId } from '../../../../common/types/timeline'; -import { TimelineTypeEnum, TimelineStatusEnum } from '../../../../common/api/timeline'; +import { + TimelineTypeEnum, + TimelineStatusEnum, + type ColumnHeaderResult, +} from '../../../../common/api/timeline'; import { mockTimeline as mockSelectedTimeline, mockTemplate as mockSelectedTemplate, @@ -378,7 +382,7 @@ describe('helpers', () => { ); const timeline = { savedObjectId: 'savedObject-1', - columns: columnsWithoutEventAction, + columns: columnsWithoutEventAction as ColumnHeaderResult[], version: '1', }; @@ -395,7 +399,7 @@ describe('helpers', () => { ); const timeline = { savedObjectId: 'savedObject-1', - columns: columnsWithoutEventAction, + columns: columnsWithoutEventAction as ColumnHeaderResult[], filters: [ { meta: { @@ -567,7 +571,7 @@ describe('helpers', () => { version: '1', status: TimelineStatusEnum.active, timelineType: TimelineTypeEnum.default, - columns: customColumns, + columns: customColumns as ColumnHeaderResult[], }; const newTimeline = defaultTimelineToTimelineModel( diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts index 74e76dcf38a90..5528d92d34240 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/index.test.ts @@ -39,7 +39,6 @@ import { describe('import timelines', () => { let server: ReturnType; - let request: ReturnType; let securitySetup: SecurityPluginSetup; let { context } = requestContextMock.createTools(); let mockGetTimeline: jest.Mock; From ddf3e6ae9dfd106776de694112e3e235b0c05390 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 9 Aug 2024 20:22:26 +0200 Subject: [PATCH 33/73] fix types --- .../timeline/routes/timelines/get_timeline/index.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.test.ts index 78df97fa441be..781da93355442 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.test.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - serverMock, - requestContextMock, - createMockConfig, -} from '../../../../detection_engine/routes/__mocks__'; +import { serverMock, requestContextMock } from '../../../../detection_engine/routes/__mocks__'; import { getTimelineOrNull, getTimelineTemplateOrNull } from '../../../saved_object/timelines'; import { getTimelineRequest } from '../../../__mocks__/request_responses'; @@ -33,7 +29,7 @@ describe('get timeline', () => { server = serverMock.create(); context = requestContextMock.createTools().context; - getTimelineRoute(server.router, createMockConfig()); + getTimelineRoute(server.router); }); test('should call getTimelineTemplateOrNull if templateTimelineId is given', async () => { From c0850b1573342c6dd7ecf45837272c81e45fadd5 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:14:14 +0000 Subject: [PATCH 34/73] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../import_timelines/create_timelines_stream_from_ndjson.ts | 2 +- .../security_solution/server/lib/timeline/utils/common.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts index 8c1a1cf35d9e4..d5c6c2fa947ec 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { ZodError, ZodType } from 'zod'; +import type { ZodError, ZodType } from '@kbn/zod'; import type { Transform } from 'stream'; import { pipe } from 'fp-ts/lib/pipeable'; import { type Either, fold, left, right } from 'fp-ts/lib/Either'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts index a15cbb95326eb..2c0ed9d70af9d 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { ZodError } from 'zod'; +import type { ZodError } from '@kbn/zod'; import { stringifyZodError } from '@kbn/zod-helpers'; import { set } from '@kbn/safer-lodash-set/fp'; From ea245e4aeb4c0ae36984541522c27af19b1e808d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Sep 2024 04:37:08 +0000 Subject: [PATCH 35/73] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...imeline_api_2023_10_31.bundled.schema.yaml | 98 ++++++------------- ...imeline_api_2023_10_31.bundled.schema.yaml | 98 ++++++------------- 2 files changed, 56 insertions(+), 140 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 016523b851231..856c0f6efffff 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -6,7 +6,7 @@ info: title: Security Solution Timeline API (Elastic Cloud and self-hosted) version: '2023-10-31' servers: - - url: 'http://{kibana_host}:{port}' + - url: http://{kibana_host}:{port} variables: kibana_host: default: localhost @@ -51,12 +51,10 @@ paths: data: type: object description: Indicates the note was successfully deleted. - servers: ! '' - security: ! '' summary: Delete a note tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution get: description: Get all notes for a given document. operationId: GetNotes @@ -104,12 +102,10 @@ paths: - $ref: '#/components/schemas/GetNotesResult' - type: object description: Indicates the requested notes were returned. - servers: ! '' - security: ! '' summary: Get notes tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution patch: description: Add a note to a Timeline or update an existing note. operationId: PersistNoteRoute @@ -141,7 +137,7 @@ paths: type: string required: - note - description: 'The note to add or update, along with additional metadata.' + description: The note to add or update, along with additional metadata. required: true responses: '200': @@ -160,12 +156,10 @@ paths: required: - data description: Indicates the note was successfully created. - servers: ! '' - security: ! '' summary: Add or update a note tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/pinned_event: patch: description: Pin an event to an existing Timeline. @@ -186,7 +180,7 @@ paths: required: - eventId - timelineId - description: 'The pinned event to add or update, along with additional metadata.' + description: The pinned event to add or update, along with additional metadata. required: true responses: '200': @@ -205,12 +199,10 @@ paths: required: - data description: Indicates the event was successfully pinned to the Timeline. - servers: ! '' - security: ! '' summary: Pin an event tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline: delete: description: Delete one or more Timelines or Timeline templates. @@ -253,12 +245,10 @@ paths: required: - data description: Indicates the Timeline was successfully deleted. - servers: ! '' - security: ! '' summary: Delete Timelines or Timeline templates tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution get: description: Get the details of an existing saved Timeline or Timeline template. operationId: GetTimeline @@ -292,12 +282,10 @@ paths: - data - type: object description: Indicates that the (template) Timeline was found and returned. - servers: ! '' - security: ! '' summary: Get Timeline or Timeline template details tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution patch: description: >- Update an existing Timeline. You can update the title, description, date @@ -322,7 +310,7 @@ paths: - timelineId - version - timeline - description: 'The Timeline updates, along with the Timeline ID and version.' + description: The Timeline updates, along with the Timeline ID and version. required: true responses: '200': @@ -362,12 +350,10 @@ paths: description: >- Indicates that the user does not have the required access to create a draft Timeline. - servers: ! '' - security: ! '' summary: Update a Timeline tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution post: description: Create a new Timeline or Timeline template. operationId: CreateTimelines @@ -436,12 +422,10 @@ paths: statusCode: type: number description: Indicates that there was an error in the Timeline creation. - servers: ! '' - security: ! '' summary: Create a Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_copy: get: description: | @@ -483,12 +467,10 @@ paths: required: - data description: Indicates that the timeline has been successfully copied. - servers: ! '' - security: ! '' summary: Copies timeline or timeline template. tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_draft: get: description: >- @@ -526,7 +508,7 @@ paths: description: Indicates that the draft Timeline was successfully retrieved. '403': content: - 'application:json': + application:json: schema: type: object properties: @@ -540,7 +522,7 @@ paths: create a draft Timeline. '409': content: - 'application:json': + application:json: schema: type: object properties: @@ -552,12 +534,10 @@ paths: This should never happen, but if a draft Timeline was not found and we attempted to create one, it indicates that there is already a draft Timeline with the given `timelineId`. - servers: ! '' - security: ! '' summary: Get draft Timeline or Timeline template details tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution post: description: > Create a clean draft Timeline or Timeline template for the current user. @@ -608,7 +588,7 @@ paths: Timeline is cleared and returned. '403': content: - 'application:json': + application:json: schema: type: object properties: @@ -621,7 +601,7 @@ paths: create a draft Timeline. '409': content: - 'application:json': + application:json: schema: type: object properties: @@ -632,12 +612,10 @@ paths: description: >- Indicates that there is already a draft Timeline with the given `timelineId`. - servers: ! '' - security: ! '' summary: Create a clean draft Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_export: post: description: Export Timelines as an NDJSON file. @@ -681,12 +659,10 @@ paths: statusCode: type: number description: Indicates that the export size limit was exceeded. - servers: ! '' - security: ! '' summary: Export Timelines tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_favorite: patch: description: Favorite a Timeline or Timeline template for the current user. @@ -735,7 +711,7 @@ paths: description: Indicates the favorite status was successfully updated. '403': content: - 'application:json': + application:json: schema: type: object properties: @@ -746,12 +722,10 @@ paths: description: >- Indicates the user does not have the required permissions to persist the favorite status. - servers: ! '' - security: ! '' summary: Favorite a Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_import: post: description: Import Timelines. @@ -820,12 +794,10 @@ paths: statusCode: type: number description: Indicates the import of Timelines was unsuccessful. - servers: ! '' - security: ! '' summary: Import Timelines tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_prepackaged: post: description: Install or update prepackaged Timelines. @@ -866,7 +838,7 @@ paths: description: Indicates the installation of prepackaged Timelines was successful. '500': content: - 'application:json': + application:json: schema: type: object properties: @@ -877,12 +849,10 @@ paths: description: >- Indicates the installation of prepackaged Timelines was unsuccessful. - servers: ! '' - security: ! '' summary: Install prepackaged Timelines tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/resolve: get: operationId: ResolveTimeline @@ -915,12 +885,10 @@ paths: description: The request is missing parameters '404': description: The (template) Timeline was not found - servers: ! '' - security: ! '' summary: Get an existing saved Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timelines: get: description: Get a list of all saved Timelines or Timeline templates. @@ -1009,7 +977,7 @@ paths: description: Indicates that the (template) Timelines were found and returned. '400': content: - 'application:json': + application:json: schema: type: object properties: @@ -1018,20 +986,11 @@ paths: statusCode: type: number description: Bad request. The user supplied invalid data. - servers: ! '' - security: ! '' summary: Get Timelines or Timeline templates tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution components: - callbacks: ! '' - examples: ! '' - headers: ! '' - links: ! '' - parameters: ! '' - requestBodies: ! '' - responses: ! '' schemas: BareNote: type: object @@ -1715,4 +1674,3 @@ tags: You can create Timelines and Timeline templates via the API, as well as import new Timelines from an ndjson file. name: Security Solution Timeline API -externalDocs: ! '' diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index f01edc49f53be..621a89cfe4627 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -6,7 +6,7 @@ info: title: Security Solution Timeline API (Elastic Cloud Serverless) version: '2023-10-31' servers: - - url: 'http://{kibana_host}:{port}' + - url: http://{kibana_host}:{port} variables: kibana_host: default: localhost @@ -51,12 +51,10 @@ paths: data: type: object description: Indicates the note was successfully deleted. - servers: ! '' - security: ! '' summary: Delete a note tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution get: description: Get all notes for a given document. operationId: GetNotes @@ -104,12 +102,10 @@ paths: - $ref: '#/components/schemas/GetNotesResult' - type: object description: Indicates the requested notes were returned. - servers: ! '' - security: ! '' summary: Get notes tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution patch: description: Add a note to a Timeline or update an existing note. operationId: PersistNoteRoute @@ -141,7 +137,7 @@ paths: type: string required: - note - description: 'The note to add or update, along with additional metadata.' + description: The note to add or update, along with additional metadata. required: true responses: '200': @@ -160,12 +156,10 @@ paths: required: - data description: Indicates the note was successfully created. - servers: ! '' - security: ! '' summary: Add or update a note tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/pinned_event: patch: description: Pin an event to an existing Timeline. @@ -186,7 +180,7 @@ paths: required: - eventId - timelineId - description: 'The pinned event to add or update, along with additional metadata.' + description: The pinned event to add or update, along with additional metadata. required: true responses: '200': @@ -205,12 +199,10 @@ paths: required: - data description: Indicates the event was successfully pinned to the Timeline. - servers: ! '' - security: ! '' summary: Pin an event tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline: delete: description: Delete one or more Timelines or Timeline templates. @@ -253,12 +245,10 @@ paths: required: - data description: Indicates the Timeline was successfully deleted. - servers: ! '' - security: ! '' summary: Delete Timelines or Timeline templates tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution get: description: Get the details of an existing saved Timeline or Timeline template. operationId: GetTimeline @@ -292,12 +282,10 @@ paths: - data - type: object description: Indicates that the (template) Timeline was found and returned. - servers: ! '' - security: ! '' summary: Get Timeline or Timeline template details tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution patch: description: >- Update an existing Timeline. You can update the title, description, date @@ -322,7 +310,7 @@ paths: - timelineId - version - timeline - description: 'The Timeline updates, along with the Timeline ID and version.' + description: The Timeline updates, along with the Timeline ID and version. required: true responses: '200': @@ -362,12 +350,10 @@ paths: description: >- Indicates that the user does not have the required access to create a draft Timeline. - servers: ! '' - security: ! '' summary: Update a Timeline tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution post: description: Create a new Timeline or Timeline template. operationId: CreateTimelines @@ -436,12 +422,10 @@ paths: statusCode: type: number description: Indicates that there was an error in the Timeline creation. - servers: ! '' - security: ! '' summary: Create a Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_copy: get: description: | @@ -483,12 +467,10 @@ paths: required: - data description: Indicates that the timeline has been successfully copied. - servers: ! '' - security: ! '' summary: Copies timeline or timeline template. tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_draft: get: description: >- @@ -526,7 +508,7 @@ paths: description: Indicates that the draft Timeline was successfully retrieved. '403': content: - 'application:json': + application:json: schema: type: object properties: @@ -540,7 +522,7 @@ paths: create a draft Timeline. '409': content: - 'application:json': + application:json: schema: type: object properties: @@ -552,12 +534,10 @@ paths: This should never happen, but if a draft Timeline was not found and we attempted to create one, it indicates that there is already a draft Timeline with the given `timelineId`. - servers: ! '' - security: ! '' summary: Get draft Timeline or Timeline template details tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution post: description: > Create a clean draft Timeline or Timeline template for the current user. @@ -608,7 +588,7 @@ paths: Timeline is cleared and returned. '403': content: - 'application:json': + application:json: schema: type: object properties: @@ -621,7 +601,7 @@ paths: create a draft Timeline. '409': content: - 'application:json': + application:json: schema: type: object properties: @@ -632,12 +612,10 @@ paths: description: >- Indicates that there is already a draft Timeline with the given `timelineId`. - servers: ! '' - security: ! '' summary: Create a clean draft Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_export: post: description: Export Timelines as an NDJSON file. @@ -681,12 +659,10 @@ paths: statusCode: type: number description: Indicates that the export size limit was exceeded. - servers: ! '' - security: ! '' summary: Export Timelines tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_favorite: patch: description: Favorite a Timeline or Timeline template for the current user. @@ -735,7 +711,7 @@ paths: description: Indicates the favorite status was successfully updated. '403': content: - 'application:json': + application:json: schema: type: object properties: @@ -746,12 +722,10 @@ paths: description: >- Indicates the user does not have the required permissions to persist the favorite status. - servers: ! '' - security: ! '' summary: Favorite a Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_import: post: description: Import Timelines. @@ -820,12 +794,10 @@ paths: statusCode: type: number description: Indicates the import of Timelines was unsuccessful. - servers: ! '' - security: ! '' summary: Import Timelines tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/_prepackaged: post: description: Install or update prepackaged Timelines. @@ -866,7 +838,7 @@ paths: description: Indicates the installation of prepackaged Timelines was successful. '500': content: - 'application:json': + application:json: schema: type: object properties: @@ -877,12 +849,10 @@ paths: description: >- Indicates the installation of prepackaged Timelines was unsuccessful. - servers: ! '' - security: ! '' summary: Install prepackaged Timelines tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timeline/resolve: get: operationId: ResolveTimeline @@ -915,12 +885,10 @@ paths: description: The request is missing parameters '404': description: The (template) Timeline was not found - servers: ! '' - security: ! '' summary: Get an existing saved Timeline or Timeline template tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution /api/timelines: get: description: Get a list of all saved Timelines or Timeline templates. @@ -1009,7 +977,7 @@ paths: description: Indicates that the (template) Timelines were found and returned. '400': content: - 'application:json': + application:json: schema: type: object properties: @@ -1018,20 +986,11 @@ paths: statusCode: type: number description: Bad request. The user supplied invalid data. - servers: ! '' - security: ! '' summary: Get Timelines or Timeline templates tags: - Security Solution Timeline API - - 'access:securitySolution' + - access:securitySolution components: - callbacks: ! '' - examples: ! '' - headers: ! '' - links: ! '' - parameters: ! '' - requestBodies: ! '' - responses: ! '' schemas: BareNote: type: object @@ -1715,4 +1674,3 @@ tags: You can create Timelines and Timeline templates via the API, as well as import new Timelines from an ndjson file. name: Security Solution Timeline API -externalDocs: ! '' From 85541bb5974591fa87646ae6f2b3e3a6e4a17277 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 24 Sep 2024 21:09:33 +0200 Subject: [PATCH 36/73] add missing `type` to `DataProviderQueryMatch` --- .../common/api/timeline/model/components.gen.ts | 1 + .../common/api/timeline/model/components.schema.yaml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index 6cd7d41258c15..479a98b080cf4 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -72,6 +72,7 @@ export const DataProviderQueryMatch = z.object({ kqlQuery: z.string().nullable().optional(), name: z.string().nullable().optional(), queryMatch: QueryMatchResult.nullable().optional(), + type: DataProviderType.nullable().optional(), }); export type DataProviderResult = z.infer; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index c9692a29b2b92..81f3127e65c73 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -325,6 +325,9 @@ components: queryMatch: $ref: '#/components/schemas/QueryMatchResult' nullable: true + type: + $ref: '#/components/schemas/DataProviderType' + nullable: true BareNoteWithoutExternalRefs: type: object properties: From 7a39d884b216549c373679b8ed81df9b38d7c9d2 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 08:47:53 +0200 Subject: [PATCH 37/73] Fix types --- .../import_timelines_route.ts | 60 ------------------- .../pinned_events/persist_pinned_event.ts | 4 -- 2 files changed, 64 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts deleted file mode 100644 index 2ad6f3f8c7333..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.ts +++ /dev/null @@ -1,60 +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 rt from 'io-ts'; - -import { BareNoteSchema, SavedTimelineRuntimeType } from '../model/api'; -import { unionWithNullType } from '../../../utility_types'; - -const pinnedEventIds = unionWithNullType(rt.array(rt.string)); - -export const eventNotes = unionWithNullType(rt.array(BareNoteSchema)); -export const globalNotes = unionWithNullType(rt.array(BareNoteSchema)); - -export const ImportTimelinesSchemaRt = rt.intersection([ - SavedTimelineRuntimeType, - rt.type({ - savedObjectId: unionWithNullType(rt.string), - version: unionWithNullType(rt.string), - }), - rt.type({ - globalNotes, - eventNotes, - pinnedEventIds, - }), -]); - -export type ImportTimelinesSchema = rt.TypeOf; - -const ReadableRt = rt.partial({ - _maxListeners: rt.unknown, - _readableState: rt.unknown, - _read: rt.unknown, - readable: rt.boolean, - _events: rt.unknown, - _eventsCount: rt.number, - _data: rt.unknown, - _position: rt.number, - _encoding: rt.string, -}); - -const booleanInString = rt.union([rt.literal('true'), rt.literal('false')]); - -export const ImportTimelinesPayloadSchemaRt = rt.intersection([ - rt.type({ - file: rt.intersection([ - ReadableRt, - rt.type({ - hapi: rt.type({ - filename: rt.string, - headers: rt.unknown, - }), - }), - ]), - }), - rt.partial({ isImmutable: booleanInString }), -]); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts index 2d546e2d91b1c..74db9e58d904b 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts @@ -58,10 +58,6 @@ export const persistPinnedEventRoute = (router: SecuritySolutionPluginRouter) => timelineId ); - const body: PersistPinnedEventRouteResponse = { - data: { persistPinnedEventOnTimeline: res }, - }; - return response.ok({ body: { data: { persistPinnedEventOnTimeline: res }, From 316d1e3765b94d23901936e270fcf946feb2bf5c Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 08:49:48 +0200 Subject: [PATCH 38/73] Update docs --- .../output/kibana.serverless.staging.yaml | 281 +++++++++++------- oas_docs/output/kibana.staging.yaml | 281 +++++++++++------- 2 files changed, 358 insertions(+), 204 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index c1079be34d264..47c4892e8723c 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16530,19 +16530,20 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_TimelineResponse - nullable: true + data: + type: object + properties: + getOneTimeline: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_TimelineResponse + required: + - getOneTimeline required: - - getOneTimeline - required: - - data + - data + - type: object description: Indicates that the (template) Timeline was found and returned. summary: Get Timeline or Timeline template details tags: @@ -16672,6 +16673,8 @@ paths: timeline: $ref: >- #/components/schemas/Security_Solution_Timeline_API_TimelineResponse + required: + - timeline required: - persistTimeline required: @@ -16692,6 +16695,53 @@ paths: tags: - Security Solution Timeline API - access:securitySolution + /api/timeline/_copy: + get: + description: | + Copies and returns a timeline or timeline template. + operationId: CopyTimeline + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + type: object + properties: + timeline: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_SavedTimeline + timelineIdToCopy: + type: string + required: + - timeline + - timelineIdToCopy + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_TimelineResponse + required: + - timeline + required: + - persistTimeline + required: + - data + description: Indicates that the timeline has been successfully copied. + summary: Copies timeline or timeline template. + tags: + - Security Solution Timeline API + - access:securitySolution /api/timeline/_draft: get: description: >- @@ -16962,29 +17012,14 @@ paths: schema: type: object properties: - file: - allOf: - - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_Readable - - type: object - properties: - hapi: - type: object - properties: - filename: - type: string - headers: - type: object - isImmutable: - enum: - - 'true' - - 'false' - type: string - required: - - filename - - headers - required: - - hapi + file: {} + isImmutable: + enum: + - 'true' + - 'false' + type: string + required: + - file description: The Timelines to import as a readable stream. required: true responses: @@ -16992,13 +17027,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult - required: - - data + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult description: Indicates the import of Timelines was successful. '400': content: @@ -17058,7 +17088,8 @@ paths: prepackagedTimelines: items: $ref: >- - #/components/schemas/Security_Solution_Timeline_API_SavedTimeline + #/components/schemas/Security_Solution_Timeline_API_TimelineSavedToReturnObject + nullable: true type: array timelinesToInstall: items: @@ -17083,13 +17114,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult - required: - - data + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult description: Indicates the installation of prepackaged Timelines was successful. '500': content: @@ -17127,19 +17153,15 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: + data: $ref: >- #/components/schemas/Security_Solution_Timeline_API_TimelineResponse - nullable: true required: - - getOneTimeline - required: - - data + - data + - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -17207,10 +17229,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: customTemplateTimelineCount: type: number @@ -17222,7 +17242,7 @@ paths: type: number templateTimelineCount: type: number - timelines: + timeline: items: $ref: >- #/components/schemas/Security_Solution_Timeline_API_TimelineResponse @@ -17230,15 +17250,14 @@ paths: totalCount: type: number required: - - timelines + - timeline - totalCount - defaultTimelineCount - templateTimelineCount - favoriteCount - elasticTemplateTimelineCount - customTemplateTimelineCount - required: - - data + - type: object description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -32424,30 +32443,39 @@ components: type: object properties: aggregatable: + nullable: true type: boolean category: + nullable: true type: string columnHeaderType: + nullable: true type: string description: + nullable: true type: string example: - oneOf: - - type: string - - type: number + nullable: true + type: string id: + nullable: true type: string indexes: items: type: string + nullable: true type: array name: + nullable: true type: string placeholder: + nullable: true type: string searchable: + nullable: true type: boolean type: + nullable: true type: string Security_Solution_Timeline_API_DataProviderQueryMatch: type: object @@ -32469,6 +32497,10 @@ components: type: string queryMatch: $ref: '#/components/schemas/Security_Solution_Timeline_API_QueryMatchResult' + nullable: true + type: + $ref: '#/components/schemas/Security_Solution_Timeline_API_DataProviderType' + nullable: true Security_Solution_Timeline_API_DataProviderResult: type: object properties: @@ -32558,41 +32590,59 @@ components: type: object properties: exists: - type: boolean + nullable: true + type: string match_all: + nullable: true type: string meta: + nullable: true type: object properties: alias: + nullable: true type: string controlledBy: + nullable: true type: string disabled: + nullable: true type: boolean field: + nullable: true type: string formattedValue: + nullable: true type: string index: + nullable: true type: string key: + nullable: true type: string negate: + nullable: true type: boolean params: + nullable: true type: string type: + nullable: true type: string value: + nullable: true type: string missing: + nullable: true type: string query: + nullable: true type: string range: + nullable: true type: string script: + nullable: true type: string Security_Solution_Timeline_API_GetNotesResult: type: object @@ -32657,6 +32707,12 @@ components: version: nullable: true type: string + required: + - savedObjectId + - version + - pinnedEventIds + - eventNotes + - globalNotes Security_Solution_Timeline_API_Note: allOf: - $ref: '#/components/schemas/Security_Solution_Timeline_API_BareNote' @@ -32714,34 +32770,13 @@ components: nullable: true type: string value: - nullable: true - type: string - Security_Solution_Timeline_API_Readable: - type: object - properties: - _data: - additionalProperties: true - type: object - _encoding: - type: string - _events: - additionalProperties: true - type: object - _eventsCount: - type: number - _maxListeners: - additionalProperties: true - type: object - _position: - type: number - _read: - additionalProperties: true - type: object - _readableState: - additionalProperties: true - type: object - readable: - type: boolean + oneOf: + - nullable: true + type: string + - items: + type: string + nullable: true + type: array Security_Solution_Timeline_API_ResponseNote: type: object properties: @@ -32806,12 +32841,16 @@ components: properties: end: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number start: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number description: nullable: true type: string @@ -32950,6 +32989,44 @@ components: nullable: true type: string Security_Solution_Timeline_API_TimelineResponse: + allOf: + - $ref: '#/components/schemas/Security_Solution_Timeline_API_SavedTimeline' + - type: object + properties: + eventIdToNoteIds: + items: + $ref: '#/components/schemas/Security_Solution_Timeline_API_Note' + nullable: true + type: array + noteIds: + items: + type: string + nullable: true + type: array + notes: + items: + $ref: '#/components/schemas/Security_Solution_Timeline_API_Note' + nullable: true + type: array + pinnedEventIds: + items: + type: string + nullable: true + type: array + pinnedEventsSaveObject: + items: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_PinnedEvent + nullable: true + type: array + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version + Security_Solution_Timeline_API_TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/Security_Solution_Timeline_API_SavedTimeline' - type: object diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index c92cf81b7f14a..3baa37463ce27 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -20638,19 +20638,20 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_TimelineResponse - nullable: true + data: + type: object + properties: + getOneTimeline: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_TimelineResponse + required: + - getOneTimeline required: - - getOneTimeline - required: - - data + - data + - type: object description: Indicates that the (template) Timeline was found and returned. summary: Get Timeline or Timeline template details tags: @@ -20780,6 +20781,8 @@ paths: timeline: $ref: >- #/components/schemas/Security_Solution_Timeline_API_TimelineResponse + required: + - timeline required: - persistTimeline required: @@ -20800,6 +20803,53 @@ paths: tags: - Security Solution Timeline API - access:securitySolution + /api/timeline/_copy: + get: + description: | + Copies and returns a timeline or timeline template. + operationId: CopyTimeline + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + type: object + properties: + timeline: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_SavedTimeline + timelineIdToCopy: + type: string + required: + - timeline + - timelineIdToCopy + required: true + responses: + '200': + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_TimelineResponse + required: + - timeline + required: + - persistTimeline + required: + - data + description: Indicates that the timeline has been successfully copied. + summary: Copies timeline or timeline template. + tags: + - Security Solution Timeline API + - access:securitySolution /api/timeline/_draft: get: description: >- @@ -21070,29 +21120,14 @@ paths: schema: type: object properties: - file: - allOf: - - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_Readable - - type: object - properties: - hapi: - type: object - properties: - filename: - type: string - headers: - type: object - isImmutable: - enum: - - 'true' - - 'false' - type: string - required: - - filename - - headers - required: - - hapi + file: {} + isImmutable: + enum: + - 'true' + - 'false' + type: string + required: + - file description: The Timelines to import as a readable stream. required: true responses: @@ -21100,13 +21135,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult - required: - - data + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult description: Indicates the import of Timelines was successful. '400': content: @@ -21166,7 +21196,8 @@ paths: prepackagedTimelines: items: $ref: >- - #/components/schemas/Security_Solution_Timeline_API_SavedTimeline + #/components/schemas/Security_Solution_Timeline_API_TimelineSavedToReturnObject + nullable: true type: array timelinesToInstall: items: @@ -21191,13 +21222,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult - required: - - data + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_ImportTimelineResult description: Indicates the installation of prepackaged Timelines was successful. '500': content: @@ -21235,19 +21261,15 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: - getOneTimeline: + data: $ref: >- #/components/schemas/Security_Solution_Timeline_API_TimelineResponse - nullable: true required: - - getOneTimeline - required: - - data + - data + - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -21315,10 +21337,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object + oneOf: + - type: object properties: customTemplateTimelineCount: type: number @@ -21330,7 +21350,7 @@ paths: type: number templateTimelineCount: type: number - timelines: + timeline: items: $ref: >- #/components/schemas/Security_Solution_Timeline_API_TimelineResponse @@ -21338,15 +21358,14 @@ paths: totalCount: type: number required: - - timelines + - timeline - totalCount - defaultTimelineCount - templateTimelineCount - favoriteCount - elasticTemplateTimelineCount - customTemplateTimelineCount - required: - - data + - type: object description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -40453,30 +40472,39 @@ components: type: object properties: aggregatable: + nullable: true type: boolean category: + nullable: true type: string columnHeaderType: + nullable: true type: string description: + nullable: true type: string example: - oneOf: - - type: string - - type: number + nullable: true + type: string id: + nullable: true type: string indexes: items: type: string + nullable: true type: array name: + nullable: true type: string placeholder: + nullable: true type: string searchable: + nullable: true type: boolean type: + nullable: true type: string Security_Solution_Timeline_API_DataProviderQueryMatch: type: object @@ -40498,6 +40526,10 @@ components: type: string queryMatch: $ref: '#/components/schemas/Security_Solution_Timeline_API_QueryMatchResult' + nullable: true + type: + $ref: '#/components/schemas/Security_Solution_Timeline_API_DataProviderType' + nullable: true Security_Solution_Timeline_API_DataProviderResult: type: object properties: @@ -40587,41 +40619,59 @@ components: type: object properties: exists: - type: boolean + nullable: true + type: string match_all: + nullable: true type: string meta: + nullable: true type: object properties: alias: + nullable: true type: string controlledBy: + nullable: true type: string disabled: + nullable: true type: boolean field: + nullable: true type: string formattedValue: + nullable: true type: string index: + nullable: true type: string key: + nullable: true type: string negate: + nullable: true type: boolean params: + nullable: true type: string type: + nullable: true type: string value: + nullable: true type: string missing: + nullable: true type: string query: + nullable: true type: string range: + nullable: true type: string script: + nullable: true type: string Security_Solution_Timeline_API_GetNotesResult: type: object @@ -40686,6 +40736,12 @@ components: version: nullable: true type: string + required: + - savedObjectId + - version + - pinnedEventIds + - eventNotes + - globalNotes Security_Solution_Timeline_API_Note: allOf: - $ref: '#/components/schemas/Security_Solution_Timeline_API_BareNote' @@ -40743,34 +40799,13 @@ components: nullable: true type: string value: - nullable: true - type: string - Security_Solution_Timeline_API_Readable: - type: object - properties: - _data: - additionalProperties: true - type: object - _encoding: - type: string - _events: - additionalProperties: true - type: object - _eventsCount: - type: number - _maxListeners: - additionalProperties: true - type: object - _position: - type: number - _read: - additionalProperties: true - type: object - _readableState: - additionalProperties: true - type: object - readable: - type: boolean + oneOf: + - nullable: true + type: string + - items: + type: string + nullable: true + type: array Security_Solution_Timeline_API_ResponseNote: type: object properties: @@ -40835,12 +40870,16 @@ components: properties: end: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number start: oneOf: - - type: string - - type: number + - nullable: true + type: string + - nullable: true + type: number description: nullable: true type: string @@ -40979,6 +41018,44 @@ components: nullable: true type: string Security_Solution_Timeline_API_TimelineResponse: + allOf: + - $ref: '#/components/schemas/Security_Solution_Timeline_API_SavedTimeline' + - type: object + properties: + eventIdToNoteIds: + items: + $ref: '#/components/schemas/Security_Solution_Timeline_API_Note' + nullable: true + type: array + noteIds: + items: + type: string + nullable: true + type: array + notes: + items: + $ref: '#/components/schemas/Security_Solution_Timeline_API_Note' + nullable: true + type: array + pinnedEventIds: + items: + type: string + nullable: true + type: array + pinnedEventsSaveObject: + items: + $ref: >- + #/components/schemas/Security_Solution_Timeline_API_PinnedEvent + nullable: true + type: array + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version + Security_Solution_Timeline_API_TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/Security_Solution_Timeline_API_SavedTimeline' - type: object From 51c05bad4ea7102da219cf588af67a145095e8e6 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 25 Sep 2024 07:41:11 +0000 Subject: [PATCH 39/73] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...ecurity_solution_timeline_api_2023_10_31.bundled.schema.yaml | 2 +- ...ecurity_solution_timeline_api_2023_10_31.bundled.schema.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index db86829e70d19..6bcab666f6160 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -469,7 +469,7 @@ paths: description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: - - Security Solution Timeline API + - Security Timeline API - access:securitySolution /api/timeline/_draft: get: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index d9e8ad3f0eb9a..1fbd468bd60c1 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -469,7 +469,7 @@ paths: description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: - - Security Solution Timeline API + - Security Timeline API - access:securitySolution /api/timeline/_draft: get: From 05b11f1592d599d6f9dcbb6429776191985b9c38 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:31:35 +0000 Subject: [PATCH 40/73] [CI] Auto-commit changed files from 'make api-docs && make api-docs-staging' --- oas_docs/output/kibana.serverless.staging.yaml | 2 +- oas_docs/output/kibana.staging.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 9c81981f16c71..7aba8318a0cd1 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16531,7 +16531,7 @@ paths: description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: - - Security Solution Timeline API + - Security Timeline API - access:securitySolution /api/timeline/_draft: get: diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 7a76e7f178ff0..7864ce0139145 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -20620,7 +20620,7 @@ paths: description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: - - Security Solution Timeline API + - Security Timeline API - access:securitySolution /api/timeline/_draft: get: From cfd3c1626e43cad315e87d95d8e1a831e6328c0f Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 12:49:44 +0200 Subject: [PATCH 41/73] use zod-generated types for resolved timeline types --- .../common/api/timeline/model/api.ts | 10 +--- .../api/timeline/model/components.gen.ts | 47 ++++++++++++++----- .../api/timeline/model/components.schema.yaml | 23 +++++++++ .../resolve_timeline_route.gen.ts | 5 +- .../resolve_timeline_route.schema.yaml | 3 +- .../components/open_timeline/helpers.ts | 4 +- .../components/open_timeline/types.ts | 8 ++-- .../public/timelines/containers/api.ts | 25 +++++++--- .../timeline/__mocks__/resolve_timeline.ts | 4 +- .../routes/timelines/get_timeline/index.ts | 7 +-- .../timelines/resolve_timeline/index.ts | 7 +-- .../saved_object/timelines/index.test.ts | 4 +- .../timeline/saved_object/timelines/index.ts | 4 +- 13 files changed, 97 insertions(+), 54 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 6d7c888f21027..9a2c37cfac6e9 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -23,6 +23,7 @@ import { ImportTimelines, type Note, PinnedEvent, + ResolvedTimeline, RowRendererId, RowRendererIdEnum, SavedTimeline, @@ -47,6 +48,7 @@ export { ImportTimelines, Note, PinnedEvent, + ResolvedTimeline, RowRendererId, RowRendererIdEnum, SavedTimeline, @@ -374,14 +376,6 @@ export type ResolvedTimelineWithOutcomeSavedObject = runtimeTypes.TypeOf< typeof ResolvedTimelineSavedObjectToReturnObjectRuntimeType >; -export const ResolvedSingleTimelineResponseType = runtimeTypes.type({ - data: ResolvedTimelineSavedObjectToReturnObjectRuntimeType, -}); - -export type SingleTimelineResolveResponse = runtimeTypes.TypeOf< - typeof ResolvedSingleTimelineResponseType ->; - const responseTimelines = runtimeTypes.type({ timeline: runtimeTypes.array(TimelineSavedToReturnObjectRuntimeType), totalCount: runtimeTypes.number, diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index 479a98b080cf4..6dc0ec7409ead 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -265,6 +265,40 @@ export const TimelineResponse = SavedTimeline.merge( }) ); +export type TimelineSavedToReturnObject = z.infer; +export const TimelineSavedToReturnObject = SavedTimeline.merge( + z.object({ + savedObjectId: z.string(), + version: z.string(), + eventIdToNoteIds: z.array(Note).optional(), + notes: z.array(Note).optional(), + noteIds: z.array(z.string()).optional(), + pinnedEventIds: z.array(z.string()).optional(), + pinnedEventsSaveObject: z.array(PinnedEvent).optional(), + }) +); + +export type SavedObjectResolveOutcome = z.infer; +export const SavedObjectResolveOutcome = z.enum(['exactMatch', 'aliasMatch', 'conflict']); +export type SavedObjectResolveOutcomeEnum = typeof SavedObjectResolveOutcome.enum; +export const SavedObjectResolveOutcomeEnum = SavedObjectResolveOutcome.enum; + +export type SavedObjectResolveAliasPurpose = z.infer; +export const SavedObjectResolveAliasPurpose = z.enum([ + 'savedObjectConversion', + 'savedObjectImport', +]); +export type SavedObjectResolveAliasPurposeEnum = typeof SavedObjectResolveAliasPurpose.enum; +export const SavedObjectResolveAliasPurposeEnum = SavedObjectResolveAliasPurpose.enum; + +export type ResolvedTimeline = z.infer; +export const ResolvedTimeline = z.object({ + timeline: TimelineSavedToReturnObject, + outcome: SavedObjectResolveOutcome, + alias_target_id: z.string().optional(), + alias_purpose: SavedObjectResolveAliasPurpose.optional(), +}); + export type FavoriteTimelineResponse = z.infer; export const FavoriteTimelineResponse = z.object({ savedObjectId: z.string(), @@ -332,19 +366,6 @@ export const ImportTimelines = SavedTimeline.merge( }) ); -export type TimelineSavedToReturnObject = z.infer; -export const TimelineSavedToReturnObject = SavedTimeline.merge( - z.object({ - savedObjectId: z.string(), - version: z.string(), - eventIdToNoteIds: z.array(Note).optional(), - notes: z.array(Note).optional(), - noteIds: z.array(z.string()).optional(), - pinnedEventIds: z.array(z.string()).optional(), - pinnedEventsSaveObject: z.array(PinnedEvent).optional(), - }) -); - export type ImportTimelineResult = z.infer; export const ImportTimelineResult = z.object({ success: z.boolean().optional(), diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index 81f3127e65c73..107582fde777f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -188,6 +188,29 @@ components: type: string version: type: string + ResolvedTimeline: + type: object + required: [timeline, outcome] + properties: + timeline: + $ref: '#/components/schemas/TimelineSavedToReturnObject' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + alias_target_id: + type: string + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + SavedObjectResolveOutcome: + type: string + enum: + - exactMatch + - aliasMatch + - conflict + SavedObjectResolveAliasPurpose: + type: string + enum: + - savedObjectConversion + - savedObjectImport FavoriteTimelineResponse: type: object required: [savedObjectId, version] diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts index 0531db234905d..15f8dc7850734 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts @@ -16,7 +16,7 @@ import { z } from '@kbn/zod'; -import { TimelineResponse } from '../model/components.gen'; +import { ResolvedTimeline } from '../model/components.gen'; export type ResolveTimelineRequestQuery = z.infer; export const ResolveTimelineRequestQuery = z.object({ @@ -34,7 +34,6 @@ export type ResolveTimelineRequestQueryInput = z.input; export const ResolveTimelineResponse = z.union([ z.object({ - data: TimelineResponse, + data: ResolvedTimeline, }), - z.object({}), ]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml index ea4414aa4b100..0156dad66baa1 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml @@ -40,8 +40,7 @@ paths: required: [data] properties: data: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' - - type: object + $ref: '../model/components.schema.yaml#/components/schemas/ResolvedTimeline' '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts index 81114901c216d..5f2f0c520fc01 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts @@ -15,7 +15,7 @@ import { useDiscoverInTimelineContext } from '../../../common/components/discove import type { ColumnHeaderOptions } from '../../../../common/types/timeline'; import type { TimelineResult, - SingleTimelineResolveResponse, + ResolvedTimeline, ColumnHeaderResult, FilterTimelineResult, DataProviderResult, @@ -376,7 +376,7 @@ export const useQueryTimelineById = () => { } else { return Promise.resolve(resolveTimeline(timelineId)) .then((result) => { - const data: SingleTimelineResolveResponse['data'] | null = getOr(null, 'data', result); + const data: ResolvedTimeline['data'] | null = getOr(null, 'data', result); if (!data) return; const timelineToOpen = omitTypenameInTimeline(data.timeline); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts index 1a47c22d0fb61..de01a172b4673 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts @@ -10,7 +10,7 @@ import type { IconType } from '@elastic/eui'; import type { TimelineModel } from '../../store/model'; import type { RowRendererId, - SingleTimelineResolveResponse, + ResolvedTimeline, TimelineType, TimelineStatus, TemplateTimelineType, @@ -210,9 +210,9 @@ export interface OpenTimelineProps { } export interface ResolveTimelineConfig { - alias_target_id: SingleTimelineResolveResponse['data']['alias_target_id']; - outcome: SingleTimelineResolveResponse['data']['outcome']; - alias_purpose: SingleTimelineResolveResponse['data']['alias_purpose']; + alias_target_id: ResolvedTimeline['data']['alias_target_id']; + outcome: ResolvedTimeline['data']['outcome']; + alias_purpose: ResolvedTimeline['data']['alias_purpose']; } export interface UpdateTimeline { duplicate: boolean; diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 5f9ed27bddaad..18b9a73392274 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { fold } from 'fp-ts/lib/Either'; +import type { ZodError, ZodType } from '@kbn/zod'; +import { type Either, fold, left, right } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { isEmpty } from 'lodash'; @@ -29,10 +30,10 @@ import { importTimelineResultSchema, allTimelinesResponse, PersistFavoriteRouteResponse, - SingleTimelineResponseType, type TimelineType, TimelineTypeEnum, ResolvedSingleTimelineResponseType, + GetTimelineResponse, } from '../../../common/api/timeline'; import { TIMELINE_URL, @@ -68,6 +69,21 @@ interface RequestPatchTimeline extends RequestPostTimeline { type RequestPersistTimeline = RequestPostTimeline & Partial>; const createToasterPlainError = (message: string) => new ToasterError([message]); + +type ErrorFactory = (message: string) => Error; + +const parseRuntimeType = + (zodType: ZodType) => + (v: unknown): Either, T> => { + const result = zodType.safeParse(v); + return result.success ? right(result.data) : left(result.error); + }; + +const decodeOrThrow = + (runtimeType: ZodType, createError: ErrorFactory = createToasterPlainError) => + (inputValue: unknown) => + pipe(parseRuntimeType(runtimeType)(inputValue), fold(throwErrors(createError), identity)); + const decodeTimelineResponse = (respTimeline?: TimelineResponse | TimelineErrorResponse) => pipe( TimelineResponseType.decode(respTimeline), @@ -75,10 +91,7 @@ const decodeTimelineResponse = (respTimeline?: TimelineResponse | TimelineErrorR ); const decodeSingleTimelineResponse = (respTimeline?: SingleTimelineResponse) => - pipe( - SingleTimelineResponseType.decode(respTimeline), - fold(throwErrors(createToasterPlainError), identity) - ); + decodeOrThrow(GetTimelineResponse)(respTimeline); const decodeResolvedSingleTimelineResponse = (respTimeline?: SingleTimelineResolveResponse) => pipe( diff --git a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/resolve_timeline.ts b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/resolve_timeline.ts index ea875a71416c1..932e6f3ce904d 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/resolve_timeline.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/__mocks__/resolve_timeline.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { ResolvedTimelineWithOutcomeSavedObject } from '../../../../common/api/timeline'; +import type { ResolvedTimeline } from '../../../../common/api/timeline'; import { TimelineStatusEnum, TimelineTypeEnum } from '../../../../common/api/timeline'; export const mockResolvedSavedObject = { @@ -117,7 +117,7 @@ export const mockPopulatedTimeline = { pinnedEventsSaveObject: [], }; -export const mockResolveTimelineResponse: ResolvedTimelineWithOutcomeSavedObject = { +export const mockResolveTimelineResponse: ResolvedTimeline = { timeline: mockPopulatedTimeline, outcome: 'aliasMatch', alias_target_id: 'new-saved-object-id', diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts index 1880694b2b3ca..04a3df7638f43 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts @@ -20,10 +20,7 @@ import { type GetTimelineResponse, } from '../../../../../../common/api/timeline'; import { getTimelineTemplateOrNull, getTimelineOrNull } from '../../../saved_object/timelines'; -import type { - TimelineSavedObject, - ResolvedTimelineWithOutcomeSavedObject, -} from '../../../../../../common/api/timeline'; +import type { TimelineSavedObject, ResolvedTimeline } from '../../../../../../common/api/timeline'; export const getTimelineRoute = (router: SecuritySolutionPluginRouter) => { router.versioned @@ -47,7 +44,7 @@ export const getTimelineRoute = (router: SecuritySolutionPluginRouter) => { const query = request.query ?? {}; const { template_timeline_id: templateTimelineId, id } = query; - let res: TimelineSavedObject | ResolvedTimelineWithOutcomeSavedObject | null = null; + let res: TimelineSavedObject | ResolvedTimeline | null = null; if (templateTimelineId != null && id == null) { res = await getTimelineTemplateOrNull(frameworkRequest, templateTimelineId); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts index d3a677133f7c5..0afc7d21ae296 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts @@ -21,10 +21,7 @@ import { type ResolveTimelineResponse, } from '../../../../../../common/api/timeline'; import { getTimelineTemplateOrNull, resolveTimelineOrNull } from '../../../saved_object/timelines'; -import type { - SavedTimeline, - ResolvedTimelineWithOutcomeSavedObject, -} from '../../../../../../common/api/timeline'; +import type { SavedTimeline, ResolvedTimeline } from '../../../../../../common/api/timeline'; export const resolveTimelineRoute = (router: SecuritySolutionPluginRouter) => { router.versioned @@ -48,7 +45,7 @@ export const resolveTimelineRoute = (router: SecuritySolutionPluginRouter) => { const query = request.query ?? {}; const { template_timeline_id: templateTimelineId, id } = query; - let res: SavedTimeline | ResolvedTimelineWithOutcomeSavedObject | null = null; + let res: SavedTimeline | ResolvedTimeline | null = null; if (templateTimelineId != null && id == null) { // Template timelineId is not a SO id, so it does not need to be updated to use resolve diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts index 20049a63bddba..c2ccbfeb15040 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts @@ -24,7 +24,7 @@ import { getAllPinnedEventsByTimelineId, persistPinnedEventOnTimeline } from '.. import { TimelineTypeEnum } from '../../../../../common/api/timeline'; import type { AllTimelinesResponse, - ResolvedTimelineWithOutcomeSavedObject, + ResolvedTimeline, SavedTimeline, } from '../../../../../common/api/timeline'; import { @@ -275,7 +275,7 @@ describe('saved_object', () => { describe('resolveTimelineOrNull', () => { let mockResolveSavedObject: jest.Mock; let mockRequest: FrameworkRequest; - let result: ResolvedTimelineWithOutcomeSavedObject | null = null; + let result: ResolvedTimeline | null = null; beforeEach(async () => { (convertSavedObjectToSavedTimeline as jest.Mock).mockReturnValue(mockResolvedTimeline); mockResolveSavedObject = jest.fn().mockReturnValue(mockResolvedSavedObject); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts index 08eeda3d8ab56..d1a4a0bbe950f 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts @@ -29,7 +29,7 @@ import type { TimelineResult, TimelineType, TimelineStatus, - ResolvedTimelineWithOutcomeSavedObject, + ResolvedTimeline, TimelineSavedObject, SavedTimeline, TimelineWithoutExternalRefs, @@ -89,7 +89,7 @@ export const getTimelineOrNull = async ( export const resolveTimelineOrNull = async ( frameworkRequest: FrameworkRequest, savedObjectId: string -): Promise => { +): Promise => { let resolvedTimeline = null; try { resolvedTimeline = await resolveSavedTimeline(frameworkRequest, savedObjectId); From 2fc6922447a5d14474ad2f19cddb3ed7ec59a6f6 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 13:41:58 +0200 Subject: [PATCH 42/73] fix type error --- .../public/timelines/containers/api.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 18b9a73392274..b4371077a9e5b 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -20,7 +20,6 @@ import type { ImportTimelineResultSchema, AllTimelinesResponse, SingleTimelineResponse, - SingleTimelineResolveResponse, GetAllTimelineVariables, } from '../../../common/api/timeline'; import { @@ -32,8 +31,8 @@ import { PersistFavoriteRouteResponse, type TimelineType, TimelineTypeEnum, - ResolvedSingleTimelineResponseType, GetTimelineResponse, + ResolveTimelineResponse, } from '../../../common/api/timeline'; import { TIMELINE_URL, @@ -93,11 +92,8 @@ const decodeTimelineResponse = (respTimeline?: TimelineResponse | TimelineErrorR const decodeSingleTimelineResponse = (respTimeline?: SingleTimelineResponse) => decodeOrThrow(GetTimelineResponse)(respTimeline); -const decodeResolvedSingleTimelineResponse = (respTimeline?: SingleTimelineResolveResponse) => - pipe( - ResolvedSingleTimelineResponseType.decode(respTimeline), - fold(throwErrors(createToasterPlainError), identity) - ); +const decodeResolvedSingleTimelineResponse = (respTimeline?: ResolveTimelineResponse) => + decodeOrThrow(ResolveTimelineResponse)(respTimeline); const decodeAllTimelinesResponse = (respTimeline: AllTimelinesResponse) => pipe( @@ -410,7 +406,7 @@ export const getTimeline = async (id: string) => { }; export const resolveTimeline = async (id: string) => { - const response = await KibanaServices.get().http.get( + const response = await KibanaServices.get().http.get( TIMELINE_RESOLVE_URL, { query: { From 294b83180134d5845443cc25fe8543d6e3ab2e96 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 13:45:03 +0200 Subject: [PATCH 43/73] remove unused types --- .../common/api/timeline/model/api.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 9a2c37cfac6e9..9150b0b3496ba 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -360,22 +360,6 @@ export const SingleTimelineResponseType = runtimeTypes.type({ export type SingleTimelineResponse = runtimeTypes.TypeOf; -/** Resolved Timeline Response */ -export const ResolvedTimelineSavedObjectToReturnObjectRuntimeType = runtimeTypes.intersection([ - runtimeTypes.type({ - timeline: TimelineSavedToReturnObjectRuntimeType, - outcome: SavedObjectResolveOutcome, - }), - runtimeTypes.partial({ - alias_target_id: SavedObjectResolveAliasTargetId, - alias_purpose: SavedObjectResolveAliasPurpose, - }), -]); - -export type ResolvedTimelineWithOutcomeSavedObject = runtimeTypes.TypeOf< - typeof ResolvedTimelineSavedObjectToReturnObjectRuntimeType ->; - const responseTimelines = runtimeTypes.type({ timeline: runtimeTypes.array(TimelineSavedToReturnObjectRuntimeType), totalCount: runtimeTypes.number, From 493b95cad84ae1321081809670bd9d9461e47c58 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 25 Sep 2024 11:55:16 +0000 Subject: [PATCH 44/73] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...imeline_api_2023_10_31.bundled.schema.yaml | 28 +++++++++++++++++-- ...imeline_api_2023_10_31.bundled.schema.yaml | 28 +++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 6bcab666f6160..ded9d3ab052da 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -876,10 +876,9 @@ paths: - type: object properties: data: - $ref: '#/components/schemas/TimelineResponse' + $ref: '#/components/schemas/ResolvedTimeline' required: - data - - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -1374,6 +1373,20 @@ components: type: string nullable: true type: array + ResolvedTimeline: + type: object + properties: + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + type: string + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + timeline: + $ref: '#/components/schemas/TimelineSavedToReturnObject' + required: + - timeline + - outcome ResponseNote: type: object properties: @@ -1408,6 +1421,17 @@ components: - threat_match - zeek type: string + SavedObjectResolveAliasPurpose: + enum: + - savedObjectConversion + - savedObjectImport + type: string + SavedObjectResolveOutcome: + enum: + - exactMatch + - aliasMatch + - conflict + type: string SavedTimeline: type: object properties: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 1fbd468bd60c1..0bc0b82bcdf97 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -876,10 +876,9 @@ paths: - type: object properties: data: - $ref: '#/components/schemas/TimelineResponse' + $ref: '#/components/schemas/ResolvedTimeline' required: - data - - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -1374,6 +1373,20 @@ components: type: string nullable: true type: array + ResolvedTimeline: + type: object + properties: + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + type: string + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + timeline: + $ref: '#/components/schemas/TimelineSavedToReturnObject' + required: + - timeline + - outcome ResponseNote: type: object properties: @@ -1408,6 +1421,17 @@ components: - threat_match - zeek type: string + SavedObjectResolveAliasPurpose: + enum: + - savedObjectConversion + - savedObjectImport + type: string + SavedObjectResolveOutcome: + enum: + - exactMatch + - aliasMatch + - conflict + type: string SavedTimeline: type: object properties: From f080b00cf3121ac83ab098bb03f98c25eb0d5dd5 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 14:00:38 +0200 Subject: [PATCH 45/73] AllTimelesResponse -> GetTimelinesResponse, --- .../public/timelines/containers/api.ts | 16 ++++++---------- .../saved_object/timelines/index.test.ts | 4 ++-- .../lib/timeline/saved_object/timelines/index.ts | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index b4371077a9e5b..257b4d230ff74 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -18,21 +18,20 @@ import type { TimelineResponse, TimelineErrorResponse, ImportTimelineResultSchema, - AllTimelinesResponse, SingleTimelineResponse, GetAllTimelineVariables, + TimelineType, } from '../../../common/api/timeline'; import { TimelineResponseType, TimelineStatusEnum, TimelineErrorResponseType, importTimelineResultSchema, - allTimelinesResponse, PersistFavoriteRouteResponse, - type TimelineType, TimelineTypeEnum, GetTimelineResponse, ResolveTimelineResponse, + GetTimelinesResponse, } from '../../../common/api/timeline'; import { TIMELINE_URL, @@ -95,11 +94,8 @@ const decodeSingleTimelineResponse = (respTimeline?: SingleTimelineResponse) => const decodeResolvedSingleTimelineResponse = (respTimeline?: ResolveTimelineResponse) => decodeOrThrow(ResolveTimelineResponse)(respTimeline); -const decodeAllTimelinesResponse = (respTimeline: AllTimelinesResponse) => - pipe( - allTimelinesResponse.decode(respTimeline), - fold(throwErrors(createToasterPlainError), identity) - ); +const decodeGetTimelinesResponse = (respTimeline: GetTimelinesResponse) => + decodeOrThrow(GetTimelinesResponse)(respTimeline); const decodeTimelineErrorResponse = (respTimeline?: TimelineErrorResponse) => pipe( @@ -431,7 +427,7 @@ export const getTimelineTemplate = async (templateTimelineId: string) => { }; export const getAllTimelines = async (args: GetAllTimelineVariables, abortSignal: AbortSignal) => { - const response = await KibanaServices.get().http.fetch(TIMELINES_URL, { + const response = await KibanaServices.get().http.fetch(TIMELINES_URL, { method: 'GET', query: { ...(args.onlyUserFavorite ? { only_user_favorite: args.onlyUserFavorite } : {}), @@ -447,7 +443,7 @@ export const getAllTimelines = async (args: GetAllTimelineVariables, abortSignal version: '2023-10-31', }); - return decodeAllTimelinesResponse(response); + return decodeGetTimelinesResponse(response); }; export const persistFavorite = async ({ diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts index c2ccbfeb15040..7e25a38363e2a 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts @@ -23,7 +23,7 @@ import { getNotesByTimelineId, persistNote } from '../notes/saved_object'; import { getAllPinnedEventsByTimelineId, persistPinnedEventOnTimeline } from '../pinned_events'; import { TimelineTypeEnum } from '../../../../../common/api/timeline'; import type { - AllTimelinesResponse, + GetTimelinesResponse, ResolvedTimeline, SavedTimeline, } from '../../../../../common/api/timeline'; @@ -141,7 +141,7 @@ describe('saved_object', () => { pageSize: 10, pageIndex: 1, }; - let result = null as unknown as AllTimelinesResponse; + let result = null as unknown as GetTimelinesResponse; beforeEach(async () => { (convertSavedObjectToSavedTimeline as jest.Mock).mockReturnValue(mockGetTimelineValue); mockFindSavedObject = jest diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts index d1a4a0bbe950f..1ff380319744f 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts @@ -19,7 +19,7 @@ import type { Note, BareNote, PinnedEvent, - AllTimelinesResponse, + GetTimelinesResponse, ExportTimelineNotFoundError, PageInfoTimeline, ResponseTimelines, @@ -218,7 +218,7 @@ export const getAllTimeline = async ( sort: SortTimeline | null, status: TimelineStatus | null, timelineType: TimelineType | null -): Promise => { +): Promise => { const searchTerm = search != null ? search : undefined; const searchFields = ['title', 'description']; const filter = combineFilters([ From 33f918d04036f21c77e593799cfc633a1ddb0993 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 14:07:00 +0200 Subject: [PATCH 46/73] fix types --- .../public/timelines/components/open_timeline/helpers.ts | 2 +- .../public/timelines/components/open_timeline/types.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts index 5f2f0c520fc01..e977d05f07689 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts @@ -376,7 +376,7 @@ export const useQueryTimelineById = () => { } else { return Promise.resolve(resolveTimeline(timelineId)) .then((result) => { - const data: ResolvedTimeline['data'] | null = getOr(null, 'data', result); + const data: ResolvedTimeline | null = getOr(null, 'data', result); if (!data) return; const timelineToOpen = omitTypenameInTimeline(data.timeline); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts index de01a172b4673..14ddedf5b9688 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts @@ -210,9 +210,9 @@ export interface OpenTimelineProps { } export interface ResolveTimelineConfig { - alias_target_id: ResolvedTimeline['data']['alias_target_id']; - outcome: ResolvedTimeline['data']['outcome']; - alias_purpose: ResolvedTimeline['data']['alias_purpose']; + alias_target_id: ResolvedTimeline['alias_target_id']; + outcome: ResolvedTimeline['outcome']; + alias_purpose: ResolvedTimeline['alias_purpose']; } export interface UpdateTimeline { duplicate: boolean; From 2846e0df97acd9eeb3004f8679a76938408d7b0c Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:27:38 +0000 Subject: [PATCH 47/73] [CI] Auto-commit changed files from 'make api-docs && make api-docs-staging' --- .../output/kibana.serverless.staging.yaml | 30 +++++++++++++++++-- oas_docs/output/kibana.staging.yaml | 30 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 7aba8318a0cd1..df652370caa87 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16945,10 +16945,9 @@ paths: properties: data: $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse + #/components/schemas/Security_Timeline_API_ResolvedTimeline required: - data - - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -31470,6 +31469,22 @@ components: type: string nullable: true type: array + Security_Timeline_API_ResolvedTimeline: + type: object + properties: + alias_purpose: + $ref: >- + #/components/schemas/Security_Timeline_API_SavedObjectResolveAliasPurpose + alias_target_id: + type: string + outcome: + $ref: '#/components/schemas/Security_Timeline_API_SavedObjectResolveOutcome' + timeline: + $ref: >- + #/components/schemas/Security_Timeline_API_TimelineSavedToReturnObject + required: + - timeline + - outcome Security_Timeline_API_ResponseNote: type: object properties: @@ -31504,6 +31519,17 @@ components: - threat_match - zeek type: string + Security_Timeline_API_SavedObjectResolveAliasPurpose: + enum: + - savedObjectConversion + - savedObjectImport + type: string + Security_Timeline_API_SavedObjectResolveOutcome: + enum: + - exactMatch + - aliasMatch + - conflict + type: string Security_Timeline_API_SavedTimeline: type: object properties: diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 7864ce0139145..c205f94528896 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -21034,10 +21034,9 @@ paths: properties: data: $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse + #/components/schemas/Security_Timeline_API_ResolvedTimeline required: - data - - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -39479,6 +39478,22 @@ components: type: string nullable: true type: array + Security_Timeline_API_ResolvedTimeline: + type: object + properties: + alias_purpose: + $ref: >- + #/components/schemas/Security_Timeline_API_SavedObjectResolveAliasPurpose + alias_target_id: + type: string + outcome: + $ref: '#/components/schemas/Security_Timeline_API_SavedObjectResolveOutcome' + timeline: + $ref: >- + #/components/schemas/Security_Timeline_API_TimelineSavedToReturnObject + required: + - timeline + - outcome Security_Timeline_API_ResponseNote: type: object properties: @@ -39513,6 +39528,17 @@ components: - threat_match - zeek type: string + Security_Timeline_API_SavedObjectResolveAliasPurpose: + enum: + - savedObjectConversion + - savedObjectImport + type: string + Security_Timeline_API_SavedObjectResolveOutcome: + enum: + - exactMatch + - aliasMatch + - conflict + type: string Security_Timeline_API_SavedTimeline: type: object properties: From f3795b34e15e16f53538f08491861051f0c1ff18 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 16:36:18 +0200 Subject: [PATCH 48/73] add PersistTimelineResponse --- .../clean_draft_timelines_route.gen.ts | 10 +- .../clean_draft_timelines_route.schema.yaml | 14 +-- .../copy_timeline/copy_timeline_route.gen.ts | 10 +- .../copy_timeline_route.schema.yaml | 14 +-- .../create_timelines_route.gen.ts | 10 +- .../create_timelines_route.schema.yaml | 14 +-- .../get_draft_timelines_route.gen.ts | 10 +- .../get_draft_timelines_route.schema.yaml | 14 +-- .../api/timeline/model/components.gen.ts | 9 ++ .../api/timeline/model/components.schema.yaml | 14 +++ .../patch_timeline_route.gen.ts | 10 +- .../patch_timeline_route.schema.yaml | 14 +-- ...imeline_api_2023_10_31.bundled.schema.yaml | 102 ++++-------------- ...imeline_api_2023_10_31.bundled.schema.yaml | 102 ++++-------------- .../public/timelines/containers/api.ts | 7 +- 15 files changed, 86 insertions(+), 268 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.gen.ts index 514a06ceec328..f3858b1cb8f34 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.gen.ts @@ -16,7 +16,7 @@ import { z } from '@kbn/zod'; -import { TimelineType, TimelineResponse } from '../model/components.gen'; +import { TimelineType, PersistTimelineResponse } from '../model/components.gen'; export type CleanDraftTimelinesRequestBody = z.infer; export const CleanDraftTimelinesRequestBody = z.object({ @@ -25,10 +25,4 @@ export const CleanDraftTimelinesRequestBody = z.object({ export type CleanDraftTimelinesRequestBodyInput = z.input; export type CleanDraftTimelinesResponse = z.infer; -export const CleanDraftTimelinesResponse = z.object({ - data: z.object({ - persistTimeline: z.object({ - timeline: TimelineResponse, - }), - }), -}); +export const CleanDraftTimelinesResponse = PersistTimelineResponse; diff --git a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml index 5e1fbff1f296d..4dd0760645105 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml @@ -39,19 +39,7 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object - required: [persistTimeline] - properties: - persistTimeline: - type: object - required: [timeline] - properties: - timeline: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' + $ref: '../model/components.schema.yaml#/components/schemas/PersistTimelineResponse' '403': description: Indicates that the user does not have the required permissions to create a draft Timeline. content: diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts index 72379c704d215..6e75f0baaf7ef 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.gen.ts @@ -16,7 +16,7 @@ import { z } from '@kbn/zod'; -import { SavedTimeline, TimelineResponse } from '../model/components.gen'; +import { SavedTimeline, PersistTimelineResponse } from '../model/components.gen'; export type CopyTimelineRequestBody = z.infer; export const CopyTimelineRequestBody = z.object({ @@ -26,10 +26,4 @@ export const CopyTimelineRequestBody = z.object({ export type CopyTimelineRequestBodyInput = z.input; export type CopyTimelineResponse = z.infer; -export const CopyTimelineResponse = z.object({ - data: z.object({ - persistTimeline: z.object({ - timeline: TimelineResponse, - }), - }), -}); +export const CopyTimelineResponse = PersistTimelineResponse; diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml index 8e26439440bf1..3da337a7d471f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml @@ -38,16 +38,4 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object - required: [persistTimeline] - properties: - persistTimeline: - type: object - required: [timeline] - properties: - timeline: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' + $ref: '../model/components.schema.yaml#/components/schemas/PersistTimelineResponse' diff --git a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts index e4d8cd0e9cbce..33fc1855f390a 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.gen.ts @@ -20,7 +20,7 @@ import { SavedTimeline, TimelineStatus, TimelineType, - TimelineResponse, + PersistTimelineResponse, } from '../model/components.gen'; export type CreateTimelinesRequestBody = z.infer; @@ -36,10 +36,4 @@ export const CreateTimelinesRequestBody = z.object({ export type CreateTimelinesRequestBodyInput = z.input; export type CreateTimelinesResponse = z.infer; -export const CreateTimelinesResponse = z.object({ - data: z.object({ - persistTimeline: z.object({ - timeline: TimelineResponse, - }), - }), -}); +export const CreateTimelinesResponse = PersistTimelineResponse; diff --git a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml index 9f6bd811f009b..f2a59d1ab0d29 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml @@ -57,19 +57,7 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object - required: [persistTimeline] - properties: - persistTimeline: - type: object - required: [timeline] - properties: - timeline: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' + $ref: '../model/components.schema.yaml#/components/schemas/PersistTimelineResponse' '405': description: Indicates that there was an error in the Timeline creation. content: diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.gen.ts index edbbc37744d03..327f02a8fb6f5 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.gen.ts @@ -16,7 +16,7 @@ import { z } from '@kbn/zod'; -import { TimelineType, TimelineResponse } from '../model/components.gen'; +import { TimelineType, PersistTimelineResponse } from '../model/components.gen'; export type GetDraftTimelinesRequestQuery = z.infer; export const GetDraftTimelinesRequestQuery = z.object({ @@ -25,10 +25,4 @@ export const GetDraftTimelinesRequestQuery = z.object({ export type GetDraftTimelinesRequestQueryInput = z.input; export type GetDraftTimelinesResponse = z.infer; -export const GetDraftTimelinesResponse = z.object({ - data: z.object({ - persistTimeline: z.object({ - timeline: TimelineResponse, - }), - }), -}); +export const GetDraftTimelinesResponse = PersistTimelineResponse; diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml index 21cabb87cd335..7dd424a5e2dec 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml @@ -31,19 +31,7 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object - required: [persistTimeline] - properties: - persistTimeline: - type: object - required: [timeline] - properties: - timeline: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' + $ref: '../model/components.schema.yaml#/components/schemas/PersistTimelineResponse' '403': description: If a draft Timeline was not found and we attempted to create one, it indicates that the user does not have the required permissions to create a draft Timeline. content: diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index 6dc0ec7409ead..1b1290195afbc 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -311,6 +311,15 @@ export const FavoriteTimelineResponse = z.object({ favorite: z.array(FavoriteTimelineResult).optional(), }); +export type PersistTimelineResponse = z.infer; +export const PersistTimelineResponse = z.object({ + data: z.object({ + persistTimeline: z.object({ + timeline: TimelineResponse, + }), + }), +}); + export type BareNoteWithoutExternalRefs = z.infer; export const BareNoteWithoutExternalRefs = z.object({ eventId: z.string().nullable().optional(), diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index 107582fde777f..eeed806a1dd18 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -237,6 +237,20 @@ components: type: array items: $ref: '#/components/schemas/FavoriteTimelineResult' + PersistTimelineResponse: + type: object + required: [data] + properties: + data: + type: object + required: [persistTimeline] + properties: + persistTimeline: + type: object + required: [timeline] + properties: + timeline: + $ref: '#/components/schemas/TimelineResponse' ColumnHeaderResult: type: object properties: diff --git a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.gen.ts index d0f2befe6b338..622c56312e21a 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.gen.ts @@ -16,7 +16,7 @@ import { z } from '@kbn/zod'; -import { SavedTimeline, TimelineResponse } from '../model/components.gen'; +import { SavedTimeline, PersistTimelineResponse } from '../model/components.gen'; export type PatchTimelineRequestBody = z.infer; export const PatchTimelineRequestBody = z.object({ @@ -27,10 +27,4 @@ export const PatchTimelineRequestBody = z.object({ export type PatchTimelineRequestBodyInput = z.input; export type PatchTimelineResponse = z.infer; -export const PatchTimelineResponse = z.object({ - data: z.object({ - persistTimeline: z.object({ - timeline: TimelineResponse, - }), - }), -}); +export const PatchTimelineResponse = PersistTimelineResponse; diff --git a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml index 31ff7d8312673..e8dfa8bf4b992 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml @@ -42,19 +42,7 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - type: object - required: [persistTimeline] - properties: - persistTimeline: - type: object - required: [timeline] - properties: - timeline: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' + $ref: '../model/components.schema.yaml#/components/schemas/PersistTimelineResponse' '405': description: Indicates that the user does not have the required access to create a draft Timeline. content: diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index ded9d3ab052da..548968ea08d19 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -317,22 +317,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -394,22 +379,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates the Timeline was successfully created. '405': content: @@ -450,22 +420,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: @@ -489,22 +444,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates that the draft Timeline was successfully retrieved. '403': content: @@ -566,22 +506,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -1329,6 +1254,23 @@ components: - $ref: '#/components/schemas/PinnedEventBaseResponseBody' - nullable: true type: object + PersistTimelineResponse: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: '#/components/schemas/TimelineResponse' + required: + - timeline + required: + - persistTimeline + required: + - data PinnedEvent: allOf: - $ref: '#/components/schemas/BarePinnedEvent' diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 0bc0b82bcdf97..2114c2d334c0d 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -317,22 +317,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -394,22 +379,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates the Timeline was successfully created. '405': content: @@ -450,22 +420,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: @@ -489,22 +444,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates that the draft Timeline was successfully retrieved. '403': content: @@ -566,22 +506,7 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: '#/components/schemas/TimelineResponse' - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: '#/components/schemas/PersistTimelineResponse' description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -1329,6 +1254,23 @@ components: - $ref: '#/components/schemas/PinnedEventBaseResponseBody' - nullable: true type: object + PersistTimelineResponse: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: '#/components/schemas/TimelineResponse' + required: + - timeline + required: + - persistTimeline + required: + - data PinnedEvent: allOf: - $ref: '#/components/schemas/BarePinnedEvent' diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 257b4d230ff74..1295fe3d92817 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -21,6 +21,7 @@ import type { SingleTimelineResponse, GetAllTimelineVariables, TimelineType, + PatchTimelineResponse, } from '../../../common/api/timeline'; import { TimelineResponseType, @@ -110,7 +111,7 @@ const decodePrepackedTimelineResponse = (respTimeline?: ImportTimelineResultSche ); const decodeResponseFavoriteTimeline = (respTimeline?: PersistFavoriteRouteResponse) => - PersistFavoriteRouteResponse.parse(respTimeline); + decodeOrThrow(PersistFavoriteRouteResponse)(respTimeline); const postTimeline = async ({ timeline, @@ -136,7 +137,7 @@ const patchTimeline = async ({ timeline, version, savedSearch, -}: RequestPatchTimeline): Promise => { +}: RequestPatchTimeline): Promise => { let response = null; let requestBody = null; try { @@ -158,7 +159,7 @@ const patchTimeline = async ({ } try { - response = await KibanaServices.get().http.patch(TIMELINE_URL, { + response = await KibanaServices.get().http.patch(TIMELINE_URL, { method: 'PATCH', body: requestBody, version: '2023-10-31', From a1ee8067c1339605a0a02f08725217bdb6894f65 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 17:06:34 +0200 Subject: [PATCH 49/73] fix types and update type bundle --- .../get_timelines/get_timelines_route.gen.ts | 21 +++--- .../get_timelines_route.schema.yaml | 57 ++++++++-------- .../resolve_timeline_route.gen.ts | 8 +-- .../resolve_timeline_route.schema.yaml | 11 ++- ...imeline_api_2023_10_31.bundled.schema.yaml | 67 +++++++++---------- ...imeline_api_2023_10_31.bundled.schema.yaml | 67 +++++++++---------- 6 files changed, 108 insertions(+), 123 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts index 7fecbb3f3bad3..e2828beb876c3 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts @@ -40,15 +40,12 @@ export const GetTimelinesRequestQuery = z.object({ export type GetTimelinesRequestQueryInput = z.input; export type GetTimelinesResponse = z.infer; -export const GetTimelinesResponse = z.union([ - z.object({ - timeline: z.array(TimelineResponse), - totalCount: z.number(), - defaultTimelineCount: z.number(), - templateTimelineCount: z.number(), - favoriteCount: z.number(), - elasticTemplateTimelineCount: z.number(), - customTemplateTimelineCount: z.number(), - }), - z.object({}), -]); +export const GetTimelinesResponse = z.object({ + timeline: z.array(TimelineResponse), + totalCount: z.number(), + defaultTimelineCount: z.number(), + templateTimelineCount: z.number(), + favoriteCount: z.number(), + elasticTemplateTimelineCount: z.number(), + customTemplateTimelineCount: z.number(), +}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml index 6bc1adec53003..73afeac39bba3 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml @@ -74,36 +74,33 @@ paths: content: application/json: schema: - oneOf: - - type: object - required: - [ - timeline, - totalCount, - defaultTimelineCount, - templateTimelineCount, - favoriteCount, - elasticTemplateTimelineCount, - customTemplateTimelineCount, - ] - properties: - timeline: - type: array - items: - $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' - totalCount: - type: number - defaultTimelineCount: - type: number - templateTimelineCount: - type: number - favoriteCount: - type: number - elasticTemplateTimelineCount: - type: number - customTemplateTimelineCount: - type: number - - type: object + type: object + required: [ + timeline, + totalCount, + defaultTimelineCount, + templateTimelineCount, + favoriteCount, + elasticTemplateTimelineCount, + customTemplateTimelineCount, + ] + properties: + timeline: + type: array + items: + $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' + totalCount: + type: number + defaultTimelineCount: + type: number + templateTimelineCount: + type: number + favoriteCount: + type: number + elasticTemplateTimelineCount: + type: number + customTemplateTimelineCount: + type: number '400': description: Bad request. The user supplied invalid data. content: diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts index 15f8dc7850734..452e80a7470af 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts @@ -32,8 +32,6 @@ export const ResolveTimelineRequestQuery = z.object({ export type ResolveTimelineRequestQueryInput = z.input; export type ResolveTimelineResponse = z.infer; -export const ResolveTimelineResponse = z.union([ - z.object({ - data: ResolvedTimeline, - }), -]); +export const ResolveTimelineResponse = z.object({ + data: ResolvedTimeline, +}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml index 0156dad66baa1..515528949b297 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml @@ -35,12 +35,11 @@ paths: content: application/json: schema: - oneOf: - - type: object - required: [data] - properties: - data: - $ref: '../model/components.schema.yaml#/components/schemas/ResolvedTimeline' + type: object + required: [data] + properties: + data: + $ref: '../model/components.schema.yaml#/components/schemas/ResolvedTimeline' '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 548968ea08d19..381a932ff6f6b 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -797,13 +797,12 @@ paths: content: application/json: schema: - oneOf: - - type: object - properties: - data: - $ref: '#/components/schemas/ResolvedTimeline' - required: - - data + type: object + properties: + data: + $ref: '#/components/schemas/ResolvedTimeline' + required: + - data description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -870,34 +869,32 @@ paths: content: application/json: schema: - oneOf: - - type: object - properties: - customTemplateTimelineCount: - type: number - defaultTimelineCount: - type: number - elasticTemplateTimelineCount: - type: number - favoriteCount: - type: number - templateTimelineCount: - type: number - timeline: - items: - $ref: '#/components/schemas/TimelineResponse' - type: array - totalCount: - type: number - required: - - timeline - - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount - - type: object + type: object + properties: + customTemplateTimelineCount: + type: number + defaultTimelineCount: + type: number + elasticTemplateTimelineCount: + type: number + favoriteCount: + type: number + templateTimelineCount: + type: number + timeline: + items: + $ref: '#/components/schemas/TimelineResponse' + type: array + totalCount: + type: number + required: + - timeline + - totalCount + - defaultTimelineCount + - templateTimelineCount + - favoriteCount + - elasticTemplateTimelineCount + - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 2114c2d334c0d..d8bef08c98477 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -797,13 +797,12 @@ paths: content: application/json: schema: - oneOf: - - type: object - properties: - data: - $ref: '#/components/schemas/ResolvedTimeline' - required: - - data + type: object + properties: + data: + $ref: '#/components/schemas/ResolvedTimeline' + required: + - data description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -870,34 +869,32 @@ paths: content: application/json: schema: - oneOf: - - type: object - properties: - customTemplateTimelineCount: - type: number - defaultTimelineCount: - type: number - elasticTemplateTimelineCount: - type: number - favoriteCount: - type: number - templateTimelineCount: - type: number - timeline: - items: - $ref: '#/components/schemas/TimelineResponse' - type: array - totalCount: - type: number - required: - - timeline - - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount - - type: object + type: object + properties: + customTemplateTimelineCount: + type: number + defaultTimelineCount: + type: number + elasticTemplateTimelineCount: + type: number + favoriteCount: + type: number + templateTimelineCount: + type: number + timeline: + items: + $ref: '#/components/schemas/TimelineResponse' + type: array + totalCount: + type: number + required: + - timeline + - totalCount + - defaultTimelineCount + - templateTimelineCount + - favoriteCount + - elasticTemplateTimelineCount + - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: From 34d0dcd53288be3e511fa4b0adcc71f457429ecf Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 17:08:48 +0200 Subject: [PATCH 50/73] update docs build --- .../output/kibana.serverless.staging.yaml | 183 ++++++------------ oas_docs/output/kibana.staging.yaml | 183 ++++++------------ 2 files changed, 122 insertions(+), 244 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index df652370caa87..8d2b28343c092 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16376,23 +16376,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -16454,23 +16439,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates the Timeline was successfully created. '405': content: @@ -16511,23 +16481,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: @@ -16551,23 +16506,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates that the draft Timeline was successfully retrieved. '403': content: @@ -16629,23 +16569,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -16940,14 +16865,13 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - oneOf: - - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Timeline_API_ResolvedTimeline - required: - - data + type: object + properties: + data: + $ref: >- + #/components/schemas/Security_Timeline_API_ResolvedTimeline + required: + - data description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -17014,35 +16938,33 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - oneOf: - - type: object - properties: - customTemplateTimelineCount: - type: number - defaultTimelineCount: - type: number - elasticTemplateTimelineCount: - type: number - favoriteCount: - type: number - templateTimelineCount: - type: number - timeline: - items: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - type: array - totalCount: - type: number - required: - - timeline - - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount - - type: object + type: object + properties: + customTemplateTimelineCount: + type: number + defaultTimelineCount: + type: number + elasticTemplateTimelineCount: + type: number + favoriteCount: + type: number + templateTimelineCount: + type: number + timeline: + items: + $ref: >- + #/components/schemas/Security_Timeline_API_TimelineResponse + type: array + totalCount: + type: number + required: + - timeline + - totalCount + - defaultTimelineCount + - templateTimelineCount + - favoriteCount + - elasticTemplateTimelineCount + - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -31425,6 +31347,23 @@ components: #/components/schemas/Security_Timeline_API_PinnedEventBaseResponseBody - nullable: true type: object + Security_Timeline_API_PersistTimelineResponse: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: '#/components/schemas/Security_Timeline_API_TimelineResponse' + required: + - timeline + required: + - persistTimeline + required: + - data Security_Timeline_API_PinnedEvent: allOf: - $ref: '#/components/schemas/Security_Timeline_API_BarePinnedEvent' diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index c205f94528896..701b11df4285e 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -20465,23 +20465,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -20543,23 +20528,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates the Timeline was successfully created. '405': content: @@ -20600,23 +20570,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates that the timeline has been successfully copied. summary: Copies timeline or timeline template. tags: @@ -20640,23 +20595,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates that the draft Timeline was successfully retrieved. '403': content: @@ -20718,23 +20658,8 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - type: object - properties: - persistTimeline: - type: object - properties: - timeline: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - required: - - timeline - required: - - persistTimeline - required: - - data + $ref: >- + #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: >- Indicates that the draft Timeline was successfully created. In the event the user already has a draft Timeline, the existing draft @@ -21029,14 +20954,13 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - oneOf: - - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Timeline_API_ResolvedTimeline - required: - - data + type: object + properties: + data: + $ref: >- + #/components/schemas/Security_Timeline_API_ResolvedTimeline + required: + - data description: The (template) Timeline has been found '400': description: The request is missing parameters @@ -21103,35 +21027,33 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - oneOf: - - type: object - properties: - customTemplateTimelineCount: - type: number - defaultTimelineCount: - type: number - elasticTemplateTimelineCount: - type: number - favoriteCount: - type: number - templateTimelineCount: - type: number - timeline: - items: - $ref: >- - #/components/schemas/Security_Timeline_API_TimelineResponse - type: array - totalCount: - type: number - required: - - timeline - - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount - - type: object + type: object + properties: + customTemplateTimelineCount: + type: number + defaultTimelineCount: + type: number + elasticTemplateTimelineCount: + type: number + favoriteCount: + type: number + templateTimelineCount: + type: number + timeline: + items: + $ref: >- + #/components/schemas/Security_Timeline_API_TimelineResponse + type: array + totalCount: + type: number + required: + - timeline + - totalCount + - defaultTimelineCount + - templateTimelineCount + - favoriteCount + - elasticTemplateTimelineCount + - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -39434,6 +39356,23 @@ components: #/components/schemas/Security_Timeline_API_PinnedEventBaseResponseBody - nullable: true type: object + Security_Timeline_API_PersistTimelineResponse: + type: object + properties: + data: + type: object + properties: + persistTimeline: + type: object + properties: + timeline: + $ref: '#/components/schemas/Security_Timeline_API_TimelineResponse' + required: + - timeline + required: + - persistTimeline + required: + - data Security_Timeline_API_PinnedEvent: allOf: - $ref: '#/components/schemas/Security_Timeline_API_BarePinnedEvent' From fc7c68b8e6e78a88f8c5913759b4bfa747f566dc Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 17:42:09 +0200 Subject: [PATCH 51/73] move zod parsing and error handling to its own file --- .../common/utils/zod_errors.ts | 29 +++++++++++++++++++ .../public/timelines/containers/api.ts | 26 +++++------------ .../create_timelines_stream_from_ndjson.ts | 23 ++------------- .../server/lib/timeline/utils/common.ts | 9 ------ 4 files changed, 39 insertions(+), 48 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/utils/zod_errors.ts diff --git a/x-pack/plugins/security_solution/common/utils/zod_errors.ts b/x-pack/plugins/security_solution/common/utils/zod_errors.ts new file mode 100644 index 0000000000000..7ef5606a4dcfb --- /dev/null +++ b/x-pack/plugins/security_solution/common/utils/zod_errors.ts @@ -0,0 +1,29 @@ +/* + * 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 { ZodError, ZodType } from '@kbn/zod'; +import { stringifyZodError } from '@kbn/zod-helpers'; +import { type Either, fold, left, right } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; + +type ErrorFactory = (message: string) => Error; + +const throwErrors = (createError: ErrorFactory) => (errors: ZodError) => { + throw createError(stringifyZodError(errors)); +}; + +const parseRuntimeType = + (zodType: ZodType) => + (v: unknown): Either, T> => { + const result = zodType.safeParse(v); + return result.success ? right(result.data) : left(result.error); + }; + +export const parseOrThrowErrorFactory = + (createError: ErrorFactory) => (runtimeType: ZodType) => (inputValue: unknown) => + pipe(parseRuntimeType(runtimeType)(inputValue), fold(throwErrors(createError), identity)); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 1295fe3d92817..6a827c5dc3135 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -5,8 +5,7 @@ * 2.0. */ -import type { ZodError, ZodType } from '@kbn/zod'; -import { type Either, fold, left, right } from 'fp-ts/lib/Either'; +import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { isEmpty } from 'lodash'; @@ -48,6 +47,7 @@ import { import { KibanaServices } from '../../common/lib/kibana'; import { ToasterError } from '../../common/components/toasters'; +import { parseOrThrowErrorFactory } from '../../../common/utils/zod_errors'; import type { ExportDocumentsProps, ImportDataProps, @@ -69,19 +69,7 @@ interface RequestPatchTimeline extends RequestPostTimeline { type RequestPersistTimeline = RequestPostTimeline & Partial>; const createToasterPlainError = (message: string) => new ToasterError([message]); -type ErrorFactory = (message: string) => Error; - -const parseRuntimeType = - (zodType: ZodType) => - (v: unknown): Either, T> => { - const result = zodType.safeParse(v); - return result.success ? right(result.data) : left(result.error); - }; - -const decodeOrThrow = - (runtimeType: ZodType, createError: ErrorFactory = createToasterPlainError) => - (inputValue: unknown) => - pipe(parseRuntimeType(runtimeType)(inputValue), fold(throwErrors(createError), identity)); +const parseOrThrow = parseOrThrowErrorFactory(createToasterPlainError); const decodeTimelineResponse = (respTimeline?: TimelineResponse | TimelineErrorResponse) => pipe( @@ -90,13 +78,13 @@ const decodeTimelineResponse = (respTimeline?: TimelineResponse | TimelineErrorR ); const decodeSingleTimelineResponse = (respTimeline?: SingleTimelineResponse) => - decodeOrThrow(GetTimelineResponse)(respTimeline); + parseOrThrow(GetTimelineResponse)(respTimeline); const decodeResolvedSingleTimelineResponse = (respTimeline?: ResolveTimelineResponse) => - decodeOrThrow(ResolveTimelineResponse)(respTimeline); + parseOrThrow(ResolveTimelineResponse)(respTimeline); const decodeGetTimelinesResponse = (respTimeline: GetTimelinesResponse) => - decodeOrThrow(GetTimelinesResponse)(respTimeline); + parseOrThrow(GetTimelinesResponse)(respTimeline); const decodeTimelineErrorResponse = (respTimeline?: TimelineErrorResponse) => pipe( @@ -111,7 +99,7 @@ const decodePrepackedTimelineResponse = (respTimeline?: ImportTimelineResultSche ); const decodeResponseFavoriteTimeline = (respTimeline?: PersistFavoriteRouteResponse) => - decodeOrThrow(PersistFavoriteRouteResponse)(respTimeline); + parseOrThrow(PersistFavoriteRouteResponse)(respTimeline); const postTimeline = async ({ timeline, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts index d5c6c2fa947ec..6eb6ea6e7f376 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts @@ -5,11 +5,7 @@ * 2.0. */ -import type { ZodError, ZodType } from '@kbn/zod'; import type { Transform } from 'stream'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { type Either, fold, left, right } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; import { createConcatStream, createSplitStream, createMapStream } from '@kbn/utils'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; import { @@ -20,27 +16,14 @@ import { import type { ImportTimelineResponse } from './types'; import { ImportTimelines } from '../../../../../../common/api/timeline'; -import { throwErrors } from '../../../utils/common'; - -type ErrorFactory = (message: string) => Error; +import { parseOrThrowErrorFactory } from '../../../../../../common/utils/zod_errors'; const createPlainError = (message: string) => new Error(message); - -const parseRuntimeType = - (zodType: ZodType) => - (v: unknown): Either, T> => { - const result = zodType.safeParse(v); - return result.success ? right(result.data) : left(result.error); - }; - -const decodeOrThrow = - (runtimeType: ZodType, createError: ErrorFactory = createPlainError) => - (inputValue: unknown) => - pipe(parseRuntimeType(runtimeType)(inputValue), fold(throwErrors(createError), identity)); +const parseOrThrow = parseOrThrowErrorFactory(createPlainError); const validateTimelines = (): Transform => createMapStream((obj: ImportTimelineResponse) => - obj instanceof Error ? new BadRequestError(obj.message) : decodeOrThrow(ImportTimelines)(obj) + obj instanceof Error ? new BadRequestError(obj.message) : parseOrThrow(ImportTimelines)(obj) ); export const createTimelinesStreamFromNdJson = (ruleLimit: number) => { return [ diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts index 2c0ed9d70af9d..259719a18bdf0 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts @@ -5,9 +5,6 @@ * 2.0. */ -import type { ZodError } from '@kbn/zod'; -import { stringifyZodError } from '@kbn/zod-helpers'; - import { set } from '@kbn/safer-lodash-set/fp'; import readline from 'readline'; import fs from 'fs'; @@ -40,12 +37,6 @@ export const buildFrameworkRequest = async ( export const escapeHatch = schema.object({}, { unknowns: 'allow' }); -type ErrorFactory = (message: string) => Error; - -export const throwErrors = (createError: ErrorFactory) => (errors: ZodError) => { - throw createError(stringifyZodError(errors)); -}; - export const getReadables = (dataPath: string): Promise => new Promise((resolved, reject) => { const contents: string[] = []; From 19368d90e8f646a73d1046ee840693e606c17731 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 19:37:46 +0200 Subject: [PATCH 52/73] migrate more types --- .../common/api/timeline/model/api.ts | 2 + .../common/api/timeline/routes.ts | 5 +- .../public/timelines/containers/api.ts | 58 ++++++++++--------- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 9150b0b3496ba..5c17009fbe038 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -23,6 +23,7 @@ import { ImportTimelines, type Note, PinnedEvent, + PersistTimelineResponse, ResolvedTimeline, RowRendererId, RowRendererIdEnum, @@ -48,6 +49,7 @@ export { ImportTimelines, Note, PinnedEvent, + PersistTimelineResponse, ResolvedTimeline, RowRendererId, RowRendererIdEnum, diff --git a/x-pack/plugins/security_solution/common/api/timeline/routes.ts b/x-pack/plugins/security_solution/common/api/timeline/routes.ts index a27c42b865f42..70b339c92f197 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/routes.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/routes.ts @@ -17,7 +17,10 @@ export { } from './persist_note/persist_note_route.gen'; export { DeleteNoteRequestBody, DeleteNoteResponse } from './delete_note/delete_note_route.gen'; -export { CleanDraftTimelinesRequestBody } from './clean_draft_timelines/clean_draft_timelines_route.gen'; +export { + CleanDraftTimelinesResponse, + CleanDraftTimelinesRequestBody, +} from './clean_draft_timelines/clean_draft_timelines_route.gen'; export { ExportTimelinesRequestQuery, diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 6a827c5dc3135..c9d1bf19f1ad3 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -13,17 +13,19 @@ import { isEmpty } from 'lodash'; import { throwErrors } from '@kbn/cases-plugin/common'; import type { SavedSearch } from '@kbn/saved-search-plugin/common'; +import type { CleanDraftTimelinesResponse } from '../../../common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.gen'; import type { - TimelineResponse, TimelineErrorResponse, ImportTimelineResultSchema, SingleTimelineResponse, GetAllTimelineVariables, TimelineType, PatchTimelineResponse, + CreateTimelinesResponse, + CopyTimelineResponse, + GetDraftTimelinesResponse, } from '../../../common/api/timeline'; import { - TimelineResponseType, TimelineStatusEnum, TimelineErrorResponseType, importTimelineResultSchema, @@ -32,6 +34,7 @@ import { GetTimelineResponse, ResolveTimelineResponse, GetTimelinesResponse, + PersistTimelineResponse, } from '../../../common/api/timeline'; import { TIMELINE_URL, @@ -71,13 +74,10 @@ const createToasterPlainError = (message: string) => new ToasterError([message]) const parseOrThrow = parseOrThrowErrorFactory(createToasterPlainError); -const decodeTimelineResponse = (respTimeline?: TimelineResponse | TimelineErrorResponse) => - pipe( - TimelineResponseType.decode(respTimeline), - fold(throwErrors(createToasterPlainError), identity) - ); +const decodeTimelineResponse = (respTimeline?: PersistTimelineResponse | TimelineErrorResponse) => + parseOrThrow(PersistTimelineResponse)(respTimeline); -const decodeSingleTimelineResponse = (respTimeline?: SingleTimelineResponse) => +const decodeSingleTimelineResponse = (respTimeline?: GetTimelineResponse) => parseOrThrow(GetTimelineResponse)(respTimeline); const decodeResolvedSingleTimelineResponse = (respTimeline?: ResolveTimelineResponse) => @@ -103,7 +103,7 @@ const decodeResponseFavoriteTimeline = (respTimeline?: PersistFavoriteRouteRespo const postTimeline = async ({ timeline, -}: RequestPostTimeline): Promise => { +}: RequestPostTimeline): Promise => { let requestBody; try { requestBody = JSON.stringify({ timeline }); @@ -111,7 +111,7 @@ const postTimeline = async ({ return Promise.reject(new Error(`Failed to stringify query: ${JSON.stringify(err)}`)); } - const response = await KibanaServices.get().http.post(TIMELINE_URL, { + const response = await KibanaServices.get().http.post(TIMELINE_URL, { method: 'POST', body: requestBody, version: '2023-10-31', @@ -169,7 +169,7 @@ export const copyTimeline = async ({ timelineId, timeline, savedSearch, -}: RequestPersistTimeline): Promise => { +}: RequestPersistTimeline): Promise => { let response = null; let requestBody = null; let newSavedSearchId = null; @@ -199,7 +199,7 @@ export const copyTimeline = async ({ } try { - response = await KibanaServices.get().http.post(TIMELINE_COPY_URL, { + response = await KibanaServices.get().http.post(TIMELINE_COPY_URL, { method: 'POST', body: requestBody, version: '1', @@ -218,10 +218,10 @@ export const persistTimeline = async ({ timeline, version, savedSearch, -}: RequestPersistTimeline): Promise => { +}: RequestPersistTimeline): Promise => { try { if (isEmpty(timelineId) && timeline.status === TimelineStatusEnum.draft && timeline) { - const temp: TimelineResponse | TimelineErrorResponse = await cleanDraftTimeline({ + const temp: CleanDraftTimelinesResponse | TimelineErrorResponse = await cleanDraftTimeline({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion timelineType: timeline.timelineType!, templateTimelineId: timeline.templateTimelineId ?? undefined, @@ -324,13 +324,16 @@ export const getDraftTimeline = async ({ timelineType, }: { timelineType: TimelineType; -}): Promise => { - const response = await KibanaServices.get().http.get(TIMELINE_DRAFT_URL, { - query: { - timelineType, - }, - version: '2023-10-31', - }); +}): Promise => { + const response = await KibanaServices.get().http.get( + TIMELINE_DRAFT_URL, + { + query: { + timelineType, + }, + version: '2023-10-31', + } + ); return decodeTimelineResponse(response); }; @@ -343,7 +346,7 @@ export const cleanDraftTimeline = async ({ timelineType: TimelineType; templateTimelineId?: string; templateTimelineVersion?: number; -}): Promise => { +}): Promise => { let requestBody; const templateTimelineInfo = timelineType === TimelineTypeEnum.template @@ -360,10 +363,13 @@ export const cleanDraftTimeline = async ({ } catch (err) { return Promise.reject(new Error(`Failed to stringify query: ${JSON.stringify(err)}`)); } - const response = await KibanaServices.get().http.post(TIMELINE_DRAFT_URL, { - body: requestBody, - version: '2023-10-31', - }); + const response = await KibanaServices.get().http.post( + TIMELINE_DRAFT_URL, + { + body: requestBody, + version: '2023-10-31', + } + ); return decodeTimelineResponse(response); }; From aabe71c6e4a94ea82419b50716dd020d527d7bd6 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Wed, 25 Sep 2024 21:28:25 +0200 Subject: [PATCH 53/73] clean up more types --- .../output/kibana.serverless.staging.yaml | 16 ++--- oas_docs/output/kibana.staging.yaml | 16 ++--- .../common/api/timeline/model/api.ts | 60 +------------------ .../resolve_timeline_route.gen.ts | 9 ++- .../resolve_timeline_route.schema.yaml | 12 ++-- ...imeline_api_2023_10_31.bundled.schema.yaml | 14 +++-- ...imeline_api_2023_10_31.bundled.schema.yaml | 14 +++-- .../public/timelines/containers/api.ts | 29 +++++---- .../store/middlewares/timeline_save.test.ts | 2 +- .../store/middlewares/timeline_save.ts | 15 ++--- .../logic/perform_timelines_installation.ts | 10 ++-- .../helpers.test.ts | 6 +- .../install_prepackaged_timelines/helpers.ts | 6 +- .../timelines/import_timelines/helpers.ts | 20 +++---- 14 files changed, 90 insertions(+), 139 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 8d2b28343c092..fc5d2a4e629f8 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16865,13 +16865,15 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Timeline_API_ResolvedTimeline - required: - - data + oneOf: + - type: object + properties: + data: + $ref: >- + #/components/schemas/Security_Timeline_API_ResolvedTimeline + required: + - data + - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 701b11df4285e..46851940678ed 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -20954,13 +20954,15 @@ paths: content: application/json; Elastic-Api-Version=2023-10-31: schema: - type: object - properties: - data: - $ref: >- - #/components/schemas/Security_Timeline_API_ResolvedTimeline - required: - - data + oneOf: + - type: object + properties: + data: + $ref: >- + #/components/schemas/Security_Timeline_API_ResolvedTimeline + required: + - data + - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 5c17009fbe038..cd83969f16f65 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -6,13 +6,11 @@ */ import * as runtimeTypes from 'io-ts'; -import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; import { stringEnum, unionWithNullType } from '../../../utility_types'; import type { Maybe } from '../../../search_strategy'; import { PinnedEventRuntimeType } from '../pinned_events/pinned_events_route'; -import { ErrorSchema } from './error_schema'; import type { DataProviderType } from './components.gen'; import { BareNote, @@ -20,6 +18,7 @@ import { DataProviderTypeEnum, FavoriteTimelineResponse, type FavoriteTimelineResult, + ImportTimelineResult, ImportTimelines, type Note, PinnedEvent, @@ -46,6 +45,7 @@ export { DataProviderType, DataProviderTypeEnum, FavoriteTimelineResponse, + ImportTimelineResult, ImportTimelines, Note, PinnedEvent, @@ -354,14 +354,6 @@ export type TimelineSavedObject = runtimeTypes.TypeOf< typeof TimelineSavedToReturnObjectRuntimeType >; -export const SingleTimelineResponseType = runtimeTypes.type({ - data: runtimeTypes.type({ - getOneTimeline: TimelineSavedToReturnObjectRuntimeType, - }), -}); - -export type SingleTimelineResponse = runtimeTypes.TypeOf; - const responseTimelines = runtimeTypes.type({ timeline: runtimeTypes.array(TimelineSavedToReturnObjectRuntimeType), totalCount: runtimeTypes.number, @@ -369,36 +361,6 @@ const responseTimelines = runtimeTypes.type({ export type ResponseTimelines = runtimeTypes.TypeOf; -export const allTimelinesResponse = runtimeTypes.intersection([ - responseTimelines, - runtimeTypes.type({ - defaultTimelineCount: runtimeTypes.number, - templateTimelineCount: runtimeTypes.number, - elasticTemplateTimelineCount: runtimeTypes.number, - customTemplateTimelineCount: runtimeTypes.number, - favoriteCount: runtimeTypes.number, - }), -]); - -export type AllTimelinesResponse = runtimeTypes.TypeOf; - -/** - * All Timeline Saved object type with metadata - */ -export const TimelineResponseType = runtimeTypes.type({ - data: runtimeTypes.type({ - persistTimeline: runtimeTypes.intersection([ - runtimeTypes.partial({ - code: unionWithNullType(runtimeTypes.number), - message: unionWithNullType(runtimeTypes.string), - }), - runtimeTypes.type({ - timeline: TimelineSavedToReturnObjectRuntimeType, - }), - ]), - }), -}); - export const TimelineErrorResponseType = runtimeTypes.union([ runtimeTypes.type({ status_code: runtimeTypes.number, @@ -411,7 +373,6 @@ export const TimelineErrorResponseType = runtimeTypes.union([ ]); export type TimelineErrorResponse = runtimeTypes.TypeOf; -export type TimelineResponse = runtimeTypes.TypeOf; /** * Import/export timelines @@ -435,23 +396,6 @@ export interface ExportTimelineNotFoundError { message: string; } -export const importTimelineResultSchema = runtimeTypes.exact( - runtimeTypes.type({ - success: runtimeTypes.boolean, - success_count: PositiveInteger, - timelines_installed: PositiveInteger, - timelines_updated: PositiveInteger, - errors: runtimeTypes.array(ErrorSchema), - }) -); - -export type ImportTimelineResultSchema = runtimeTypes.TypeOf; - -export const pageInfoTimeline = runtimeTypes.type({ - pageIndex: runtimeTypes.number, - pageSize: runtimeTypes.number, -}); - export interface PageInfoTimeline { pageIndex: number; pageSize: number; diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts index 452e80a7470af..28f46f193ce74 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts @@ -32,6 +32,9 @@ export const ResolveTimelineRequestQuery = z.object({ export type ResolveTimelineRequestQueryInput = z.input; export type ResolveTimelineResponse = z.infer; -export const ResolveTimelineResponse = z.object({ - data: ResolvedTimeline, -}); +export const ResolveTimelineResponse = z.union([ + z.object({ + data: ResolvedTimeline, + }), + z.object({}), +]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml index 515528949b297..c4e3dcaae0887 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml @@ -35,11 +35,13 @@ paths: content: application/json: schema: - type: object - required: [data] - properties: - data: - $ref: '../model/components.schema.yaml#/components/schemas/ResolvedTimeline' + oneOf: + - type: object + required: [data] + properties: + data: + $ref: '../model/components.schema.yaml#/components/schemas/ResolvedTimeline' + - type: object '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 381a932ff6f6b..40fd9869d88e2 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -797,12 +797,14 @@ paths: content: application/json: schema: - type: object - properties: - data: - $ref: '#/components/schemas/ResolvedTimeline' - required: - - data + oneOf: + - type: object + properties: + data: + $ref: '#/components/schemas/ResolvedTimeline' + required: + - data + - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index d8bef08c98477..f4a7a13a41775 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -797,12 +797,14 @@ paths: content: application/json: schema: - type: object - properties: - data: - $ref: '#/components/schemas/ResolvedTimeline' - required: - - data + oneOf: + - type: object + properties: + data: + $ref: '#/components/schemas/ResolvedTimeline' + required: + - data + - type: object description: The (template) Timeline has been found '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index c9d1bf19f1ad3..b5f6d525e46fa 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -13,11 +13,9 @@ import { isEmpty } from 'lodash'; import { throwErrors } from '@kbn/cases-plugin/common'; import type { SavedSearch } from '@kbn/saved-search-plugin/common'; -import type { CleanDraftTimelinesResponse } from '../../../common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.gen'; import type { - TimelineErrorResponse, - ImportTimelineResultSchema, - SingleTimelineResponse, + CleanDraftTimelinesResponse, + TimelineErrorResponse, // todo GetAllTimelineVariables, TimelineType, PatchTimelineResponse, @@ -26,9 +24,9 @@ import type { GetDraftTimelinesResponse, } from '../../../common/api/timeline'; import { + ImportTimelineResult, TimelineStatusEnum, - TimelineErrorResponseType, - importTimelineResultSchema, + TimelineErrorResponseType, // todo PersistFavoriteRouteResponse, TimelineTypeEnum, GetTimelineResponse, @@ -76,6 +74,10 @@ const parseOrThrow = parseOrThrowErrorFactory(createToasterPlainError); const decodeTimelineResponse = (respTimeline?: PersistTimelineResponse | TimelineErrorResponse) => parseOrThrow(PersistTimelineResponse)(respTimeline); +// - migrate over all decode functions +// - make that where theyre used, the correct new types are used and none of the legacy types +// - Check what can be done about TimelineErrorResponse +// - check in timeline/api.ts if more types can be removed const decodeSingleTimelineResponse = (respTimeline?: GetTimelineResponse) => parseOrThrow(GetTimelineResponse)(respTimeline); @@ -92,11 +94,8 @@ const decodeTimelineErrorResponse = (respTimeline?: TimelineErrorResponse) => fold(throwErrors(createToasterPlainError), identity) ); -const decodePrepackedTimelineResponse = (respTimeline?: ImportTimelineResultSchema) => - pipe( - importTimelineResultSchema.decode(respTimeline), - fold(throwErrors(createToasterPlainError), identity) - ); +const decodePrepackedTimelineResponse = (respTimeline?: ImportTimelineResult) => + parseOrThrow(ImportTimelineResult)(respTimeline); const decodeResponseFavoriteTimeline = (respTimeline?: PersistFavoriteRouteResponse) => parseOrThrow(PersistFavoriteRouteResponse)(respTimeline); @@ -374,8 +373,8 @@ export const cleanDraftTimeline = async ({ return decodeTimelineResponse(response); }; -export const installPrepackedTimelines = async (): Promise => { - const response = await KibanaServices.get().http.post( +export const installPrepackedTimelines = async (): Promise => { + const response = await KibanaServices.get().http.post( TIMELINE_PREPACKAGED_URL, { version: '2023-10-31', @@ -386,7 +385,7 @@ export const installPrepackedTimelines = async (): Promise { - const response = await KibanaServices.get().http.get(TIMELINE_URL, { + const response = await KibanaServices.get().http.get(TIMELINE_URL, { query: { id, }, @@ -411,7 +410,7 @@ export const resolveTimeline = async (id: string) => { }; export const getTimelineTemplate = async (templateTimelineId: string) => { - const response = await KibanaServices.get().http.get(TIMELINE_URL, { + const response = await KibanaServices.get().http.get(TIMELINE_URL, { query: { template_timeline_id: templateTimelineId, }, diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts index 6051c9c1bb4e5..7aa7770d560c3 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts @@ -167,7 +167,7 @@ describe('Timeline save middleware', () => { }); it('should show an error message when the call is unauthorized', async () => { - (persistTimeline as jest.Mock).mockResolvedValue({ data: { persistTimeline: { code: 403 } } }); + (persistTimeline as jest.Mock).mockResolvedValue({ status_code: 403 }); await store.dispatch(saveTimeline({ id: TimelineId.test, saveAsNew: false })); expect(refreshTimelines as unknown as jest.Mock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts index dcbbc5cadb6d0..32ec25396c19a 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts @@ -34,7 +34,10 @@ import { selectTimelineById } from '../selectors'; import * as i18n from '../../pages/translations'; import type { inputsModel } from '../../../common/store/inputs'; import { TimelineStatusEnum, TimelineTypeEnum } from '../../../../common/api/timeline'; -import type { TimelineErrorResponse, TimelineResponse } from '../../../../common/api/timeline'; +import type { + TimelineErrorResponse, + PersistTimelineResponse, +} from '../../../../common/api/timeline'; import type { TimelineInput } from '../../../../common/search_strategy'; import type { TimelineModel } from '../model'; import type { ColumnHeaderOptions } from '../../../../common/types/timeline'; @@ -83,6 +86,9 @@ export const saveTimelineMiddleware: (kibana: CoreStart) => Middleware<{}, State if (isTimelineErrorResponse(result)) { const error = getErrorFromResponse(result); switch (error?.errorCode) { + case 403: + store.dispatch(showCallOutUnauthorizedMsg()); + break; // conflict case 409: kibana.notifications.toasts.addDanger({ @@ -108,11 +114,6 @@ export const saveTimelineMiddleware: (kibana: CoreStart) => Middleware<{}, State return; } - if (response && response.code === 403) { - store.dispatch(showCallOutUnauthorizedMsg()); - return; - } - refreshTimelines(store.getState()); store.dispatch( @@ -270,7 +271,7 @@ const convertToString = (obj: unknown) => { } }; -type PossibleResponse = TimelineResponse | TimelineErrorResponse; +type PossibleResponse = PersistTimelineResponse | TimelineErrorResponse; function isTimelineErrorResponse(response: PossibleResponse): response is TimelineErrorResponse { return response && ('status_code' in response || 'statusCode' in response); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/perform_timelines_installation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/perform_timelines_installation.ts index 101883e8ccd9b..857c7a6b95814 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/perform_timelines_installation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/perform_timelines_installation.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; -import { importTimelineResultSchema } from '../../../../../common/api/timeline'; +import { stringifyZodError } from '@kbn/zod-helpers'; +import { ImportTimelineResult } from '../../../../../common/api/timeline'; import type { SecuritySolutionApiRequestHandlerContext } from '../../../../types'; import { installPrepackagedTimelines } from '../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines'; @@ -18,10 +18,10 @@ export const performTimelinesInstallation = async ( securitySolutionContext.getFrameworkRequest(), true ); - const [result, error] = validate(timeline, importTimelineResultSchema); + const parsed = ImportTimelineResult.safeParse(timeline); return { - result, - error, + result: parsed.data, + error: parsed.error && stringifyZodError(parsed.error), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts index 7a4e7a41a1ee7..6b8124f16aa91 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.test.ts @@ -20,7 +20,6 @@ import { import * as helpers from './helpers'; import { importTimelines } from '../../timelines/import_timelines/helpers'; import { buildFrameworkRequest } from '../../../utils/common'; -import type { ImportTimelineResultSchema } from '../../../../../../common/api/timeline'; jest.mock('../../timelines/import_timelines/helpers'); @@ -231,9 +230,8 @@ describe('installPrepackagedTimelines', () => { ); expect( - (result as ImportTimelineResultSchema).errors[0].error.message.includes( - 'read prepackaged timelines error:' - ) + 'errors' in result && + result.errors?.[0].error?.message?.includes('read prepackaged timelines error:') ).toBeTruthy(); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts index dee31d479e2da..f6f43435e5641 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines/helpers.ts @@ -8,7 +8,7 @@ import path, { join, resolve } from 'path'; import { Readable } from 'stream'; -import type { ImportTimelineResultSchema } from '../../../../../../common/api/timeline'; +import type { ImportTimelineResult } from '../../../../../../common/api/timeline'; import type { FrameworkRequest } from '../../../../framework'; @@ -22,7 +22,7 @@ export const installPrepackagedTimelines = async ( isImmutable: boolean, filePath?: string, fileName?: string -): Promise => { +): Promise => { let readStream; const dir = resolve( join( @@ -47,7 +47,7 @@ export const installPrepackagedTimelines = async ( ], }; } - return loadData(readStream, (docs: T) => + return loadData(readStream, (docs: T) => docs instanceof Readable ? importTimelines(docs, maxTimelineImportExportSize, frameworkRequest, isImmutable) : Promise.reject(new Error(`read prepackaged timelines error`)) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts index 6f7767247396d..5539631c66a67 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/helpers.ts @@ -10,12 +10,8 @@ import type { Readable } from 'stream'; import { v4 as uuidv4 } from 'uuid'; import { createPromiseFromStreams } from '@kbn/utils'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; -import type { ImportTimelineResultSchema } from '../../../../../../common/api/timeline'; -import { - importTimelineResultSchema, - TimelineStatusEnum, -} from '../../../../../../common/api/timeline'; +import { stringifyZodError } from '@kbn/zod-helpers'; +import { ImportTimelineResult, TimelineStatusEnum } from '../../../../../../common/api/timeline'; import type { BulkError } from '../../../../detection_engine/routes/utils'; import { createBulkErrorObject } from '../../../../detection_engine/routes/utils'; @@ -88,7 +84,7 @@ export const importTimelines = async ( maxTimelineImportExportSize: number, frameworkRequest: FrameworkRequest, isImmutable?: boolean -): Promise => { +): Promise => { const readStream = createTimelinesStreamFromNdJson(maxTimelineImportExportSize); const parsedObjects = await createPromiseFromStreams([file, ...readStream]); @@ -262,17 +258,17 @@ export const importTimelines = async ( const timelinesUpdated = importTimelineResponse.filter( (resp) => isImportRegular(resp) && resp.action === 'updateViaImport' ); - const importTimelinesRes: ImportTimelineResultSchema = { + const importTimelinesRes: ImportTimelineResult = { success: errorsResp.length === 0, success_count: successes.length, errors: errorsResp, timelines_installed: timelinesInstalled.length ?? 0, timelines_updated: timelinesUpdated.length ?? 0, }; - const [validated, errors] = validate(importTimelinesRes, importTimelineResultSchema); - if (errors != null || validated == null) { - return new Error(errors || 'Import timeline error'); + const parseResult = ImportTimelineResult.safeParse(importTimelinesRes); + if (parseResult.success && parseResult.data) { + return parseResult.data; } else { - return validated; + return new Error(stringifyZodError(parseResult.error) || 'Import timeline error'); } }; From 2e87b8c328c34e6a3382652ec62984b53b56e704 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 08:00:44 +0200 Subject: [PATCH 54/73] fix more types --- .../cypress/objects/timeline.ts | 8 +++++--- .../cypress/tasks/api_calls/timelines.ts | 13 ++++++------ .../services/timeline/index.ts | 20 +++++++++++-------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/objects/timeline.ts b/x-pack/test/security_solution_cypress/cypress/objects/timeline.ts index a5e732c86b65f..1dcaae65a3392 100644 --- a/x-pack/test/security_solution_cypress/cypress/objects/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/objects/timeline.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { TimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; +import type { PersistTimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; export interface Timeline { title: string; @@ -69,7 +69,7 @@ export const getTimelineNonValidQuery = (): CompleteTimeline => ({ }); export const expectedExportedTimelineTemplate = ( - templateResponse: Cypress.Response + templateResponse: Cypress.Response ) => { const timelineTemplateBody = templateResponse.body.data.persistTimeline.timeline; @@ -113,7 +113,9 @@ export const expectedExportedTimelineTemplate = ( }; }; -export const expectedExportedTimeline = (timelineResponse: Cypress.Response) => { +export const expectedExportedTimeline = ( + timelineResponse: Cypress.Response +) => { const timelineBody = timelineResponse.body.data.persistTimeline.timeline; return { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts index 864767d0504f9..055d98a2efcfd 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts @@ -6,8 +6,9 @@ */ import type { - AllTimelinesResponse, - TimelineResponse, + DeleteTimelinesResponse, + GetTimelinesResponse, + PatchTimelineResponse, } from '@kbn/security-solution-plugin/common/api/timeline'; import type { CompleteTimeline } from '../../objects/timeline'; import { getTimeline } from '../../objects/timeline'; @@ -21,7 +22,7 @@ const mockTimeline = getTimeline(); * @returns undefined */ export const createTimeline = (timeline: CompleteTimeline = mockTimeline) => - rootRequest({ + rootRequest({ method: 'POST', url: 'api/timeline', body: { @@ -75,7 +76,7 @@ export const createTimeline = (timeline: CompleteTimeline = mockTimeline) => * @returns undefined */ export const createTimelineTemplate = (timeline: CompleteTimeline = mockTimeline) => - rootRequest({ + rootRequest({ method: 'POST', url: 'api/timeline', body: { @@ -159,7 +160,7 @@ export const favoriteTimeline = ({ }); export const getAllTimelines = () => - rootRequest({ + rootRequest({ method: 'GET', url: 'api/timelines?page_size=100&page_index=1&sort_field=updated&sort_order=desc&timeline_type=default', }); @@ -167,7 +168,7 @@ export const getAllTimelines = () => export const deleteTimelines = () => { getAllTimelines().then(($timelines) => { const savedObjectIds = $timelines.body.timeline.map((timeline) => timeline.savedObjectId); - rootRequest({ + rootRequest({ method: 'DELETE', url: 'api/timeline', body: { diff --git a/x-pack/test/security_solution_ftr/services/timeline/index.ts b/x-pack/test/security_solution_ftr/services/timeline/index.ts index ebf6497567d81..42ceecbbdb683 100644 --- a/x-pack/test/security_solution_ftr/services/timeline/index.ts +++ b/x-pack/test/security_solution_ftr/services/timeline/index.ts @@ -8,7 +8,11 @@ import { Response } from 'superagent'; import { EndpointError } from '@kbn/security-solution-plugin/common/endpoint/errors'; import { TIMELINE_DRAFT_URL, TIMELINE_URL } from '@kbn/security-solution-plugin/common/constants'; -import { TimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; +import { + DeleteTimelinesResponse, + GetDraftTimelinesResponse, + PatchTimelineResponse, +} from '@kbn/security-solution-plugin/common/api/timeline'; import { TimelineInput } from '@kbn/security-solution-plugin/common/search_strategy'; import moment from 'moment'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; @@ -52,7 +56,7 @@ export class TimelineTestService extends FtrService { * for display (not sure why). TO get around this, just select a date range from the user date * picker and that seems to trigger the events to be fetched. */ - async createTimeline(title: string): Promise { + async createTimeline(title: string): Promise { // Create a new timeline draft const createdTimeline = ( await this.supertest @@ -61,7 +65,7 @@ export class TimelineTestService extends FtrService { .set('elastic-api-version', '2023-10-31') .send({ timelineType: 'default' }) .then(this.getHttpResponseFailureHandler()) - .then((response) => response.body as TimelineResponse) + .then((response) => response.body as GetDraftTimelinesResponse) ).data.persistTimeline.timeline; this.log.info('Draft timeline:'); @@ -109,7 +113,7 @@ export class TimelineTestService extends FtrService { timelineId: string, updates: TimelineInput, version: string - ): Promise { + ): Promise { return await this.supertest .patch(TIMELINE_URL) .set('kbn-xsrf', 'true') @@ -120,11 +124,11 @@ export class TimelineTestService extends FtrService { timeline: updates, }) .then(this.getHttpResponseFailureHandler()) - .then((response) => response.body as TimelineResponse); + .then((response) => response.body as PatchTimelineResponse); } /** Deletes a timeline using it timeline id */ - async deleteTimeline(id: string | string[]): Promise { + async deleteTimeline(id: string | string[]) { await this.supertest .delete(TIMELINE_URL) .set('kbn-xsrf', 'true') @@ -133,7 +137,7 @@ export class TimelineTestService extends FtrService { savedObjectIds: Array.isArray(id) ? id : [id], }) .then(this.getHttpResponseFailureHandler()) - .then((response) => response.body as TimelineResponse); + .then((response) => response.body as DeleteTimelinesResponse); } /** @@ -173,7 +177,7 @@ export class TimelineTestService extends FtrService { /** If defined, then only alerts from the specific `agent.id` will be displayed */ endpointAgentId: string; }> - ): Promise { + ): Promise { const newTimeline = await this.createTimeline(title); const { expression, esQuery } = this.getEndpointAlertsKqlQuery(endpointAgentId); From eeb83e46ffee0169e3eb5d7a23ba252e753f3f59 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 08:55:37 +0200 Subject: [PATCH 55/73] remove GetAllTimelineVariables --- .../public/timelines/containers/all/index.tsx | 14 ++++++++------ .../public/timelines/containers/api.ts | 18 ++++++------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx index 7a2b3eca0f74b..1f6ef7df66961 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx @@ -23,7 +23,7 @@ import type { PageInfoTimeline, TimelineResult, SortTimeline, - GetAllTimelineVariables, + GetTimelinesRequestQuery, } from '../../../../common/api/timeline'; import { TimelineTypeEnum } from '../../../../common/api/timeline'; import { getAllTimelines } from '../api'; @@ -132,13 +132,15 @@ export const useGetAllTimeline = (): AllTimelinesArgs => { loading: true, })); - const variables: GetAllTimelineVariables = { - onlyUserFavorite, - pageInfo, + const variables: GetTimelinesRequestQuery = { + only_user_favorite: onlyUserFavorite ? 'true' : 'false', + page_size: pageInfo.pageSize.toString(), + page_index: pageInfo.pageIndex.toString(), search, - sort, + sort_field: sort.sortField, + sort_order: sort.sortOrder, status, - timelineType, + timeline_type: timelineType, }; const getAllTimelineResponse = await getAllTimelines(variables, abortCtrl.signal); const totalCount = getAllTimelineResponse?.totalCount ?? 0; diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index b5f6d525e46fa..186cebcb6331d 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -16,12 +16,12 @@ import type { SavedSearch } from '@kbn/saved-search-plugin/common'; import type { CleanDraftTimelinesResponse, TimelineErrorResponse, // todo - GetAllTimelineVariables, TimelineType, PatchTimelineResponse, CreateTimelinesResponse, CopyTimelineResponse, GetDraftTimelinesResponse, + GetTimelinesRequestQuery, } from '../../../common/api/timeline'; import { ImportTimelineResult, @@ -420,19 +420,13 @@ export const getTimelineTemplate = async (templateTimelineId: string) => { return decodeSingleTimelineResponse(response); }; -export const getAllTimelines = async (args: GetAllTimelineVariables, abortSignal: AbortSignal) => { +export const getAllTimelines = async ( + query: GetTimelinesRequestQuery, + abortSignal: AbortSignal +) => { const response = await KibanaServices.get().http.fetch(TIMELINES_URL, { method: 'GET', - query: { - ...(args.onlyUserFavorite ? { only_user_favorite: args.onlyUserFavorite } : {}), - ...(args?.pageInfo?.pageSize ? { page_size: args.pageInfo.pageSize } : {}), - ...(args?.pageInfo?.pageIndex ? { page_index: args.pageInfo.pageIndex } : {}), - ...(args.search ? { search: args.search } : {}), - ...(args?.sort?.sortField ? { sort_field: args?.sort?.sortField } : {}), - ...(args?.sort?.sortOrder ? { sort_order: args?.sort?.sortOrder } : {}), - ...(args.status ? { status: args.status } : {}), - ...(args.timelineType ? { timeline_type: args.timelineType } : {}), - }, + query, signal: abortSignal, version: '2023-10-31', }); From 5c46bfd8a684c4890411ff53885bde08ae30eb5c Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 10:00:17 +0200 Subject: [PATCH 56/73] TimelineResponse -> PatchTimelineResponse --- .../apps/endpoint/endpoint_solution_integrations.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_solution_integrations.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_solution_integrations.ts index 16fb1bb48808a..580b96bfd2340 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_solution_integrations.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_solution_integrations.ts @@ -6,7 +6,7 @@ */ import { IndexedHostsAndAlertsResponse } from '@kbn/security-solution-plugin/common/endpoint/index_data'; -import { TimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; +import { PatchTimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; // @ts-expect-error we have to check types with "allowJs: false" for now, causing this import to fail import { kibanaPackageJson } from '@kbn/repo-info'; import { type IndexedEndpointRuleAlerts } from '@kbn/security-solution-plugin/common/endpoint/data_loaders/index_endpoint_rule_alerts'; @@ -64,7 +64,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // failing tests: https://github.com/elastic/kibana/issues/170705 describe.skip('from Timeline', () => { - let timeline: TimelineResponse; + let timeline: PatchTimelineResponse; before(async () => { log.info( From c9851b3a478b4af1e2c9ae0b944d6ae3b3039382 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 10:31:34 +0200 Subject: [PATCH 57/73] fix fetching all timelines --- .../security_solution/public/timelines/containers/all/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx index 1f6ef7df66961..48d4aa698a324 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx @@ -139,7 +139,7 @@ export const useGetAllTimeline = (): AllTimelinesArgs => { search, sort_field: sort.sortField, sort_order: sort.sortOrder, - status, + status: status || undefined, timeline_type: timelineType, }; const getAllTimelineResponse = await getAllTimelines(variables, abortCtrl.signal); From e4e4e7c6766048fa9c04271d5b737e386dcbadaf Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 14:17:05 +0200 Subject: [PATCH 58/73] Migrate more types --- .../output/kibana.serverless.staging.yaml | 31 +++++--- oas_docs/output/kibana.staging.yaml | 31 +++++--- .../get_timelines/get_timelines_route.gen.ts | 10 +-- .../get_timelines_route.schema.yaml | 5 -- .../common/api/timeline/model/api.ts | 45 ++--------- .../api/timeline/model/components.gen.ts | 34 ++++++-- .../api/timeline/model/components.schema.yaml | 38 +++++++-- ...imeline_api_2023_10_31.bundled.schema.yaml | 30 ++++--- ...imeline_api_2023_10_31.bundled.schema.yaml | 30 ++++--- .../public/timelines/containers/api.ts | 12 +-- .../timeline/saved_object/timelines/index.ts | 79 ++++++++++--------- .../timelines/pick_saved_timeline.ts | 6 +- 12 files changed, 189 insertions(+), 162 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index fc5d2a4e629f8..326d38b61519e 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16962,11 +16962,6 @@ paths: required: - timeline - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -31598,6 +31593,18 @@ components: updatedBy: nullable: true type: string + Security_Timeline_API_SavedTimelineWithSavedObjectId: + allOf: + - $ref: '#/components/schemas/Security_Timeline_API_SavedTimeline' + - type: object + properties: + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version Security_Timeline_API_SerializedFilterQueryResult: type: object properties: @@ -31647,6 +31654,8 @@ components: Security_Timeline_API_TimelineResponse: allOf: - $ref: '#/components/schemas/Security_Timeline_API_SavedTimeline' + - $ref: >- + #/components/schemas/Security_Timeline_API_SavedTimelineWithSavedObjectId - type: object properties: eventIdToNoteIds: @@ -31674,13 +31683,6 @@ components: $ref: '#/components/schemas/Security_Timeline_API_PinnedEvent' nullable: true type: array - savedObjectId: - type: string - version: - type: string - required: - - savedObjectId - - version Security_Timeline_API_TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/Security_Timeline_API_SavedTimeline' @@ -31689,22 +31691,27 @@ components: eventIdToNoteIds: items: $ref: '#/components/schemas/Security_Timeline_API_Note' + nullable: true type: array noteIds: items: type: string + nullable: true type: array notes: items: $ref: '#/components/schemas/Security_Timeline_API_Note' + nullable: true type: array pinnedEventIds: items: type: string + nullable: true type: array pinnedEventsSaveObject: items: $ref: '#/components/schemas/Security_Timeline_API_PinnedEvent' + nullable: true type: array savedObjectId: type: string diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 46851940678ed..74770826b33ac 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -21051,11 +21051,6 @@ paths: required: - timeline - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -39607,6 +39602,18 @@ components: updatedBy: nullable: true type: string + Security_Timeline_API_SavedTimelineWithSavedObjectId: + allOf: + - $ref: '#/components/schemas/Security_Timeline_API_SavedTimeline' + - type: object + properties: + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version Security_Timeline_API_SerializedFilterQueryResult: type: object properties: @@ -39656,6 +39663,8 @@ components: Security_Timeline_API_TimelineResponse: allOf: - $ref: '#/components/schemas/Security_Timeline_API_SavedTimeline' + - $ref: >- + #/components/schemas/Security_Timeline_API_SavedTimelineWithSavedObjectId - type: object properties: eventIdToNoteIds: @@ -39683,13 +39692,6 @@ components: $ref: '#/components/schemas/Security_Timeline_API_PinnedEvent' nullable: true type: array - savedObjectId: - type: string - version: - type: string - required: - - savedObjectId - - version Security_Timeline_API_TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/Security_Timeline_API_SavedTimeline' @@ -39698,22 +39700,27 @@ components: eventIdToNoteIds: items: $ref: '#/components/schemas/Security_Timeline_API_Note' + nullable: true type: array noteIds: items: type: string + nullable: true type: array notes: items: $ref: '#/components/schemas/Security_Timeline_API_Note' + nullable: true type: array pinnedEventIds: items: type: string + nullable: true type: array pinnedEventsSaveObject: items: $ref: '#/components/schemas/Security_Timeline_API_PinnedEvent' + nullable: true type: array savedObjectId: type: string diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts index e2828beb876c3..714746875599b 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.gen.ts @@ -43,9 +43,9 @@ export type GetTimelinesResponse = z.infer; export const GetTimelinesResponse = z.object({ timeline: z.array(TimelineResponse), totalCount: z.number(), - defaultTimelineCount: z.number(), - templateTimelineCount: z.number(), - favoriteCount: z.number(), - elasticTemplateTimelineCount: z.number(), - customTemplateTimelineCount: z.number(), + defaultTimelineCount: z.number().optional(), + templateTimelineCount: z.number().optional(), + favoriteCount: z.number().optional(), + elasticTemplateTimelineCount: z.number().optional(), + customTemplateTimelineCount: z.number().optional(), }); diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml index 73afeac39bba3..7d83f60af3e02 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml @@ -78,11 +78,6 @@ paths: required: [ timeline, totalCount, - defaultTimelineCount, - templateTimelineCount, - favoriteCount, - elasticTemplateTimelineCount, - customTemplateTimelineCount, ] properties: timeline: diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index cd83969f16f65..7ad3052b7ad6f 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -27,11 +27,14 @@ import { RowRendererId, RowRendererIdEnum, SavedTimeline, + SavedTimelineWithSavedObjectId, SortDirection, SortFieldTimeline, SortFieldTimelineEnum, TemplateTimelineType, TemplateTimelineTypeEnum, + TimelineErrorResponse, + TimelineResponse, TimelineSavedToReturnObject, TimelineStatus, TimelineStatusEnum, @@ -54,10 +57,13 @@ export { RowRendererId, RowRendererIdEnum, SavedTimeline, + SavedTimelineWithSavedObjectId, SortDirection, SortFieldTimeline, SortFieldTimelineEnum, TemplateTimelineType, + TimelineErrorResponse, + TimelineResponse, TemplateTimelineTypeEnum, TimelineSavedToReturnObject, TimelineStatus, @@ -325,16 +331,6 @@ export const SavedTimelineRuntimeType = runtimeTypes.partial({ savedSearchId: unionWithNullType(runtimeTypes.string), }); -export type SavedTimelineWithSavedObjectId = SavedTimeline & { - savedObjectId?: string | null; -}; - -/** - * This type represents a timeline type stored in a saved object that does not include any fields that reference - * other saved objects. - */ -export type TimelineWithoutExternalRefs = Omit; - export const TimelineSavedToReturnObjectRuntimeType = runtimeTypes.intersection([ SavedTimelineRuntimeType, runtimeTypes.type({ @@ -354,26 +350,6 @@ export type TimelineSavedObject = runtimeTypes.TypeOf< typeof TimelineSavedToReturnObjectRuntimeType >; -const responseTimelines = runtimeTypes.type({ - timeline: runtimeTypes.array(TimelineSavedToReturnObjectRuntimeType), - totalCount: runtimeTypes.number, -}); - -export type ResponseTimelines = runtimeTypes.TypeOf; - -export const TimelineErrorResponseType = runtimeTypes.union([ - runtimeTypes.type({ - status_code: runtimeTypes.number, - message: runtimeTypes.string, - }), - runtimeTypes.type({ - statusCode: runtimeTypes.number, - message: runtimeTypes.string, - }), -]); - -export type TimelineErrorResponse = runtimeTypes.TypeOf; - /** * Import/export timelines */ @@ -533,12 +509,3 @@ export interface SortTimeline { sortField: SortFieldTimeline; sortOrder: SortDirection; } - -export interface GetAllTimelineVariables { - pageInfo: PageInfoTimeline; - search?: Maybe; - sort?: Maybe; - onlyUserFavorite?: Maybe; - timelineType?: Maybe; - status?: Maybe; -} diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index 1b1290195afbc..c8d966aad9934 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -215,6 +215,14 @@ export const SavedTimeline = z.object({ updatedBy: z.string().nullable().optional(), }); +export type SavedTimelineWithSavedObjectId = z.infer; +export const SavedTimelineWithSavedObjectId = SavedTimeline.merge( + z.object({ + savedObjectId: z.string(), + version: z.string(), + }) +); + export type BareNote = z.infer; export const BareNote = z.object({ eventId: z.string().nullable().optional(), @@ -253,15 +261,13 @@ export const PinnedEvent = BarePinnedEvent.merge( ); export type TimelineResponse = z.infer; -export const TimelineResponse = SavedTimeline.merge( +export const TimelineResponse = SavedTimeline.merge(SavedTimelineWithSavedObjectId).merge( z.object({ eventIdToNoteIds: z.array(Note).nullable().optional(), notes: z.array(Note).nullable().optional(), noteIds: z.array(z.string()).nullable().optional(), pinnedEventIds: z.array(z.string()).nullable().optional(), pinnedEventsSaveObject: z.array(PinnedEvent).nullable().optional(), - savedObjectId: z.string(), - version: z.string(), }) ); @@ -270,11 +276,11 @@ export const TimelineSavedToReturnObject = SavedTimeline.merge( z.object({ savedObjectId: z.string(), version: z.string(), - eventIdToNoteIds: z.array(Note).optional(), - notes: z.array(Note).optional(), - noteIds: z.array(z.string()).optional(), - pinnedEventIds: z.array(z.string()).optional(), - pinnedEventsSaveObject: z.array(PinnedEvent).optional(), + eventIdToNoteIds: z.array(Note).nullable().optional(), + notes: z.array(Note).nullable().optional(), + noteIds: z.array(z.string()).nullable().optional(), + pinnedEventIds: z.array(z.string()).nullable().optional(), + pinnedEventsSaveObject: z.array(PinnedEvent).nullable().optional(), }) ); @@ -396,6 +402,18 @@ export const ImportTimelineResult = z.object({ .optional(), }); +export type TimelineErrorResponse = z.infer; +export const TimelineErrorResponse = z.union([ + z.object({ + message: z.string(), + status_code: z.number(), + }), + z.object({ + message: z.string(), + statusCode: z.number(), + }), +]); + export type ExportedTimelines = z.infer; export const ExportedTimelines = SavedTimeline.merge( z.object({ diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index eeed806a1dd18..1335062586e06 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -153,11 +153,21 @@ components: updatedBy: type: string nullable: true - TimelineResponse: + SavedTimelineWithSavedObjectId: allOf: - $ref: '#/components/schemas/SavedTimeline' - type: object required: [savedObjectId, version] + properties: + savedObjectId: + type: string + version: + type: string + TimelineResponse: + allOf: + - $ref: '#/components/schemas/SavedTimeline' + - $ref: '#/components/schemas/SavedTimelineWithSavedObjectId' + - type: object properties: eventIdToNoteIds: type: array @@ -184,10 +194,6 @@ components: nullable: true items: $ref: '#/components/schemas/PinnedEvent' - savedObjectId: - type: string - version: - type: string ResolvedTimeline: type: object required: [timeline, outcome] @@ -662,22 +668,27 @@ components: type: string eventIdToNoteIds: type: array + nullable: true items: $ref: '#/components/schemas/Note' notes: type: array + nullable: true items: $ref: '#/components/schemas/Note' noteIds: type: array + nullable: true items: type: string pinnedEventIds: type: array + nullable: true items: type: string pinnedEventsSaveObject: type: array + nullable: true items: $ref: '#/components/schemas/PinnedEvent' ImportTimelineResult: @@ -705,6 +716,23 @@ components: type: string status_code: type: number + TimelineErrorResponse: + oneOf: + - type: object + required: [message, status_code] + properties: + message: + type: string + status_code: + type: number + - type: object + required: [message, statusCode] + properties: + message: + type: string + statusCode: + type: number + ExportedTimelines: allOf: - $ref: '#/components/schemas/SavedTimeline' diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 40fd9869d88e2..b8db839779fb6 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -892,11 +892,6 @@ paths: required: - timeline - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -1499,6 +1494,18 @@ components: updatedBy: nullable: true type: string + SavedTimelineWithSavedObjectId: + allOf: + - $ref: '#/components/schemas/SavedTimeline' + - type: object + properties: + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version SerializedFilterQueryResult: type: object properties: @@ -1548,6 +1555,7 @@ components: TimelineResponse: allOf: - $ref: '#/components/schemas/SavedTimeline' + - $ref: '#/components/schemas/SavedTimelineWithSavedObjectId' - type: object properties: eventIdToNoteIds: @@ -1575,13 +1583,6 @@ components: $ref: '#/components/schemas/PinnedEvent' nullable: true type: array - savedObjectId: - type: string - version: - type: string - required: - - savedObjectId - - version TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/SavedTimeline' @@ -1590,22 +1591,27 @@ components: eventIdToNoteIds: items: $ref: '#/components/schemas/Note' + nullable: true type: array noteIds: items: type: string + nullable: true type: array notes: items: $ref: '#/components/schemas/Note' + nullable: true type: array pinnedEventIds: items: type: string + nullable: true type: array pinnedEventsSaveObject: items: $ref: '#/components/schemas/PinnedEvent' + nullable: true type: array savedObjectId: type: string diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index f4a7a13a41775..f42cab0247072 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -892,11 +892,6 @@ paths: required: - timeline - totalCount - - defaultTimelineCount - - templateTimelineCount - - favoriteCount - - elasticTemplateTimelineCount - - customTemplateTimelineCount description: Indicates that the (template) Timelines were found and returned. '400': content: @@ -1499,6 +1494,18 @@ components: updatedBy: nullable: true type: string + SavedTimelineWithSavedObjectId: + allOf: + - $ref: '#/components/schemas/SavedTimeline' + - type: object + properties: + savedObjectId: + type: string + version: + type: string + required: + - savedObjectId + - version SerializedFilterQueryResult: type: object properties: @@ -1548,6 +1555,7 @@ components: TimelineResponse: allOf: - $ref: '#/components/schemas/SavedTimeline' + - $ref: '#/components/schemas/SavedTimelineWithSavedObjectId' - type: object properties: eventIdToNoteIds: @@ -1575,13 +1583,6 @@ components: $ref: '#/components/schemas/PinnedEvent' nullable: true type: array - savedObjectId: - type: string - version: - type: string - required: - - savedObjectId - - version TimelineSavedToReturnObject: allOf: - $ref: '#/components/schemas/SavedTimeline' @@ -1590,22 +1591,27 @@ components: eventIdToNoteIds: items: $ref: '#/components/schemas/Note' + nullable: true type: array noteIds: items: type: string + nullable: true type: array notes: items: $ref: '#/components/schemas/Note' + nullable: true type: array pinnedEventIds: items: type: string + nullable: true type: array pinnedEventsSaveObject: items: $ref: '#/components/schemas/PinnedEvent' + nullable: true type: array savedObjectId: type: string diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 186cebcb6331d..52befd485471d 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -5,17 +5,12 @@ * 2.0. */ -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; import { isEmpty } from 'lodash'; -import { throwErrors } from '@kbn/cases-plugin/common'; import type { SavedSearch } from '@kbn/saved-search-plugin/common'; import type { CleanDraftTimelinesResponse, - TimelineErrorResponse, // todo TimelineType, PatchTimelineResponse, CreateTimelinesResponse, @@ -25,8 +20,8 @@ import type { } from '../../../common/api/timeline'; import { ImportTimelineResult, + TimelineErrorResponse, TimelineStatusEnum, - TimelineErrorResponseType, // todo PersistFavoriteRouteResponse, TimelineTypeEnum, GetTimelineResponse, @@ -89,10 +84,7 @@ const decodeGetTimelinesResponse = (respTimeline: GetTimelinesResponse) => parseOrThrow(GetTimelinesResponse)(respTimeline); const decodeTimelineErrorResponse = (respTimeline?: TimelineErrorResponse) => - pipe( - TimelineErrorResponseType.decode(respTimeline), - fold(throwErrors(createToasterPlainError), identity) - ); + parseOrThrow(TimelineErrorResponse)(respTimeline); const decodePrepackedTimelineResponse = (respTimeline?: ImportTimelineResult) => parseOrThrow(ImportTimelineResult)(respTimeline); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts index 1ff380319744f..cbde4fb2aaacf 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts @@ -22,17 +22,14 @@ import type { GetTimelinesResponse, ExportTimelineNotFoundError, PageInfoTimeline, - ResponseTimelines, FavoriteTimelineResponse, - ResponseTimeline, SortTimeline, - TimelineResult, + TimelineResponse, TimelineType, TimelineStatus, ResolvedTimeline, - TimelineSavedObject, SavedTimeline, - TimelineWithoutExternalRefs, + SavedTimelineWithSavedObjectId, } from '../../../../../common/api/timeline'; import { TimelineStatusEnum, TimelineTypeEnum } from '../../../../../common/api/timeline'; import type { SavedObjectTimelineWithoutExternalRefs } from '../../../../../common/types/timeline/saved_object'; @@ -49,11 +46,13 @@ import { timelineFieldsMigrator } from './field_migrator'; export { pickSavedTimeline } from './pick_saved_timeline'; export { convertSavedObjectToSavedTimeline } from './convert_saved_object_to_savedtimeline'; +type TimelineWithoutExternalRefs = Omit; + export const getTimeline = async ( request: FrameworkRequest, timelineId: string, timelineType: TimelineType | null = TimelineTypeEnum.default -): Promise => { +): Promise => { let timelineIdToUse = timelineId; try { if (timelineType === TimelineTypeEnum.template) { @@ -77,7 +76,7 @@ export const getTimeline = async ( export const getTimelineOrNull = async ( frameworkRequest: FrameworkRequest, savedObjectId: string -): Promise => { +): Promise => { let timeline = null; try { timeline = await getTimeline(frameworkRequest, savedObjectId); @@ -90,22 +89,18 @@ export const resolveTimelineOrNull = async ( frameworkRequest: FrameworkRequest, savedObjectId: string ): Promise => { - let resolvedTimeline = null; try { - resolvedTimeline = await resolveSavedTimeline(frameworkRequest, savedObjectId); - // eslint-disable-next-line no-empty - } catch (e) {} - return resolvedTimeline; - // } + const resolvedTimeline = await resolveSavedTimeline(frameworkRequest, savedObjectId); + return resolvedTimeline; + } catch (e) { + return null; + } }; export const getTimelineByTemplateTimelineId = async ( request: FrameworkRequest, templateTimelineId: string -): Promise<{ - totalCount: number; - timeline: TimelineSavedObject[]; -}> => { +): Promise => { const options: SavedObjectsFindOptions = { type: timelineSavedObjectType, filter: `siem-ui-timeline.attributes.templateTimelineId: "${templateTimelineId}"`, @@ -117,7 +112,7 @@ export const getTimelineByTemplateTimelineId = async ( export const getTimelineTemplateOrNull = async ( frameworkRequest: FrameworkRequest, templateTimelineId: string -): Promise => { +): Promise => { let templateTimeline = null; try { templateTimeline = await getTimelineByTemplateTimelineId(frameworkRequest, templateTimelineId); @@ -190,10 +185,7 @@ export const getExistingPrepackagedTimelines = async ( request: FrameworkRequest, countsOnly?: boolean, pageInfo?: PageInfoTimeline -): Promise<{ - totalCount: number; - timeline: TimelineSavedObject[]; -}> => { +): Promise => { const queryPageInfo = countsOnly && pageInfo == null ? { @@ -291,7 +283,7 @@ export const getAllTimeline = async ( export const getDraftTimeline = async ( request: FrameworkRequest, timelineType: TimelineType | null -): Promise => { +): Promise => { const filter = combineFilters([ getTimelineTypeFilter(timelineType ?? null, TimelineStatusEnum.draft), getTimelinesCreatedAndUpdatedByCurrentUser({ request }), @@ -385,13 +377,19 @@ export const persistFavorite = async ( } }; +interface InternalTimelineResponse { + code: number; + message: string; + timeline: TimelineResponse; +} + export const persistTimeline = async ( request: FrameworkRequest, timelineId: string | null, version: string | null, timeline: SavedTimeline, isImmutable?: boolean -): Promise => { +): Promise => { const savedObjectsClient = (await request.context.core).savedObjects.client; const userInfo = isImmutable ? ({ username: 'Elastic' } as AuthenticatedUser) : request.user; try { @@ -414,7 +412,7 @@ export const persistTimeline = async ( timeline: await getSavedTimeline(request, timelineId), }; } else if (getOr(null, 'output.statusCode', err) === 403) { - const timelineToReturn: TimelineResult = { + const timelineToReturn: TimelineResponse = { ...timeline, savedObjectId: '', version: '', @@ -439,7 +437,7 @@ export const createTimeline = async ({ timeline: SavedTimeline; savedObjectsClient: SavedObjectsClientContract; userInfo: AuthenticatedUser | null; -}) => { +}): Promise => { const { transformedFields: migratedAttributes, references } = timelineFieldsMigrator.extractFieldsToReferences({ data: pickSavedTimeline(timelineId, timeline, userInfo), @@ -479,7 +477,7 @@ const updateTimeline = async ({ savedObjectsClient: SavedObjectsClientContract; userInfo: AuthenticatedUser | null; version: string | null; -}) => { +}): Promise => { const rawTimelineSavedObject = await savedObjectsClient.get( timelineSavedObjectType, @@ -516,11 +514,12 @@ export const updatePartialSavedTimeline = async ( timelineId ); - const { transformedFields, references } = - timelineFieldsMigrator.extractFieldsToReferences({ - data: timeline, - existingReferences: currentSavedTimeline.references, - }); + const { transformedFields, references } = timelineFieldsMigrator.extractFieldsToReferences< + Omit + >({ + data: timeline, + existingReferences: currentSavedTimeline.references, + }); const timelineUpdateAttributes = pickSavedTimeline( null, @@ -588,7 +587,7 @@ export const copyTimeline = async ( request: FrameworkRequest, timeline: SavedTimeline, timelineId: string -): Promise => { +): Promise => { const savedObjectsClient = (await request.context.core).savedObjects.client; // Fetch all objects that need to be copied @@ -658,7 +657,10 @@ const resolveBasicSavedTimeline = async (request: FrameworkRequest, timelineId: }; }; -const resolveSavedTimeline = async (request: FrameworkRequest, timelineId: string) => { +const resolveSavedTimeline = async ( + request: FrameworkRequest, + timelineId: string +): Promise => { const userName = request.user?.username ?? UNAUTHENTICATED_USER; const { resolvedTimelineSavedObject, ...resolveAttributes } = await resolveBasicSavedTimeline( @@ -673,7 +675,6 @@ const resolveSavedTimeline = async (request: FrameworkRequest, timelineId: strin ]); const [notes, pinnedEvents, timeline] = timelineWithNotesAndPinnedEvents; - return { timeline: timelineWithReduxProperties(notes, pinnedEvents, timeline, userName), ...resolveAttributes, @@ -742,9 +743,9 @@ export const convertStringToBase64 = (text: string): string => Buffer.from(text) export const timelineWithReduxProperties = ( notes: Note[], pinnedEvents: PinnedEvent[], - timeline: TimelineSavedObject, + timeline: TimelineResponse, userName: string -): TimelineSavedObject => ({ +): TimelineResponse => ({ ...timeline, favorite: timeline.favorite != null && userName != null @@ -789,7 +790,7 @@ export const getSelectedTimelines = async ( ); const timelineObjects: { - timelines: TimelineSavedObject[]; + timelines: TimelineResponse[]; errors: ExportTimelineNotFoundError[]; } = savedObjects.saved_objects.reduce( (acc, savedObject) => { @@ -805,7 +806,7 @@ export const getSelectedTimelines = async ( return { errors: [...acc.errors, savedObject.error], timelines: acc.timelines }; }, { - timelines: [] as TimelineSavedObject[], + timelines: [] as TimelineResponse[], errors: [] as ExportTimelineNotFoundError[], } ); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts index 50b57bf96bd5b..221e088bdab02 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts @@ -9,14 +9,14 @@ import { isEmpty } from 'lodash/fp'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { getUserDisplayName } from '@kbn/user-profile-components'; import { UNAUTHENTICATED_USER } from '../../../../../common/constants'; -import type { SavedTimelineWithSavedObjectId } from '../../../../../common/api/timeline'; +import type { SavedTimeline } from '../../../../../common/api/timeline'; import { TimelineTypeEnum, TimelineStatusEnum } from '../../../../../common/api/timeline'; export const pickSavedTimeline = ( timelineId: string | null, - savedTimeline: SavedTimelineWithSavedObjectId, + savedTimeline: SavedTimeline, userInfo: AuthenticatedUser | null -): SavedTimelineWithSavedObjectId => { +): SavedTimeline => { const dateNow = new Date().valueOf(); if (timelineId == null) { From e4c97b4b5b90c0e5cd391723586cebbcf3b9c3bc Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 14:53:39 +0200 Subject: [PATCH 59/73] remove unused types --- .../common/api/timeline/model/api.ts | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 7ad3052b7ad6f..65d5b47698d64 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -74,30 +74,6 @@ export { export type BarePinnedEventWithoutExternalRefs = Omit; -/** - * Outcome is a property of the saved object resolve api - * will tell us info about the rule after 8.0 migrations - */ -export type SavedObjectResolveOutcome = runtimeTypes.TypeOf; -export const SavedObjectResolveOutcome = runtimeTypes.union([ - runtimeTypes.literal('exactMatch'), - runtimeTypes.literal('aliasMatch'), - runtimeTypes.literal('conflict'), -]); - -export type SavedObjectResolveAliasTargetId = runtimeTypes.TypeOf< - typeof SavedObjectResolveAliasTargetId ->; -export const SavedObjectResolveAliasTargetId = runtimeTypes.string; - -export type SavedObjectResolveAliasPurpose = runtimeTypes.TypeOf< - typeof SavedObjectResolveAliasPurpose ->; -export const SavedObjectResolveAliasPurpose = runtimeTypes.union([ - runtimeTypes.literal('savedObjectConversion'), - runtimeTypes.literal('savedObjectImport'), -]); - export const BareNoteSchema = runtimeTypes.intersection([ runtimeTypes.type({ timelineId: runtimeTypes.string, From d27f8a4786203f975e66dd5d2951c682c9bcda10 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 15:18:04 +0200 Subject: [PATCH 60/73] remove remaining runtime types from model/api.ts --- .../common/api/timeline/model/api.ts | 250 +----------------- .../routes/timelines/get_timeline/index.ts | 4 +- .../convert_saved_object_to_savedtimeline.ts | 4 +- .../timeline/utils/check_timelines_status.ts | 8 +- .../lib/timeline/utils/failure_cases.test.ts | 40 +-- .../lib/timeline/utils/failure_cases.ts | 38 +-- .../lib/timeline/utils/timeline_object.ts | 4 +- 7 files changed, 51 insertions(+), 297 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 65d5b47698d64..9780f872e3b48 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -5,12 +5,7 @@ * 2.0. */ -import * as runtimeTypes from 'io-ts'; - -import { stringEnum, unionWithNullType } from '../../../utility_types'; - import type { Maybe } from '../../../search_strategy'; -import { PinnedEventRuntimeType } from '../pinned_events/pinned_events_route'; import type { DataProviderType } from './components.gen'; import { BareNote, @@ -28,6 +23,7 @@ import { RowRendererIdEnum, SavedTimeline, SavedTimelineWithSavedObjectId, + Sort, SortDirection, SortFieldTimeline, SortFieldTimelineEnum, @@ -58,6 +54,7 @@ export { RowRendererIdEnum, SavedTimeline, SavedTimelineWithSavedObjectId, + Sort, SortDirection, SortFieldTimeline, SortFieldTimelineEnum, @@ -74,258 +71,15 @@ export { export type BarePinnedEventWithoutExternalRefs = Omit; -export const BareNoteSchema = runtimeTypes.intersection([ - runtimeTypes.type({ - timelineId: runtimeTypes.string, - }), - runtimeTypes.partial({ - eventId: unionWithNullType(runtimeTypes.string), - note: unionWithNullType(runtimeTypes.string), - created: unionWithNullType(runtimeTypes.number), - createdBy: unionWithNullType(runtimeTypes.string), - updated: unionWithNullType(runtimeTypes.number), - updatedBy: unionWithNullType(runtimeTypes.string), - }), -]); - /** * This type represents a note type stored in a saved object that does not include any fields that reference * other saved objects. */ export type BareNoteWithoutExternalRefs = Omit; -export const NoteRuntimeType = runtimeTypes.intersection([ - BareNoteSchema, - runtimeTypes.type({ - noteId: runtimeTypes.string, - version: runtimeTypes.string, - }), -]); - -/* - * ColumnHeader Types - */ -const SavedColumnHeaderRuntimeType = runtimeTypes.partial({ - aggregatable: unionWithNullType(runtimeTypes.boolean), - category: unionWithNullType(runtimeTypes.string), - columnHeaderType: unionWithNullType(runtimeTypes.string), - description: unionWithNullType(runtimeTypes.string), - example: unionWithNullType(runtimeTypes.string), - indexes: unionWithNullType(runtimeTypes.array(runtimeTypes.string)), - id: unionWithNullType(runtimeTypes.string), - name: unionWithNullType(runtimeTypes.string), - placeholder: unionWithNullType(runtimeTypes.string), - searchable: unionWithNullType(runtimeTypes.boolean), - type: unionWithNullType(runtimeTypes.string), -}); - -/* - * DataProvider Types - */ -const SavedDataProviderQueryMatchBasicRuntimeType = runtimeTypes.partial({ - field: unionWithNullType(runtimeTypes.string), - displayField: unionWithNullType(runtimeTypes.string), - value: runtimeTypes.union([ - runtimeTypes.null, - runtimeTypes.string, - runtimeTypes.array(runtimeTypes.string), - ]), - displayValue: unionWithNullType(runtimeTypes.string), - operator: unionWithNullType(runtimeTypes.string), -}); - -const SavedDataProviderQueryMatchRuntimeType = runtimeTypes.partial({ - id: unionWithNullType(runtimeTypes.string), - name: unionWithNullType(runtimeTypes.string), - enabled: unionWithNullType(runtimeTypes.boolean), - excluded: unionWithNullType(runtimeTypes.boolean), - kqlQuery: unionWithNullType(runtimeTypes.string), - queryMatch: unionWithNullType(SavedDataProviderQueryMatchBasicRuntimeType), -}); - -export const DataProviderTypeLiteralRt = runtimeTypes.union([ - runtimeTypes.literal(DataProviderTypeEnum.default), - runtimeTypes.literal(DataProviderTypeEnum.template), -]); - -const SavedDataProviderRuntimeType = runtimeTypes.partial({ - id: unionWithNullType(runtimeTypes.string), - name: unionWithNullType(runtimeTypes.string), - enabled: unionWithNullType(runtimeTypes.boolean), - excluded: unionWithNullType(runtimeTypes.boolean), - kqlQuery: unionWithNullType(runtimeTypes.string), - queryMatch: unionWithNullType(SavedDataProviderQueryMatchBasicRuntimeType), - and: unionWithNullType(runtimeTypes.array(SavedDataProviderQueryMatchRuntimeType)), - type: unionWithNullType(DataProviderTypeLiteralRt), -}); - -/* - * Filters Types - */ -const SavedFilterMetaRuntimeType = runtimeTypes.partial({ - alias: unionWithNullType(runtimeTypes.string), - controlledBy: unionWithNullType(runtimeTypes.string), - disabled: unionWithNullType(runtimeTypes.boolean), - field: unionWithNullType(runtimeTypes.string), - formattedValue: unionWithNullType(runtimeTypes.string), - index: unionWithNullType(runtimeTypes.string), - key: unionWithNullType(runtimeTypes.string), - negate: unionWithNullType(runtimeTypes.boolean), - params: unionWithNullType(runtimeTypes.string), - type: unionWithNullType(runtimeTypes.string), - value: unionWithNullType(runtimeTypes.string), -}); - -const SavedFilterRuntimeType = runtimeTypes.partial({ - exists: unionWithNullType(runtimeTypes.string), - meta: unionWithNullType(SavedFilterMetaRuntimeType), - match_all: unionWithNullType(runtimeTypes.string), - missing: unionWithNullType(runtimeTypes.string), - query: unionWithNullType(runtimeTypes.string), - range: unionWithNullType(runtimeTypes.string), - script: unionWithNullType(runtimeTypes.string), -}); - -/* - * eqlOptionsQuery -> filterQuery Types - */ -const EqlOptionsRuntimeType = runtimeTypes.partial({ - eventCategoryField: unionWithNullType(runtimeTypes.string), - query: unionWithNullType(runtimeTypes.string), - tiebreakerField: unionWithNullType(runtimeTypes.string), - timestampField: unionWithNullType(runtimeTypes.string), - size: unionWithNullType(runtimeTypes.union([runtimeTypes.string, runtimeTypes.number])), -}); - -/* - * kqlQuery -> filterQuery Types - */ -const SavedKueryFilterQueryRuntimeType = runtimeTypes.partial({ - kind: unionWithNullType(runtimeTypes.string), - expression: unionWithNullType(runtimeTypes.string), -}); - -const SavedSerializedFilterQueryQueryRuntimeType = runtimeTypes.partial({ - kuery: unionWithNullType(SavedKueryFilterQueryRuntimeType), - serializedQuery: unionWithNullType(runtimeTypes.string), -}); - -const SavedFilterQueryQueryRuntimeType = runtimeTypes.partial({ - filterQuery: unionWithNullType(SavedSerializedFilterQueryQueryRuntimeType), -}); - -/* - * DatePicker Range Types - */ -const SavedDateRangePickerRuntimeType = runtimeTypes.partial({ - /* Before the change of all timestamp to ISO string the values of start and from - * attributes where a number. Specifically UNIX timestamps. - * To support old timeline's saved object we need to add the number io-ts type - */ - start: unionWithNullType(runtimeTypes.union([runtimeTypes.string, runtimeTypes.number])), - end: unionWithNullType(runtimeTypes.union([runtimeTypes.string, runtimeTypes.number])), -}); - -/* - * Favorite Types - */ -const SavedFavoriteRuntimeType = runtimeTypes.partial({ - keySearch: unionWithNullType(runtimeTypes.string), - favoriteDate: unionWithNullType(runtimeTypes.number), - fullName: unionWithNullType(runtimeTypes.string), - userName: unionWithNullType(runtimeTypes.string), -}); - -/* - * Sort Types - */ - -const SavedSortObject = runtimeTypes.partial({ - columnId: unionWithNullType(runtimeTypes.string), - columnType: unionWithNullType(runtimeTypes.string), - sortDirection: unionWithNullType(runtimeTypes.string), -}); -const SavedSortRuntimeType = runtimeTypes.union([ - runtimeTypes.array(SavedSortObject), - SavedSortObject, -]); - -export type Sort = runtimeTypes.TypeOf; - -/* - * Timeline Statuses - */ - -export const TimelineStatusLiteralRt = runtimeTypes.union([ - runtimeTypes.literal(TimelineStatusEnum.active), - runtimeTypes.literal(TimelineStatusEnum.draft), - runtimeTypes.literal(TimelineStatusEnum.immutable), -]); - export const RowRendererCount = Object.keys(RowRendererIdEnum).length; export const RowRendererValues = Object.values(RowRendererId.Values); -const RowRendererIdRuntimeType = stringEnum(RowRendererIdEnum, 'RowRendererId'); - -/** - * Timeline types - */ - -export const TimelineTypeLiteralRt = runtimeTypes.union([ - runtimeTypes.literal(TimelineTypeEnum.template), - runtimeTypes.literal(TimelineTypeEnum.default), -]); - -/** - * This is the response type - */ -export const SavedTimelineRuntimeType = runtimeTypes.partial({ - columns: unionWithNullType(runtimeTypes.array(SavedColumnHeaderRuntimeType)), - dataProviders: unionWithNullType(runtimeTypes.array(SavedDataProviderRuntimeType)), - dataViewId: unionWithNullType(runtimeTypes.string), - description: unionWithNullType(runtimeTypes.string), - eqlOptions: unionWithNullType(EqlOptionsRuntimeType), - eventType: unionWithNullType(runtimeTypes.string), - excludedRowRendererIds: unionWithNullType(runtimeTypes.array(RowRendererIdRuntimeType)), - favorite: unionWithNullType(runtimeTypes.array(SavedFavoriteRuntimeType)), - filters: unionWithNullType(runtimeTypes.array(SavedFilterRuntimeType)), - indexNames: unionWithNullType(runtimeTypes.array(runtimeTypes.string)), - kqlMode: unionWithNullType(runtimeTypes.string), - kqlQuery: unionWithNullType(SavedFilterQueryQueryRuntimeType), - title: unionWithNullType(runtimeTypes.string), - templateTimelineId: unionWithNullType(runtimeTypes.string), - templateTimelineVersion: unionWithNullType(runtimeTypes.number), - timelineType: unionWithNullType(TimelineTypeLiteralRt), - dateRange: unionWithNullType(SavedDateRangePickerRuntimeType), - savedQueryId: unionWithNullType(runtimeTypes.string), - sort: unionWithNullType(SavedSortRuntimeType), - status: unionWithNullType(TimelineStatusLiteralRt), - created: unionWithNullType(runtimeTypes.number), - createdBy: unionWithNullType(runtimeTypes.string), - updated: unionWithNullType(runtimeTypes.number), - updatedBy: unionWithNullType(runtimeTypes.string), - savedSearchId: unionWithNullType(runtimeTypes.string), -}); - -export const TimelineSavedToReturnObjectRuntimeType = runtimeTypes.intersection([ - SavedTimelineRuntimeType, - runtimeTypes.type({ - savedObjectId: runtimeTypes.string, - version: runtimeTypes.string, - }), - runtimeTypes.partial({ - eventIdToNoteIds: runtimeTypes.array(NoteRuntimeType), - noteIds: runtimeTypes.array(runtimeTypes.string), - notes: runtimeTypes.array(NoteRuntimeType), - pinnedEventIds: runtimeTypes.array(runtimeTypes.string), - pinnedEventsSaveObject: runtimeTypes.array(PinnedEventRuntimeType), - }), -]); - -export type TimelineSavedObject = runtimeTypes.TypeOf< - typeof TimelineSavedToReturnObjectRuntimeType ->; - /** * Import/export timelines */ diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts index 04a3df7638f43..870955f7e8691 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts @@ -20,7 +20,7 @@ import { type GetTimelineResponse, } from '../../../../../../common/api/timeline'; import { getTimelineTemplateOrNull, getTimelineOrNull } from '../../../saved_object/timelines'; -import type { TimelineSavedObject, ResolvedTimeline } from '../../../../../../common/api/timeline'; +import type { ResolvedTimeline, TimelineResponse } from '../../../../../../common/api/timeline'; export const getTimelineRoute = (router: SecuritySolutionPluginRouter) => { router.versioned @@ -44,7 +44,7 @@ export const getTimelineRoute = (router: SecuritySolutionPluginRouter) => { const query = request.query ?? {}; const { template_timeline_id: templateTimelineId, id } = query; - let res: TimelineSavedObject | ResolvedTimeline | null = null; + let res: TimelineResponse | ResolvedTimeline | null = null; if (templateTimelineId != null && id == null) { res = await getTimelineTemplateOrNull(frameworkRequest, templateTimelineId); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/convert_saved_object_to_savedtimeline.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/convert_saved_object_to_savedtimeline.ts index 2cde936f1c462..88054f0eb6953 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/convert_saved_object_to_savedtimeline.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/convert_saved_object_to_savedtimeline.ts @@ -16,7 +16,7 @@ import { SavedObjectTimelineType, SavedObjectTimelineStatus, } from '../../../../../common/types/timeline/saved_object'; -import type { TimelineSavedObject } from '../../../../../common/api/timeline'; +import type { TimelineResponse } from '../../../../../common/api/timeline'; import { type TimelineType, TimelineTypeEnum, @@ -49,7 +49,7 @@ const getTimelineTypeAndStatus = ( }; }; -export const convertSavedObjectToSavedTimeline = (savedObject: unknown): TimelineSavedObject => +export const convertSavedObjectToSavedTimeline = (savedObject: unknown): TimelineResponse => pipe( TimelineSavedObjectWithDraftRuntime.decode(savedObject), map((savedTimeline) => { diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts index 34f94594e29cb..caf4bee68e70f 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/check_timelines_status.ts @@ -7,7 +7,7 @@ import path, { join, resolve } from 'path'; import type { - TimelineSavedObject, + TimelineResponse, ImportTimelines, InstallPrepackedTimelinesRequestBody, } from '../../../../common/api/timeline'; @@ -20,7 +20,7 @@ import { loadData, getReadables } from './common'; export const getTimelinesToUpdate = ( timelinesFromFileSystem: ImportTimelines[], - installedTimelines: TimelineSavedObject[] + installedTimelines: TimelineResponse[] ): ImportTimelines[] => { return timelinesFromFileSystem.filter((timeline) => installedTimelines.some((installedTimeline) => { @@ -35,7 +35,7 @@ export const getTimelinesToUpdate = ( export const getTimelinesToInstall = ( timelinesFromFileSystem: ImportTimelines[], - installedTimelines: TimelineSavedObject[] + installedTimelines: TimelineResponse[] ): ImportTimelines[] => { return timelinesFromFileSystem.filter( (timeline) => @@ -53,7 +53,7 @@ export const checkTimelinesStatus = async ( let readStream; let timeline: { totalCount: number; - timeline: TimelineSavedObject[]; + timeline: TimelineResponse[]; }; const dir = resolve( join( diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.test.ts index e5e247c1209fe..716bacaacf5ac 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.test.ts @@ -26,7 +26,7 @@ import { NOT_ALLOW_UPDATE_STATUS_ERROR_MESSAGE, TEMPLATE_TIMELINE_VERSION_CONFLICT_MESSAGE, } from './failure_cases'; -import type { TimelineSavedObject } from '../../../../common/api/timeline'; +import type { TimelineResponse } from '../../../../common/api/timeline'; import { TimelineStatusEnum, TimelineTypeEnum } from '../../../../common/api/timeline'; import { mockGetTimelineValue, mockGetTemplateTimelineValue } from '../__mocks__/import_timelines'; @@ -69,7 +69,7 @@ describe('failure cases', () => { const version = null; const templateTimelineVersion = null; const templateTimelineId = null; - const existTimeline = mockGetTimelineValue as TimelineSavedObject; + const existTimeline = mockGetTimelineValue as TimelineResponse; const existTemplateTimeline = null; const result = checkIsCreateFailureCases( isHandlingTemplateTimeline, @@ -94,7 +94,7 @@ describe('failure cases', () => { const templateTimelineVersion = 1; const templateTimelineId = 'template-timeline-id-one'; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsCreateFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -144,7 +144,7 @@ describe('failure cases', () => { const templateTimelineVersion = null; const templateTimelineId = null; const existTimeline = { - ...(mockGetTimelineValue as TimelineSavedObject), + ...(mockGetTimelineValue as TimelineResponse), status: TimelineStatusEnum.immutable, }; const existTemplateTimeline = null; @@ -172,7 +172,7 @@ describe('failure cases', () => { const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; const existTemplateTimeline = { - ...(mockGetTemplateTimelineValue as TimelineSavedObject), + ...(mockGetTemplateTimelineValue as TimelineResponse), status: TimelineStatusEnum.immutable, }; const result = checkIsUpdateFailureCases( @@ -198,7 +198,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -246,10 +246,10 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = { - ...(mockGetTemplateTimelineValue as TimelineSavedObject), + ...(mockGetTemplateTimelineValue as TimelineResponse), savedObjectId: 'someOtherId', }; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -273,7 +273,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -297,7 +297,7 @@ describe('failure cases', () => { const templateTimelineVersion = null; const templateTimelineId = null; const existTimeline = { - ...(mockGetTemplateTimelineValue as TimelineSavedObject), + ...(mockGetTemplateTimelineValue as TimelineResponse), savedObjectId: 'someOtherId', }; const existTemplateTimeline = null; @@ -326,7 +326,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsCreateViaImportFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.draft, @@ -350,7 +350,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsCreateViaImportFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -373,7 +373,7 @@ describe('failure cases', () => { const version = mockGetTimelineValue.version; const templateTimelineVersion = null; const templateTimelineId = null; - const existTimeline = mockGetTimelineValue as TimelineSavedObject; + const existTimeline = mockGetTimelineValue as TimelineResponse; const existTemplateTimeline = null; const result = checkIsCreateViaImportFailureCases( isHandlingTemplateTimeline, @@ -399,7 +399,7 @@ describe('failure cases', () => { const version = mockGetTimelineValue.version; const templateTimelineVersion = null; const templateTimelineId = null; - const existTimeline = mockGetTimelineValue as TimelineSavedObject; + const existTimeline = mockGetTimelineValue as TimelineResponse; const existTemplateTimeline = null; const result = checkIsUpdateViaImportFailureCases( isHandlingTemplateTimeline, @@ -424,7 +424,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateViaImportFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -448,7 +448,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateViaImportFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.immutable, @@ -496,10 +496,10 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = { - ...(mockGetTemplateTimelineValue as TimelineSavedObject), + ...(mockGetTemplateTimelineValue as TimelineResponse), savedObjectId: 'someOtherId', }; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateViaImportFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -523,7 +523,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateViaImportFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, @@ -547,7 +547,7 @@ describe('failure cases', () => { const templateTimelineVersion = mockGetTemplateTimelineValue.templateTimelineVersion; const templateTimelineId = mockGetTemplateTimelineValue.templateTimelineId; const existTimeline = null; - const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineSavedObject; + const existTemplateTimeline = mockGetTemplateTimelineValue as TimelineResponse; const result = checkIsUpdateViaImportFailureCases( isHandlingTemplateTimeline, TimelineStatusEnum.active, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.ts index 045793e2251ba..7dace57181239 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/failure_cases.ts @@ -6,7 +6,7 @@ */ import { isEmpty } from 'lodash/fp'; -import type { TimelineType, TimelineSavedObject } from '../../../../common/api/timeline'; +import type { TimelineType, TimelineResponse } from '../../../../common/api/timeline'; import { type TimelineStatus, TimelineStatusEnum } from '../../../../common/api/timeline'; export const UPDATE_TIMELINE_ERROR_MESSAGE = @@ -42,8 +42,8 @@ export const DEFAULT_ERROR = `Something has gone wrong. We didn't handle somethi const isUpdatingStatus = ( isHandlingTemplateTimeline: boolean, status: TimelineStatus | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { const obj = isHandlingTemplateTimeline ? existTemplateTimeline : existTimeline; return obj?.status === TimelineStatusEnum.immutable ? UPDATE_STATUS_ERROR_MESSAGE : null; @@ -76,8 +76,8 @@ const commonUpdateTemplateTimelineCheck = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { if (isHandlingTemplateTimeline) { if ( @@ -129,8 +129,8 @@ const commonUpdateTimelineCheck = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { if (existTimeline == null) { // timeline !exists @@ -158,8 +158,8 @@ const commonUpdateCases = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { if (isHandlingTemplateTimeline) { return commonUpdateTemplateTimelineCheck( @@ -193,8 +193,8 @@ const createTemplateTimelineCheck = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { if (isHandlingTemplateTimeline && existTemplateTimeline != null) { // Throw error to create timeline template in patch @@ -219,8 +219,8 @@ export const checkIsUpdateViaImportFailureCases = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { if (!isHandlingTemplateTimeline) { if (existTimeline == null) { @@ -281,8 +281,8 @@ export const checkIsUpdateFailureCases = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { const error = isUpdatingStatus( isHandlingTemplateTimeline, @@ -315,8 +315,8 @@ export const checkIsCreateFailureCases = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { if (!isHandlingTemplateTimeline && existTimeline != null) { return { @@ -346,8 +346,8 @@ export const checkIsCreateViaImportFailureCases = ( version: string | null, templateTimelineVersion: number | null, templateTimelineId: string | null | undefined, - existTimeline: TimelineSavedObject | null, - existTemplateTimeline: TimelineSavedObject | null + existTimeline: TimelineResponse | null, + existTemplateTimeline: TimelineResponse | null ) => { if (status === TimelineStatusEnum.draft) { return { diff --git a/x-pack/plugins/security_solution/server/lib/timeline/utils/timeline_object.ts b/x-pack/plugins/security_solution/server/lib/timeline/utils/timeline_object.ts index 360125e450764..44afe078f9104 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/utils/timeline_object.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/utils/timeline_object.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { TimelineSavedObject } from '../../../../common/api/timeline'; +import type { TimelineResponse } from '../../../../common/api/timeline'; import { type TimelineType, TimelineTypeEnum, @@ -27,7 +27,7 @@ export class TimelineObject { public readonly version: string | number | null; private frameworkRequest: FrameworkRequest; - public data: TimelineSavedObject | null; + public data: TimelineResponse | null; constructor({ id = null, From 71f511a948daeaf28dcd9c3cbcd940b208a5448f Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 15:21:42 +0200 Subject: [PATCH 61/73] Remove unused route file --- .../common/api/timeline/index.ts | 2 -- .../pinned_events/pinned_events_route.ts | 34 ------------------- 2 files changed, 36 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index efca50791c0ac..0a148bcc59797 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -7,5 +7,3 @@ export * from './model/api'; export * from './routes'; - -export * from './pinned_events/pinned_events_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts deleted file mode 100644 index 31c3233e9b8ca..0000000000000 --- a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.ts +++ /dev/null @@ -1,34 +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 runtimeTypes from 'io-ts'; -import { unionWithNullType } from '../../../utility_types'; - -/* - * Pinned Event Types - * TODO: remove these when the timeline types are moved to zod - */ -const BarePinnedEventType = runtimeTypes.intersection([ - runtimeTypes.type({ - timelineId: runtimeTypes.string, - eventId: runtimeTypes.string, - }), - runtimeTypes.partial({ - created: unionWithNullType(runtimeTypes.number), - createdBy: unionWithNullType(runtimeTypes.string), - updated: unionWithNullType(runtimeTypes.number), - updatedBy: unionWithNullType(runtimeTypes.string), - }), -]); - -export const PinnedEventRuntimeType = runtimeTypes.intersection([ - runtimeTypes.type({ - pinnedEventId: runtimeTypes.string, - version: runtimeTypes.string, - }), - BarePinnedEventType, -]); From b74128bd299bde61d911232697ab33ccb8ddb848 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 15:26:51 +0200 Subject: [PATCH 62/73] Remove comments --- .../security_solution/public/timelines/containers/api.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 52befd485471d..738ff3369bcc0 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -69,10 +69,6 @@ const parseOrThrow = parseOrThrowErrorFactory(createToasterPlainError); const decodeTimelineResponse = (respTimeline?: PersistTimelineResponse | TimelineErrorResponse) => parseOrThrow(PersistTimelineResponse)(respTimeline); -// - migrate over all decode functions -// - make that where theyre used, the correct new types are used and none of the legacy types -// - Check what can be done about TimelineErrorResponse -// - check in timeline/api.ts if more types can be removed const decodeSingleTimelineResponse = (respTimeline?: GetTimelineResponse) => parseOrThrow(GetTimelineResponse)(respTimeline); From 1ca9ef5052b42e1c14b20bc596d71399108a01a4 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 19:28:45 +0200 Subject: [PATCH 63/73] fix types --- .../lib/timeline/routes/timelines/create_timelines/helpers.ts | 2 +- .../server/lib/timeline/saved_object/notes/persist_notes.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts index 1428f09d39560..3736386ac3f03 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts @@ -21,7 +21,7 @@ interface CreateTimelineProps { overrideNotesOwner?: boolean; pinnedEventIds?: string[] | null; notes?: Note[]; - existingNoteIds?: string[]; + existingNoteIds?: string[] | null; isImmutable?: boolean; } diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/persist_notes.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/persist_notes.ts index a12aaeb010234..571e0f4da8616 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/persist_notes.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/persist_notes.ts @@ -13,7 +13,7 @@ import type { Note } from '../../../../../common/api/timeline'; export const persistNotes = async ( frameworkRequest: FrameworkRequest, timelineSavedObjectId: string, - existingNoteIds?: string[], + existingNoteIds?: string[] | null, newNotes?: Note[], overrideOwner: boolean = true ) => { From 3c19531d3bc85e659a31e9aea0fc56b0572482e1 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 26 Sep 2024 20:45:37 +0200 Subject: [PATCH 64/73] fix and remove more types --- .../common/api/timeline/model/api.ts | 143 +----------------- .../api/timeline/model/components.gen.ts | 9 -- .../api/timeline/model/components.schema.yaml | 18 --- .../public/common/mock/timeline_results.ts | 4 +- .../components/alerts_table/actions.tsx | 14 +- .../components/open_timeline/helpers.test.ts | 8 +- .../components/open_timeline/helpers.ts | 20 +-- .../public/timelines/containers/all/index.tsx | 6 +- .../public/timelines/containers/helpers.ts | 4 +- .../timelines/create_timelines/helpers.ts | 5 +- .../timelines/export_timelines/helpers.ts | 6 +- .../timeline/saved_object/timelines/index.ts | 2 +- 12 files changed, 45 insertions(+), 194 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index 9780f872e3b48..fcf21c0de0639 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -5,19 +5,21 @@ * 2.0. */ -import type { Maybe } from '../../../search_strategy'; import type { DataProviderType } from './components.gen'; import { BareNote, BarePinnedEvent, + ColumnHeaderResult, DataProviderTypeEnum, + DataProviderResult, FavoriteTimelineResponse, - type FavoriteTimelineResult, + FilterTimelineResult, ImportTimelineResult, ImportTimelines, type Note, PinnedEvent, PersistTimelineResponse, + QueryMatchResult, ResolvedTimeline, RowRendererId, RowRendererIdEnum, @@ -41,14 +43,18 @@ import { export { BareNote, BarePinnedEvent, + ColumnHeaderResult, + DataProviderResult, DataProviderType, DataProviderTypeEnum, FavoriteTimelineResponse, + FilterTimelineResult, ImportTimelineResult, ImportTimelines, Note, PinnedEvent, PersistTimelineResponse, + QueryMatchResult, ResolvedTimeline, RowRendererId, RowRendererIdEnum, @@ -92,11 +98,6 @@ export interface ExportedNotes { globalNotes: ExportedGlobalNotes; } -export type ExportedTimelines = SavedTimeline & - ExportedNotes & { - pinnedEventIds: string[]; - }; - export interface ExportTimelineNotFoundError { statusCode: number; message: string; @@ -107,134 +108,6 @@ export interface PageInfoTimeline { pageSize: number; } -export interface ColumnHeaderResult { - aggregatable?: Maybe; - category?: Maybe; - columnHeaderType?: Maybe; - description?: Maybe; - example?: Maybe; - indexes?: Maybe; - id?: Maybe; - name?: Maybe; - placeholder?: Maybe; - searchable?: Maybe; - type?: Maybe; -} - -export interface DataProviderResult { - id?: Maybe; - name?: Maybe; - enabled?: Maybe; - excluded?: Maybe; - kqlQuery?: Maybe; - queryMatch?: Maybe; - type?: Maybe; - and?: Maybe; -} - -export interface QueryMatchResult { - field?: Maybe; - displayField?: Maybe; - value?: Maybe; - displayValue?: Maybe; - operator?: Maybe; -} - -export interface DateRangePickerResult { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - start?: Maybe; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - end?: Maybe; -} - -export interface EqlOptionsResult { - eventCategoryField?: Maybe; - tiebreakerField?: Maybe; - timestampField?: Maybe; - query?: Maybe; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - size?: Maybe; -} - -export interface FilterTimelineResult { - exists?: Maybe; - meta?: Maybe; - match_all?: Maybe; - missing?: Maybe; - query?: Maybe; - range?: Maybe; - script?: Maybe; -} - -export interface FilterMetaTimelineResult { - alias?: Maybe; - controlledBy?: Maybe; - disabled?: Maybe; - field?: Maybe; - formattedValue?: Maybe; - index?: Maybe; - key?: Maybe; - negate?: Maybe; - params?: Maybe; - type?: Maybe; - value?: Maybe; -} - -export interface SerializedFilterQueryResult { - filterQuery?: Maybe; -} - -export interface KueryFilterQueryResult { - kind?: Maybe; - expression?: Maybe; -} - -export interface SerializedKueryQueryResult { - kuery?: Maybe; - serializedQuery?: Maybe; -} - -export interface TimelineResult { - columns?: Maybe; - created?: Maybe; - createdBy?: Maybe; - dataProviders?: Maybe; - dataViewId?: Maybe; - dateRange?: Maybe; - description?: Maybe; - eqlOptions?: Maybe; - eventIdToNoteIds?: Maybe; - eventType?: Maybe; - excludedRowRendererIds?: Maybe; - favorite?: Maybe; - filters?: Maybe; - kqlMode?: Maybe; - kqlQuery?: Maybe; - indexNames?: Maybe; - notes?: Maybe; - noteIds?: Maybe; - pinnedEventIds?: Maybe; - pinnedEventsSaveObject?: Maybe; - savedQueryId?: Maybe; - savedObjectId: string; - sort?: Maybe; - status?: Maybe; - title?: Maybe; - templateTimelineId?: Maybe; - templateTimelineVersion?: Maybe; - timelineType?: Maybe; - updated?: Maybe; - updatedBy?: Maybe; - version: string; - savedSearchId?: Maybe; -} - -export interface ResponseTimeline { - code?: Maybe; - message?: Maybe; - timeline: TimelineResult; -} - export interface SortTimeline { sortField: SortFieldTimeline; sortOrder: SortDirection; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts index c8d966aad9934..93d627f53263b 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.gen.ts @@ -413,12 +413,3 @@ export const TimelineErrorResponse = z.union([ statusCode: z.number(), }), ]); - -export type ExportedTimelines = z.infer; -export const ExportedTimelines = SavedTimeline.merge( - z.object({ - globalNotes: z.array(Note).optional(), - eventNotes: z.array(Note).optional(), - pinnedEventIds: z.array(z.string()).optional(), - }) -); diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml index 1335062586e06..568eec1975769 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/model/components.schema.yaml @@ -732,21 +732,3 @@ components: type: string statusCode: type: number - - ExportedTimelines: - allOf: - - $ref: '#/components/schemas/SavedTimeline' - - type: object - properties: - globalNotes: - type: array - items: - $ref: '#/components/schemas/Note' - eventNotes: - type: array - items: - $ref: '#/components/schemas/Note' - pinnedEventIds: - type: array - items: - type: string diff --git a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts index a97be122e8a6a..d32891333c7f0 100644 --- a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts +++ b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts @@ -9,8 +9,8 @@ import { FilterStateStore } from '@kbn/es-query'; import type { DataTableModel } from '@kbn/securitysolution-data-table'; import { VIEW_SELECTION } from '../../../common/constants'; -import type { TimelineResult } from '../../../common/api/timeline'; import { TimelineId, TimelineTabs } from '../../../common/types/timeline'; +import type { TimelineResponse } from '../../../common/api/timeline'; import { type ColumnHeaderResult, RowRendererIdEnum, @@ -1987,7 +1987,7 @@ export const mockDataTableModel: DataTableModel = { }, }; -export const mockGetOneTimelineResult: TimelineResult = { +export const mockGetOneTimelineResult: TimelineResponse = { savedObjectId: 'ef579e40-jibber-jabber', columns: timelineDefaults.columns.filter( (column) => column.id !== 'event.action' diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx index c83fa2bf22211..a2dfef2c43e9f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx @@ -50,8 +50,8 @@ import { isNewTermsRule, isThresholdRule, } from '../../../../common/detection_engine/utils'; -import type { TimelineResult } from '../../../../common/api/timeline'; import { TimelineId } from '../../../../common/types/timeline'; +import type { TimelineResponse } from '../../../../common/api/timeline'; import { TimelineStatusEnum, TimelineTypeEnum } from '../../../../common/api/timeline'; import type { SendAlertToTimelineActionProps, @@ -69,7 +69,7 @@ import { TimelineEventsQueries } from '../../../../common/search_strategy/timeli import { timelineDefaults } from '../../../timelines/store/defaults'; import { omitTypenameInTimeline, - formatTimelineResultToModel, + formatTimelineResponseToModel, } from '../../../timelines/components/open_timeline/helpers'; import { convertKueryToElasticSearchQuery } from '../../../common/lib/kuery'; import { getField, getFieldKey } from '../../../helpers'; @@ -983,11 +983,15 @@ export const sendAlertToTimelineAction = async ({ ), ]); - const resultingTimeline: TimelineResult = getOr({}, 'data.getOneTimeline', responseTimeline); + const resultingTimeline: TimelineResponse = getOr( + {}, + 'data.getOneTimeline', + responseTimeline + ); const eventData: TimelineEventsDetailsItem[] = eventDataResp.data ?? []; if (!isEmpty(resultingTimeline)) { - const timelineTemplate: TimelineResult = omitTypenameInTimeline(resultingTimeline); - const { timeline, notes } = formatTimelineResultToModel( + const timelineTemplate = omitTypenameInTimeline(resultingTimeline); + const { timeline, notes } = formatTimelineResponseToModel( timelineTemplate, true, timelineTemplate.timelineType ?? TimelineTypeEnum.default diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts index 9238568b7cc96..a3428ae6f2e1d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts @@ -20,7 +20,7 @@ import { isUntitled, omitTypenameInTimeline, useQueryTimelineById, - formatTimelineResultToModel, + formatTimelineResponseToModel, } from './helpers'; import type { OpenTimelineResult } from './types'; import { TimelineId } from '../../../../common/types/timeline'; @@ -695,7 +695,7 @@ describe('helpers', () => { }); test('Do not override daterange if TimelineStatus is active', () => { - const { timeline } = formatTimelineResultToModel( + const { timeline } = formatTimelineResponseToModel( omitTypenameInTimeline(getOr({}, 'data.timeline', selectedTimeline)), args.duplicate, args.timelineType @@ -748,7 +748,7 @@ describe('helpers', () => { }); test('should not override daterange if TimelineStatus is active', () => { - const { timeline } = formatTimelineResultToModel( + const { timeline } = formatTimelineResponseToModel( omitTypenameInTimeline(getOr({}, 'data.timeline', selectedTimeline)), args.duplicate, args.timelineType @@ -822,7 +822,7 @@ describe('helpers', () => { }); test('override daterange if TimelineStatus is immutable', () => { - const { timeline } = formatTimelineResultToModel( + const { timeline } = formatTimelineResponseToModel( omitTypenameInTimeline(getOr({}, 'data.timeline', template)), args.duplicate, args.timelineType diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts index e977d05f07689..000a7b226561e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts @@ -14,7 +14,7 @@ import { useCallback } from 'react'; import { useDiscoverInTimelineContext } from '../../../common/components/discover_in_timeline/use_discover_in_timeline_context'; import type { ColumnHeaderOptions } from '../../../../common/types/timeline'; import type { - TimelineResult, + TimelineResponse, ResolvedTimeline, ColumnHeaderResult, FilterTimelineResult, @@ -80,7 +80,7 @@ export const isUntitled = ({ title }: OpenTimelineResult): boolean => const omitTypename = (key: string, value: keyof TimelineModel) => key === '__typename' ? undefined : value; -export const omitTypenameInTimeline = (timeline: TimelineResult): TimelineResult => +export const omitTypenameInTimeline = (timeline: TimelineResponse): TimelineResponse => JSON.parse(JSON.stringify(timeline), omitTypename); const parseString = (params: string) => { @@ -164,7 +164,7 @@ const setPinnedEventIds = (duplicate: boolean, pinnedEventIds: string[] | null | : {}; const getTemplateTimelineId = ( - timeline: TimelineResult, + timeline: TimelineResponse, duplicate: boolean, targetTimelineType?: TimelineType ) => { @@ -200,7 +200,7 @@ const convertToDefaultField = ({ and, ...dataProvider }: DataProviderResult) => const getDataProviders = ( duplicate: boolean, - dataProviders: TimelineResult['dataProviders'], + dataProviders: TimelineResponse['dataProviders'], timelineType?: TimelineType ) => { if (duplicate && dataProviders && timelineType === TimelineTypeEnum.default) { @@ -214,7 +214,7 @@ const getDataProviders = ( }; export const getTimelineTitle = ( - timeline: TimelineResult, + timeline: TimelineResponse, duplicate: boolean, timelineType?: TimelineType ) => { @@ -225,7 +225,7 @@ export const getTimelineTitle = ( }; export const getTimelineStatus = ( - timeline: TimelineResult, + timeline: TimelineResponse, duplicate: boolean, timelineType?: TimelineType ) => { @@ -236,7 +236,7 @@ export const getTimelineStatus = ( }; export const defaultTimelineToTimelineModel = ( - timeline: TimelineResult, + timeline: TimelineResponse, duplicate: boolean, timelineType?: TimelineType, unifiedComponentsInTimelineDisabled?: boolean @@ -291,8 +291,8 @@ export const defaultTimelineToTimelineModel = ( ); }; -export const formatTimelineResultToModel = ( - timelineToOpen: TimelineResult, +export const formatTimelineResponseToModel = ( + timelineToOpen: TimelineResponse, duplicate: boolean = false, timelineType?: TimelineType, unifiedComponentsInTimelineDisabled?: boolean @@ -381,7 +381,7 @@ export const useQueryTimelineById = () => { const timelineToOpen = omitTypenameInTimeline(data.timeline); - const { timeline, notes } = formatTimelineResultToModel( + const { timeline, notes } = formatTimelineResponseToModel( timelineToOpen, duplicate, timelineType, diff --git a/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx index 48d4aa698a324..9db2a0b8924d9 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/all/index.tsx @@ -21,7 +21,7 @@ import type { TimelineType, TimelineStatus, PageInfoTimeline, - TimelineResult, + TimelineResponse, SortTimeline, GetTimelinesRequestQuery, } from '../../../../common/api/timeline'; @@ -59,7 +59,7 @@ export interface AllTimelinesVariables { export const ALL_TIMELINE_QUERY_ID = 'FETCH_ALL_TIMELINES'; export const getAllTimeline = memoizeOne( - (_variables: string, timelines: TimelineResult[]): OpenTimelineResult[] => + (_variables: string, timelines: TimelineResponse[]): OpenTimelineResult[] => timelines.map((timeline) => ({ created: timeline.created, description: timeline.description, @@ -165,7 +165,7 @@ export const useGetAllTimeline = (): AllTimelinesArgs => { setAllTimelines({ loading: false, totalCount, - timelines: getAllTimeline(JSON.stringify(variables), timelines as TimelineResult[]), + timelines: getAllTimeline(JSON.stringify(variables), timelines as TimelineResponse[]), customTemplateTimelineCount, defaultTimelineCount, elasticTemplateTimelineCount, diff --git a/x-pack/plugins/security_solution/public/timelines/containers/helpers.ts b/x-pack/plugins/security_solution/public/timelines/containers/helpers.ts index 17d0050488f5b..fef5fa22f0bfb 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/helpers.ts @@ -6,10 +6,10 @@ */ import { TableId } from '@kbn/securitysolution-data-table'; -import type { TimelineResult } from '../../../common/api/timeline'; +import type { TimelineResponse } from '../../../common/api/timeline'; import { DEFAULT_ALERTS_INDEX } from '../../../common/constants'; -export const getTimelineQueryTypes = (timeline: TimelineResult) => ({ +export const getTimelineQueryTypes = (timeline: TimelineResponse) => ({ hasQuery: (timeline.kqlQuery != null && timeline.kqlQuery.filterQuery != null && diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts index 3736386ac3f03..ac05fe3f880e9 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/create_timelines/helpers.ts @@ -10,8 +10,9 @@ import { isEmpty } from 'lodash/fp'; import moment from 'moment'; import { timeline as timelineLib, pinnedEvent as pinnedEventLib } from '../../../saved_object'; import type { FrameworkRequest } from '../../../../framework'; -import type { ResponseTimeline, SavedTimeline, Note } from '../../../../../../common/api/timeline'; +import type { SavedTimeline, Note } from '../../../../../../common/api/timeline'; import { persistNotes } from '../../../saved_object/notes/persist_notes'; +import type { InternalTimelineResponse } from '../../../saved_object/timelines'; interface CreateTimelineProps { frameworkRequest: FrameworkRequest; @@ -40,7 +41,7 @@ export const createTimelines = async ({ existingNoteIds = [], isImmutable, overrideNotesOwner = true, -}: CreateTimelineProps): Promise => { +}: CreateTimelineProps): Promise => { const timerangeStart = isImmutable ? moment().subtract(24, 'hours').toISOString() : timeline.dateRange?.start; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/helpers.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/helpers.ts index 4974e6bd0edda..6e4f3d84da1ff 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/helpers.ts @@ -9,11 +9,11 @@ import { omit } from 'lodash/fp'; import { transformDataToNdjson } from '@kbn/securitysolution-utils'; import type { - ExportedTimelines, ExportedNotes, ExportTimelineNotFoundError, Note, PinnedEvent, + TimelineResponse, } from '../../../../../../common/api/timeline'; import type { FrameworkRequest } from '../../../../framework'; @@ -45,7 +45,7 @@ const getPinnedEventsIdsByTimelineId = (currentPinnedEvents: PinnedEvent[]): str const getTimelinesFromObjects = async ( request: FrameworkRequest, ids?: string[] | null -): Promise> => { +): Promise> => { const { timelines, errors } = await getSelectedTimelines(request, ids); const exportedIds = timelines.map((t) => t.savedObjectId); @@ -65,7 +65,7 @@ const getTimelinesFromObjects = async ( [] ); - const myResponse = exportedIds.reduce((acc, timelineId) => { + const myResponse = exportedIds.reduce((acc, timelineId) => { const myTimeline = timelines.find((t) => t.savedObjectId === timelineId); if (myTimeline != null) { const timelineNotes = myNotes.filter((n) => n.timelineId === timelineId); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts index cbde4fb2aaacf..c3016164d4e7e 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts @@ -377,7 +377,7 @@ export const persistFavorite = async ( } }; -interface InternalTimelineResponse { +export interface InternalTimelineResponse { code: number; message: string; timeline: TimelineResponse; From 39255f9f6271cec28fd23ab8f055587b2c9e9a1d Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 27 Sep 2024 08:38:19 +0200 Subject: [PATCH 65/73] fix types --- .../security_solution/common/api/timeline/model/api.ts | 6 ++++++ .../saved_objects/trial_license_complete_tier/timeline.ts | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index fcf21c0de0639..250daaf3077eb 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -75,6 +75,12 @@ export { TimelineTypeEnum, }; +/** + * This type represents a timeline type stored in a saved object that does not include any fields that reference + * other saved objects. + */ +export type TimelineWithoutExternalRefs = Omit; + export type BarePinnedEventWithoutExternalRefs = Omit; /** diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/timeline.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/timeline.ts index 6895d79c5aa8e..3206c14eee04d 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/timeline.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/timeline.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { - TimelineResult, + TimelineResponse, TimelineTypeEnum, } from '@kbn/security-solution-plugin/common/api/timeline'; import { FtrProviderContext } from '../../../../../api_integration/ftr_provider_context'; @@ -419,8 +419,8 @@ export default function ({ getService }: FtrProviderContext) { }); } -const omitTypename = (key: string, value: keyof TimelineResult) => +const omitTypename = (key: string, value: keyof TimelineResponse) => key === '__typename' ? undefined : value; -const omitTypenameInTimeline = (timeline: TimelineResult) => +const omitTypenameInTimeline = (timeline: TimelineResponse) => JSON.parse(JSON.stringify(timeline), omitTypename); From 2acec5510b71e28c1875600f80b07c810e004d8a Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 27 Sep 2024 09:22:00 +0200 Subject: [PATCH 66/73] remove more types --- .../common/search_strategy/timeline/index.ts | 124 +----------------- .../public/timelines/containers/api.ts | 4 +- .../store/middlewares/timeline_save.test.ts | 2 +- .../store/middlewares/timeline_save.ts | 8 +- .../services/timeline/index.ts | 8 +- 5 files changed, 12 insertions(+), 134 deletions(-) diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts index ff9613503e8e3..7fe70febe4e2c 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts @@ -5,13 +5,7 @@ * 2.0. */ -import type { SortField, Maybe } from '../common'; -import type { - DataProviderType, - TimelineType, - TimelineStatus, - RowRendererId, -} from '../../api/timeline'; +import type { SortField } from '../common'; export * from './events'; @@ -20,122 +14,6 @@ export interface TimelineRequestSortField extends SortField; - category?: Maybe; - columnHeaderType?: Maybe; - description?: Maybe; - example?: Maybe; - indexes?: Maybe; - id?: Maybe; - name?: Maybe; - placeholder?: Maybe; - searchable?: Maybe; - type?: Maybe; -} - -export interface QueryMatchInput { - field?: Maybe; - - displayField?: Maybe; - - value?: Maybe; - - displayValue?: Maybe; - - operator?: Maybe; -} - -export interface DataProviderInput { - id?: Maybe; - name?: Maybe; - enabled?: Maybe; - excluded?: Maybe; - kqlQuery?: Maybe; - queryMatch?: Maybe; - and?: Maybe; - type?: Maybe; -} - -export interface EqlOptionsInput { - eventCategoryField?: Maybe; - tiebreakerField?: Maybe; - timestampField?: Maybe; - query?: Maybe; - size?: Maybe; -} - -export interface FilterMetaTimelineInput { - alias?: Maybe; - controlledBy?: Maybe; - disabled?: Maybe; - field?: Maybe; - formattedValue?: Maybe; - index?: Maybe; - key?: Maybe; - negate?: Maybe; - params?: Maybe; - type?: Maybe; - value?: Maybe; -} - -export interface FilterTimelineInput { - exists?: Maybe; - meta?: Maybe; - match_all?: Maybe; - missing?: Maybe; - query?: Maybe; - range?: Maybe; - script?: Maybe; -} - -export interface SerializedFilterQueryInput { - filterQuery?: Maybe; -} - -export interface SerializedKueryQueryInput { - kuery?: Maybe; - serializedQuery?: Maybe; -} - -export interface KueryFilterQueryInput { - kind?: Maybe; - expression?: Maybe; -} - -export interface DateRangePickerInput { - start?: Maybe; - end?: Maybe; -} - -export interface SortTimelineInput { - columnId?: Maybe; - sortDirection?: Maybe; -} - -export interface TimelineInput { - columns?: Maybe; - dataProviders?: Maybe; - dataViewId?: Maybe; - description?: Maybe; - eqlOptions?: Maybe; - eventType?: Maybe; - excludedRowRendererIds?: Maybe; - filters?: Maybe; - kqlMode?: Maybe; - kqlQuery?: Maybe; - indexNames?: Maybe; - title?: Maybe; - templateTimelineId?: Maybe; - templateTimelineVersion?: Maybe; - timelineType?: Maybe; - dateRange?: Maybe; - savedQueryId?: Maybe; - sort?: Maybe; - status?: Maybe; - savedSearchId: Maybe; -} - export enum FlowDirection { uniDirectional = 'uniDirectional', biDirectional = 'biDirectional', diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 738ff3369bcc0..665fa81f19749 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -17,6 +17,7 @@ import type { CopyTimelineResponse, GetDraftTimelinesResponse, GetTimelinesRequestQuery, + SavedTimeline, } from '../../../common/api/timeline'; import { ImportTimelineResult, @@ -49,10 +50,9 @@ import type { ImportDataProps, ImportDataResponse, } from '../../detection_engine/rule_management/logic'; -import type { TimelineInput } from '../../../common/search_strategy'; interface RequestPostTimeline { - timeline: TimelineInput; + timeline: SavedTimeline; signal?: AbortSignal; } diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts index 7aa7770d560c3..3c8bcf4b55f58 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.test.ts @@ -175,7 +175,7 @@ describe('Timeline save middleware', () => { }); describe('#convertTimelineAsInput ', () => { - test('should return a TimelineInput instead of TimelineModel ', () => { + test('should return a SavedTimeline instead of TimelineModel ', () => { const columns: TimelineModel['columns'] = [ { columnHeaderType: 'not-filtered', diff --git a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts index 32ec25396c19a..58e8aced4470b 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/middlewares/timeline_save.ts @@ -37,8 +37,8 @@ import { TimelineStatusEnum, TimelineTypeEnum } from '../../../../common/api/tim import type { TimelineErrorResponse, PersistTimelineResponse, + SavedTimeline, } from '../../../../common/api/timeline'; -import type { TimelineInput } from '../../../../common/search_strategy'; import type { TimelineModel } from '../model'; import type { ColumnHeaderOptions } from '../../../../common/types/timeline'; import { refreshTimelines } from './helpers'; @@ -156,7 +156,7 @@ export const saveTimelineMiddleware: (kibana: CoreStart) => Middleware<{}, State return ret; }; -const timelineInput: TimelineInput = { +const timelineInput: SavedTimeline = { columns: null, dataProviders: null, dataViewId: null, @@ -182,8 +182,8 @@ const timelineInput: TimelineInput = { export const convertTimelineAsInput = ( timeline: TimelineModel, timelineTimeRange: inputsModel.TimeRange -): TimelineInput => - Object.keys(timelineInput).reduce((acc, key) => { +): SavedTimeline => + Object.keys(timelineInput).reduce((acc, key) => { if (has(key, timeline)) { if (key === 'kqlQuery') { return set(`${key}.filterQuery`, get(`${key}.filterQuery`, timeline), acc); diff --git a/x-pack/test/security_solution_ftr/services/timeline/index.ts b/x-pack/test/security_solution_ftr/services/timeline/index.ts index 42ceecbbdb683..8195f63ffc246 100644 --- a/x-pack/test/security_solution_ftr/services/timeline/index.ts +++ b/x-pack/test/security_solution_ftr/services/timeline/index.ts @@ -12,8 +12,8 @@ import { DeleteTimelinesResponse, GetDraftTimelinesResponse, PatchTimelineResponse, + SavedTimeline, } from '@kbn/security-solution-plugin/common/api/timeline'; -import { TimelineInput } from '@kbn/security-solution-plugin/common/search_strategy'; import moment from 'moment'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { FtrService } from '../../../functional/ftr_provider_context'; @@ -75,7 +75,7 @@ export class TimelineTestService extends FtrService { const { savedObjectId: timelineId, version } = createdTimeline; - const timelineUpdate: TimelineInput = { + const timelineUpdate: SavedTimeline = { title, // Set date range to the last 1 year dateRange: { @@ -83,7 +83,7 @@ export class TimelineTestService extends FtrService { end: moment().toISOString(), // Not sure why `start`/`end` are defined as numbers in the type, but looking at the // UI's use of it, I can see they are being set to strings, so I'm forcing a cast here - } as unknown as TimelineInput['dateRange'], + } as unknown as SavedTimeline['dateRange'], // Not sure why, but the following fields are not in the created timeline, which causes // the timeline to not be able to pull in the event for display @@ -111,7 +111,7 @@ export class TimelineTestService extends FtrService { async updateTimeline( timelineId: string, - updates: TimelineInput, + updates: SavedTimeline, version: string ): Promise { return await this.supertest From d96a1de2aacd21fc697f7eed0f1730c1dfe40983 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 27 Sep 2024 14:06:06 +0200 Subject: [PATCH 67/73] add types to clean draft timeline route --- .../routes/draft_timelines/clean_draft_timelines/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts index 6c3e82805ca26..6515817f28e11 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts @@ -6,6 +6,7 @@ */ import { v4 as uuidv4 } from 'uuid'; +import type { IKibanaResponse } from '@kbn/core-http-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; @@ -20,6 +21,7 @@ import { persistTimeline, } from '../../../saved_object/timelines'; import { draftTimelineDefaults } from '../../../utils/default_timeline'; +import type { CleanDraftTimelinesResponse } from '../../../../../../common/api/timeline'; import { CleanDraftTimelinesRequestBody, TimelineTypeEnum, @@ -41,7 +43,7 @@ export const cleanDraftTimelinesRoute = (router: SecuritySolutionPluginRouter) = }, version: '2023-10-31', }, - async (context, request, response) => { + async (context, request, response): Promise> => { const frameworkRequest = await buildFrameworkRequest(context, request); const siemResponse = buildSiemResponse(response); From c4de6dfa85068643aad5785c65f419114ee347f9 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 30 Sep 2024 14:48:24 +0200 Subject: [PATCH 68/73] remove servers prop from yaml files --- .../clean_draft_timelines_route.schema.yaml | 7 ------- .../timeline/copy_timeline/copy_timeline_route.schema.yaml | 7 ------- .../create_timelines/create_timelines_route.schema.yaml | 7 ------- .../api/timeline/delete_note/delete_note_route.schema.yaml | 7 ------- .../delete_timelines/delete_timelines_route.schema.yaml | 7 ------- .../export_timelines/export_timelines_route.schema.yaml | 7 ------- .../get_draft_timelines_route.schema.yaml | 7 ------- .../api/timeline/get_notes/get_notes_route.schema.yaml | 7 ------- .../timeline/get_timeline/get_timeline_route.schema.yaml | 7 ------- .../timeline/get_timelines/get_timelines_route.schema.yaml | 7 ------- .../import_timelines/import_timelines_route.schema.yaml | 7 ------- .../install_prepackaged_timelines_route.schema.yaml | 7 ------- .../patch_timelines/patch_timeline_route.schema.yaml | 7 ------- .../persist_favorite/persist_favorite_route.schema.yaml | 7 ------- .../timeline/persist_note/persist_note_route.schema.yaml | 7 ------- .../timeline/pinned_events/pinned_events_route.schema.yaml | 7 ------- .../resolve_timeline/resolve_timeline_route.schema.yaml | 7 ------- 17 files changed, 119 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml index 4dd0760645105..7ff1e397c1d18 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/clean_draft_timelines/clean_draft_timelines_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Draft Timeline API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/_draft: post: diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml index 3da337a7d471f..f4d4b8a1c2ec1 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Copy Timeline API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/_copy: get: diff --git a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml index f2a59d1ab0d29..8f369fde6e9e9 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/create_timelines/create_timelines_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/timeline-api-create.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline: post: diff --git a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml index 380029bff8070..e79cb9aab65ac 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/delete_note/delete_note_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Notes API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/note: delete: diff --git a/x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.schema.yaml index 7a0a168747d47..bb6674fa65877 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/delete_timelines/delete_timelines_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/timeline-api-delete.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline: delete: diff --git a/x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.schema.yaml index 44ef7d0f3abe0..24387adf1f2a5 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/export_timelines/export_timelines_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/timeline-api-import.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/_export: post: diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml index 7dd424a5e2dec..4a8af1c77f40d 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_draft_timelines/get_draft_timelines_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Get Draft Timelines API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/_draft: get: diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml index 5942fd76c5d51..793eeac5e7c71 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_notes/get_notes_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Notes API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/note: get: diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml index a954b89b04290..ff555bfbf34ff 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/_get_timeline_or_timeline_template_by_savedobjectid.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline: get: diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml index 7d83f60af3e02..36a7b853b3823 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timelines/get_timelines_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/timeline-api-get.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timelines: get: diff --git a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml index 0079fe297e786..d0d2691f2ac7e 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/import_timelines/import_timelines_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/timeline-api-import.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/_import: post: diff --git a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml index 7682e890b6b16..876bf499e385b 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Install Prepackaged Timelines API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/_prepackaged: post: diff --git a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml index e8dfa8bf4b992..6b1c05d32995c 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/patch_timelines/patch_timeline_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Patch Timeline API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline: patch: diff --git a/x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.schema.yaml index 9ad4d03901d70..3a57dd066d3b3 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/persist_favorite/persist_favorite_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Favorite API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/_favorite: patch: diff --git a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml index 4ca14d2b15b13..640e75171c613 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/persist_note/persist_note_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/timeline-api-update.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/note: patch: diff --git a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml index 4ef83ebe04183..3b697e957ad89 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/pinned_events/pinned_events_route.schema.yaml @@ -5,13 +5,6 @@ info: externalDocs: url: https://www.elastic.co/guide/en/security/current/_pin_an_event_to_an_existing_timeline.html description: Documentation -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/pinned_event: patch: diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml index c4e3dcaae0887..5ec0e942df8d8 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml @@ -2,13 +2,6 @@ openapi: 3.0.0 info: title: Elastic Security - Timeline - Resolve Timeline API version: '2023-10-31' -servers: - - url: 'http://{kibana_host}:{port}' - variables: - kibana_host: - default: localhost - port: - default: '5601' paths: /api/timeline/resolve: get: From dd48e1a96a4cfe1a5001053f3231a8d0cc4f3e6f Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 30 Sep 2024 14:50:58 +0200 Subject: [PATCH 69/73] remove full stops from summary --- .../api/timeline/copy_timeline/copy_timeline_route.schema.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml index f4d4b8a1c2ec1..743de4c334fe5 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.schema.yaml @@ -8,7 +8,7 @@ paths: x-labels: [serverless, ess] x-codegen-enabled: true operationId: CopyTimeline - summary: Copies timeline or timeline template. + summary: Copies timeline or timeline template description: | Copies and returns a timeline or timeline template. tags: From bd68dc7bace505a7debb4fd8d91f72d3c48d1971 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 30 Sep 2024 14:56:46 +0200 Subject: [PATCH 70/73] make sure the schema only accepts empty objects --- .../api/timeline/get_timeline/get_timeline_route.schema.yaml | 1 + .../timeline/resolve_timeline/resolve_timeline_route.schema.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml index ff555bfbf34ff..9b5d3fedfd59e 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.schema.yaml @@ -43,3 +43,4 @@ paths: getOneTimeline: $ref: '../model/components.schema.yaml#/components/schemas/TimelineResponse' - type: object + additionalProperties: false diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml index 5ec0e942df8d8..b06969e28cad4 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.schema.yaml @@ -35,6 +35,7 @@ paths: data: $ref: '../model/components.schema.yaml#/components/schemas/ResolvedTimeline' - type: object + additionalProperties: false '400': description: The request is missing parameters From 746a1acdb507c895dba32b5c64c9bcb633faad48 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 30 Sep 2024 15:08:59 +0200 Subject: [PATCH 71/73] simplify the expression --- .../server/lib/timeline/routes/timelines/get_timelines/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts index 7fcb8824b5b32..52995efcf4be1 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts @@ -40,7 +40,7 @@ export const getTimelinesRoute = (router: SecuritySolutionPluginRouter) => { async (context, request, response): Promise> => { try { const frameworkRequest = await buildFrameworkRequest(context, request); - const onlyUserFavorite = request.query?.only_user_favorite === 'true' ? true : false; + const onlyUserFavorite = request.query?.only_user_favorite === 'true'; const pageSize = request.query?.page_size ? parseInt(request.query.page_size, 10) : null; const pageIndex = request.query?.page_index ? parseInt(request.query.page_index, 10) From 3e192bb265d8b7f3689d2fe72542f0a61db62472 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 30 Sep 2024 15:17:36 +0200 Subject: [PATCH 72/73] move zod_errors --- .github/CODEOWNERS | 1 + .../security_solution/common/{utils => timelines}/zod_errors.ts | 0 .../security_solution/public/timelines/containers/api.ts | 2 +- .../import_timelines/create_timelines_stream_from_ndjson.ts | 2 +- 4 files changed, 3 insertions(+), 2 deletions(-) rename x-pack/plugins/security_solution/common/{utils => timelines}/zod_errors.ts (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7f8f48e638148..19eb7055895ab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1531,6 +1531,7 @@ x-pack/test/security_solution_api_integration/test_suites/sources @elastic/secur x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout @elastic/security-threat-hunting-investigations x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/common/timelines @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/common/components/alerts_viewer @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_action @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/common/components/event_details @elastic/security-threat-hunting-investigations diff --git a/x-pack/plugins/security_solution/common/utils/zod_errors.ts b/x-pack/plugins/security_solution/common/timelines/zod_errors.ts similarity index 100% rename from x-pack/plugins/security_solution/common/utils/zod_errors.ts rename to x-pack/plugins/security_solution/common/timelines/zod_errors.ts diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 665fa81f19749..fa006293719d5 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -44,7 +44,7 @@ import { import { KibanaServices } from '../../common/lib/kibana'; import { ToasterError } from '../../common/components/toasters'; -import { parseOrThrowErrorFactory } from '../../../common/utils/zod_errors'; +import { parseOrThrowErrorFactory } from '../../../common/timelines/zod_errors'; import type { ExportDocumentsProps, ImportDataProps, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts index 6eb6ea6e7f376..83a25ee38cd63 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/import_timelines/create_timelines_stream_from_ndjson.ts @@ -16,7 +16,7 @@ import { import type { ImportTimelineResponse } from './types'; import { ImportTimelines } from '../../../../../../common/api/timeline'; -import { parseOrThrowErrorFactory } from '../../../../../../common/utils/zod_errors'; +import { parseOrThrowErrorFactory } from '../../../../../../common/timelines/zod_errors'; const createPlainError = (message: string) => new Error(message); const parseOrThrow = parseOrThrowErrorFactory(createPlainError); From 6ffce63744c06da782e3dec09654ee8b1fb8925e Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 30 Sep 2024 15:22:54 +0200 Subject: [PATCH 73/73] generate docs & OAS --- oas_docs/output/kibana.serverless.staging.yaml | 8 +++++--- oas_docs/output/kibana.staging.yaml | 8 +++++--- .../api/timeline/get_timeline/get_timeline_route.gen.ts | 2 +- .../resolve_timeline/resolve_timeline_route.gen.ts | 2 +- ...y_solution_timeline_api_2023_10_31.bundled.schema.yaml | 8 +++++--- ...y_solution_timeline_api_2023_10_31.bundled.schema.yaml | 8 +++++--- 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index f6937f8f49b45..f4b413e01e7dc 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16369,7 +16369,8 @@ paths: - getOneTimeline required: - data - - type: object + - additionalProperties: false + type: object description: Indicates that the (template) Timeline was found and returned. summary: Get Timeline or Timeline template details tags: @@ -16514,7 +16515,7 @@ paths: $ref: >- #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates that the timeline has been successfully copied. - summary: Copies timeline or timeline template. + summary: Copies timeline or timeline template tags: - Security Timeline API - access:securitySolution @@ -16903,7 +16904,8 @@ paths: #/components/schemas/Security_Timeline_API_ResolvedTimeline required: - data - - type: object + - additionalProperties: false + type: object description: The (template) Timeline has been found '400': description: The request is missing parameters diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 7facd79fd995c..c1e70788cd789 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -20458,7 +20458,8 @@ paths: - getOneTimeline required: - data - - type: object + - additionalProperties: false + type: object description: Indicates that the (template) Timeline was found and returned. summary: Get Timeline or Timeline template details tags: @@ -20603,7 +20604,7 @@ paths: $ref: >- #/components/schemas/Security_Timeline_API_PersistTimelineResponse description: Indicates that the timeline has been successfully copied. - summary: Copies timeline or timeline template. + summary: Copies timeline or timeline template tags: - Security Timeline API - access:securitySolution @@ -20992,7 +20993,8 @@ paths: #/components/schemas/Security_Timeline_API_ResolvedTimeline required: - data - - type: object + - additionalProperties: false + type: object description: The (template) Timeline has been found '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts index 92a3d5443f598..7a41788077524 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/get_timeline/get_timeline_route.gen.ts @@ -38,5 +38,5 @@ export const GetTimelineResponse = z.union([ getOneTimeline: TimelineResponse, }), }), - z.object({}), + z.object({}).strict(), ]); diff --git a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts index 28f46f193ce74..d4c79eec50b26 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/resolve_timeline/resolve_timeline_route.gen.ts @@ -36,5 +36,5 @@ export const ResolveTimelineResponse = z.union([ z.object({ data: ResolvedTimeline, }), - z.object({}), + z.object({}).strict(), ]); diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index b8db839779fb6..e36af57a2b3e9 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -280,7 +280,8 @@ paths: - getOneTimeline required: - data - - type: object + - additionalProperties: false + type: object description: Indicates that the (template) Timeline was found and returned. summary: Get Timeline or Timeline template details tags: @@ -422,7 +423,7 @@ paths: schema: $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates that the timeline has been successfully copied. - summary: Copies timeline or timeline template. + summary: Copies timeline or timeline template tags: - Security Timeline API - access:securitySolution @@ -804,7 +805,8 @@ paths: $ref: '#/components/schemas/ResolvedTimeline' required: - data - - type: object + - additionalProperties: false + type: object description: The (template) Timeline has been found '400': description: The request is missing parameters diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index f42cab0247072..818b83d7b85dd 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -280,7 +280,8 @@ paths: - getOneTimeline required: - data - - type: object + - additionalProperties: false + type: object description: Indicates that the (template) Timeline was found and returned. summary: Get Timeline or Timeline template details tags: @@ -422,7 +423,7 @@ paths: schema: $ref: '#/components/schemas/PersistTimelineResponse' description: Indicates that the timeline has been successfully copied. - summary: Copies timeline or timeline template. + summary: Copies timeline or timeline template tags: - Security Timeline API - access:securitySolution @@ -804,7 +805,8 @@ paths: $ref: '#/components/schemas/ResolvedTimeline' required: - data - - type: object + - additionalProperties: false + type: object description: The (template) Timeline has been found '400': description: The request is missing parameters