Skip to content

Commit

Permalink
[Security Solution] Add versioned router for timelines #7144 (#166729)
Browse files Browse the repository at this point in the history
## Summary

This PR introduces versioned router for timeline apis, as per
elastic/security-team#7144
  • Loading branch information
lgestc authored Oct 3, 2023
1 parent 5b627f0 commit d1e13ef
Show file tree
Hide file tree
Showing 19 changed files with 710 additions and 607 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ describe('persistTimeline', () => {
body: JSON.stringify({
timelineType: initialDraftTimeline.timelineType,
}),
version: '2023-10-31',
});
});

Expand Down Expand Up @@ -346,6 +347,7 @@ describe('importTimelines', () => {
headers: { 'Content-Type': undefined },
body: new FormData(),
signal: undefined,
version: '2023-10-31',
})
);
});
Expand Down Expand Up @@ -377,6 +379,7 @@ describe('exportSelectedTimeline', () => {
method: 'POST',
query: { file_name: 'timelines_export.ndjson' },
signal: {},
version: '2023-10-31',
});
});
});
Expand All @@ -400,6 +403,7 @@ describe('getDraftTimeline', () => {
test('should pass correct args to KibanaServices', () => {
expect(getMock).toBeCalledWith('/api/timeline/_draft', {
query: timelineType,
version: '2023-10-31',
});
});
});
Expand All @@ -425,6 +429,7 @@ describe('cleanDraftTimeline', () => {

expect(postMock).toBeCalledWith('/api/timeline/_draft', {
body: JSON.stringify(args),
version: '2023-10-31',
});
});

Expand All @@ -439,6 +444,7 @@ describe('cleanDraftTimeline', () => {

expect(postMock).toBeCalledWith('/api/timeline/_draft', {
body: JSON.stringify(args),
version: '2023-10-31',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { pipe } from 'fp-ts/lib/pipeable';
import { isEmpty } from 'lodash';

import { throwErrors } from '@kbn/cases-plugin/common';

import type {
TimelineResponse,
TimelineErrorResponse,
Expand Down Expand Up @@ -119,6 +120,7 @@ const postTimeline = async ({
const response = await KibanaServices.get().http.post<TimelineResponse>(TIMELINE_URL, {
method: 'POST',
body: requestBody,
version: '2023-10-31',
});

return decodeTimelineResponse(response);
Expand All @@ -140,6 +142,7 @@ const patchTimeline = async ({
response = await KibanaServices.get().http.patch<TimelineResponse>(TIMELINE_URL, {
method: 'PATCH',
body: requestBody,
version: '2023-10-31',
});
} catch (err) {
// For Future developer
Expand Down Expand Up @@ -228,6 +231,7 @@ export const importTimelines = async ({
headers: { 'Content-Type': undefined },
body: formData,
signal,
version: '2023-10-31',
});
};

Expand All @@ -249,6 +253,7 @@ export const exportSelectedTimeline = ({
file_name: filename,
},
signal,
version: '2023-10-31',
});
};

Expand All @@ -261,6 +266,7 @@ export const getDraftTimeline = async ({
query: {
timelineType,
},
version: '2023-10-31',
});

return decodeTimelineResponse(response);
Expand Down Expand Up @@ -293,6 +299,7 @@ export const cleanDraftTimeline = async ({
}
const response = await KibanaServices.get().http.post<TimelineResponse>(TIMELINE_DRAFT_URL, {
body: requestBody,
version: '2023-10-31',
});

return decodeTimelineResponse(response);
Expand All @@ -301,7 +308,9 @@ export const cleanDraftTimeline = async ({
export const installPrepackedTimelines = async (): Promise<ImportTimelineResultSchema> => {
const response = await KibanaServices.get().http.post<ImportTimelineResultSchema>(
TIMELINE_PREPACKAGED_URL,
{}
{
version: '2023-10-31',
}
);

return decodePrepackedTimelineResponse(response);
Expand All @@ -312,6 +321,7 @@ export const getTimeline = async (id: string) => {
query: {
id,
},
version: '2023-10-31',
});

return decodeSingleTimelineResponse(response);
Expand All @@ -324,6 +334,7 @@ export const resolveTimeline = async (id: string) => {
query: {
id,
},
version: '2023-10-31',
}
);

Expand All @@ -335,6 +346,7 @@ export const getTimelineTemplate = async (templateTimelineId: string) => {
query: {
template_timeline_id: templateTimelineId,
},
version: '2023-10-31',
});

return decodeSingleTimelineResponse(response);
Expand All @@ -354,6 +366,7 @@ export const getAllTimelines = async (args: GetTimelinesArgs, abortSignal: Abort
...(args.timelineType ? { timeline_type: args.timelineType } : {}),
},
signal: abortSignal,
version: '2023-10-31',
});

return decodeAllTimelinesResponse(response);
Expand Down Expand Up @@ -388,6 +401,7 @@ export const persistFavorite = async ({
{
method: 'PATCH',
body: requestBody,
version: '2023-10-31',
}
);

Expand All @@ -407,6 +421,7 @@ export const deleteTimelinesByIds = async (savedObjectIds: string[]) => {
const response = await KibanaServices.get().http.delete<boolean>(TIMELINE_URL, {
method: 'DELETE',
body: requestBody,
version: '2023-10-31',
});
return response;
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const persistNote = async ({
const response = await KibanaServices.get().http.patch<Note[]>(NOTE_URL, {
method: 'PATCH',
body: requestBody,
version: '2023-10-31',
});
return response;
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const persistPinnedEvent = async ({
const response = await KibanaServices.get().http.patch<PinnedEvent | null>(PINNED_EVENT_URL, {
method: 'PATCH',
body: requestBody,
version: '2023-10-31',
});
return response;
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,81 +29,86 @@ export const cleanDraftTimelinesRoute = (
_: ConfigType,
security: SetupPlugins['security']
) => {
router.post(
{
router.versioned
.post({
path: TIMELINE_DRAFT_URL,
validate: {
body: buildRouteValidationWithExcess(cleanDraftTimelineSchema),
},
options: {
tags: ['access:securitySolution'],
},
},
async (context, request, response) => {
const frameworkRequest = await buildFrameworkRequest(context, security, request);
const siemResponse = buildSiemResponse(response);
access: 'public',
})
.addVersion(
{
validate: {
request: { body: buildRouteValidationWithExcess(cleanDraftTimelineSchema) },
},
version: '2023-10-31',
},
async (context, request, response) => {
const frameworkRequest = await buildFrameworkRequest(context, security, request);
const siemResponse = buildSiemResponse(response);

try {
const {
timeline: [draftTimeline],
} = await getDraftTimeline(frameworkRequest, request.body.timelineType);
try {
const {
timeline: [draftTimeline],
} = await getDraftTimeline(frameworkRequest, request.body.timelineType);

if (draftTimeline?.savedObjectId) {
await resetTimeline(
frameworkRequest,
[draftTimeline.savedObjectId],
request.body.timelineType
);
const cleanedDraftTimeline = await getTimeline(
frameworkRequest,
draftTimeline.savedObjectId
);
if (draftTimeline?.savedObjectId) {
await resetTimeline(
frameworkRequest,
[draftTimeline.savedObjectId],
request.body.timelineType
);
const cleanedDraftTimeline = await getTimeline(
frameworkRequest,
draftTimeline.savedObjectId
);

return response.ok({
body: {
data: {
persistTimeline: {
timeline: cleanedDraftTimeline,
return response.ok({
body: {
data: {
persistTimeline: {
timeline: cleanedDraftTimeline,
},
},
},
},
});
}
const templateTimelineData =
request.body.timelineType === TimelineType.template
? {
timelineType: request.body.timelineType,
templateTimelineId: uuidv4(),
templateTimelineVersion: 1,
}
: {};
});
}
const templateTimelineData =
request.body.timelineType === TimelineType.template
? {
timelineType: request.body.timelineType,
templateTimelineId: uuidv4(),
templateTimelineVersion: 1,
}
: {};

const newTimelineResponse = await persistTimeline(frameworkRequest, null, null, {
...draftTimelineDefaults,
...templateTimelineData,
});
const newTimelineResponse = await persistTimeline(frameworkRequest, null, null, {
...draftTimelineDefaults,
...templateTimelineData,
});

if (newTimelineResponse.code === 200) {
return response.ok({
body: {
data: {
persistTimeline: {
timeline: newTimelineResponse.timeline,
if (newTimelineResponse.code === 200) {
return response.ok({
body: {
data: {
persistTimeline: {
timeline: newTimelineResponse.timeline,
},
},
},
},
});
}
});
}

return response.ok({});
} catch (err) {
const error = transformError(err);
return response.ok({});
} catch (err) {
const error = transformError(err);

return siemResponse.error({
body: error.message,
statusCode: error.statusCode,
});
return siemResponse.error({
body: error.message,
statusCode: error.statusCode,
});
}
}
}
);
);
};
Loading

0 comments on commit d1e13ef

Please sign in to comment.