Skip to content

Commit

Permalink
[Security Solution] Saving is not working if hitting "favorites butto…
Browse files Browse the repository at this point in the history
…n" beforehand (#88642) (#90132)

* fix favorites for templates

* fix integration test

* fix integration test

* fix event details request

* handle data when searchstrategy is still running

Co-authored-by: Kibana Machine <[email protected]>

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
angorayc and kibanamachine authored Feb 3, 2021
1 parent cc3eb8e commit ca3fe07
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 11 deletions.
42 changes: 42 additions & 0 deletions x-pack/plugins/security_solution/public/graphql/introspection.json
Original file line number Diff line number Diff line change
Expand Up @@ -3365,6 +3365,24 @@
"description": "",
"type": { "kind": "SCALAR", "name": "ID", "ofType": null },
"defaultValue": null
},
{
"name": "templateTimelineId",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"defaultValue": null
},
{
"name": "templateTimelineVersion",
"description": "",
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
"defaultValue": null
},
{
"name": "timelineType",
"description": "",
"type": { "kind": "ENUM", "name": "TimelineType", "ofType": null },
"defaultValue": null
}
],
"type": {
Expand Down Expand Up @@ -4149,6 +4167,30 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "templateTimelineId",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "templateTimelineVersion",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "timelineType",
"description": "",
"args": [],
"type": { "kind": "ENUM", "name": "TimelineType", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "version",
"description": "",
Expand Down
21 changes: 21 additions & 0 deletions x-pack/plugins/security_solution/public/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,12 @@ export interface ResponseFavoriteTimeline {

savedObjectId: string;

templateTimelineId?: Maybe<string>;

templateTimelineVersion?: Maybe<number>;

timelineType?: Maybe<TimelineType>;

version: string;

favorite?: Maybe<FavoriteTimelineResult[]>;
Expand Down Expand Up @@ -1691,6 +1697,12 @@ export interface PersistTimelineMutationArgs {
}
export interface PersistFavoriteMutationArgs {
timelineId?: Maybe<string>;

templateTimelineId?: Maybe<string>;

templateTimelineVersion?: Maybe<number>;

timelineType?: Maybe<TimelineType>;
}
export interface DeleteTimelineMutationArgs {
id: string[];
Expand Down Expand Up @@ -2096,6 +2108,9 @@ export namespace DeleteTimelineMutation {
export namespace PersistTimelineFavoriteMutation {
export type Variables = {
timelineId?: Maybe<string>;
templateTimelineId?: Maybe<string>;
templateTimelineVersion?: Maybe<number>;
timelineType: TimelineType;
};

export type Mutation = {
Expand All @@ -2112,6 +2127,12 @@ export namespace PersistTimelineFavoriteMutation {
version: string;

favorite: Maybe<Favorite[]>;

templateTimelineId: Maybe<string>;

templateTimelineVersion: Maybe<number>;

timelineType: Maybe<TimelineType>;
};

export type Favorite = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { timelineActions } from '../../../store/timeline';
import { NOTE_CONTENT_CLASS_NAME } from '../../timeline/body/helpers';
import * as i18n from './translations';
import { TimelineTabs } from '../../../../../common/types/timeline';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { sourcererSelectors } from '../../../../common/store';

export const NotePreviewsContainer = styled.section`
padding-top: ${({ theme }) => `${theme.eui.euiSizeS}`};
Expand All @@ -35,19 +37,24 @@ const ToggleEventDetailsButtonComponent: React.FC<ToggleEventDetailsButtonProps>
timelineId,
}) => {
const dispatch = useDispatch();
const existingIndexNamesSelector = useMemo(
() => sourcererSelectors.getAllExistingIndexNamesSelector(),
[]
);
const existingIndexNames = useDeepEqualSelector<string[]>(existingIndexNamesSelector);

const handleClick = useCallback(() => {
dispatch(
timelineActions.toggleExpandedEvent({
tabType: TimelineTabs.notes,
timelineId,
event: {
eventId,
// we don't store yet info about event index name in note
indexName: '',
indexName: existingIndexNames.join(','),
},
})
);
}, [dispatch, eventId, timelineId]);
}, [dispatch, eventId, existingIndexNames, timelineId]);

return (
<EuiButtonIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,28 @@
import gql from 'graphql-tag';

export const persistTimelineFavoriteMutation = gql`
mutation PersistTimelineFavoriteMutation($timelineId: ID) {
persistFavorite(timelineId: $timelineId) {
mutation PersistTimelineFavoriteMutation(
$timelineId: ID
$templateTimelineId: String
$templateTimelineVersion: Int
$timelineType: TimelineType!
) {
persistFavorite(
timelineId: $timelineId
templateTimelineId: $templateTimelineId
templateTimelineVersion: $templateTimelineVersion
timelineType: $timelineType
) {
savedObjectId
version
favorite {
fullName
userName
favoriteDate
}
templateTimelineId
templateTimelineVersion
timelineType
}
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { refetchQueries } from './refetch_queries';
import { myEpicTimelineId } from './my_epic_timeline_id';
import { ActionTimeline, TimelineById } from './types';
import { inputsModel } from '../../../common/store/inputs';
import { TimelineType } from '../../../../common/types/timeline';

export const timelineFavoriteActionsType = [updateIsFavorite.type];

Expand All @@ -48,6 +49,9 @@ export const epicPersistTimelineFavorite = (
fetchPolicy: 'no-cache',
variables: {
timelineId: myEpicTimelineId.getTimelineId(),
templateTimelineId: timeline[action.payload.id].templateTimelineId,
templateTimelineVersion: timeline[action.payload.id].templateTimelineVersion,
timelineType: timeline[action.payload.id].timelineType ?? TimelineType.default,
},
refetchQueries,
})
Expand Down Expand Up @@ -96,6 +100,12 @@ export const epicPersistTimelineFavorite = (
myEpicTimelineId.setTimelineVersion(
updatedTimeline[get('payload.id', checkAction)].version
);
myEpicTimelineId.setTemplateTimelineId(
updatedTimeline[get('payload.id', checkAction)].templateTimelineId
);
myEpicTimelineId.setTemplateTimelineVersion(
updatedTimeline[get('payload.id', checkAction)].templateTimelineVersion
);
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { AppResolverWithFields, AppResolverOf } from '../../lib/framework';
import { MutationResolvers, QueryResolvers } from '../types';
import { Timeline } from '../../lib/timeline/saved_object';
import { TimelineType } from '../../../common/types/timeline';

export type QueryTimelineResolver = AppResolverOf<QueryResolvers.GetOneTimelineResolver>;

Expand Down Expand Up @@ -63,7 +64,13 @@ export const createTimelineResolvers = (
return true;
},
async persistFavorite(root, args, { req }) {
return libs.timeline.persistFavorite(req, args.timelineId || null);
return libs.timeline.persistFavorite(
req,
args.timelineId || null,
args.templateTimelineId || null,
args.templateTimelineVersion || null,
args.timelineType || TimelineType.default
);
},
async persistTimeline(root, args, { req }) {
return libs.timeline.persistTimeline(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ export const timelineSchema = gql`
code: Float
message: String
savedObjectId: String!
templateTimelineId: String
templateTimelineVersion: Int
timelineType: TimelineType
version: String!
favorite: [FavoriteTimelineResult!]
}
Expand All @@ -320,7 +323,7 @@ export const timelineSchema = gql`
extend type Mutation {
"Persists a timeline"
persistTimeline(id: ID, version: String, timeline: TimelineInput!): ResponseTimeline!
persistFavorite(timelineId: ID): ResponseFavoriteTimeline!
persistFavorite(timelineId: ID, templateTimelineId: String, templateTimelineVersion: Int, timelineType: TimelineType): ResponseFavoriteTimeline!
deleteTimeline(id: [ID!]!): Boolean!
}
`;
39 changes: 39 additions & 0 deletions x-pack/plugins/security_solution/server/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,12 @@ export interface ResponseFavoriteTimeline {

savedObjectId: string;

templateTimelineId?: Maybe<string>;

templateTimelineVersion?: Maybe<number>;

timelineType?: Maybe<TimelineType>;

version: string;

favorite?: Maybe<FavoriteTimelineResult[]>;
Expand Down Expand Up @@ -1693,6 +1699,12 @@ export interface PersistTimelineMutationArgs {
}
export interface PersistFavoriteMutationArgs {
timelineId?: Maybe<string>;

templateTimelineId?: Maybe<string>;

templateTimelineVersion?: Maybe<number>;

timelineType?: Maybe<TimelineType>;
}
export interface DeleteTimelineMutationArgs {
id: string[];
Expand Down Expand Up @@ -3419,6 +3431,12 @@ export namespace MutationResolvers {
> = Resolver<R, Parent, TContext, PersistFavoriteArgs>;
export interface PersistFavoriteArgs {
timelineId?: Maybe<string>;

templateTimelineId?: Maybe<string>;

templateTimelineVersion?: Maybe<number>;

timelineType?: Maybe<TimelineType>;
}

export type DeleteTimelineResolver<R = boolean, Parent = {}, TContext = SiemContext> = Resolver<
Expand Down Expand Up @@ -3492,6 +3510,12 @@ export namespace ResponseFavoriteTimelineResolvers {

savedObjectId?: SavedObjectIdResolver<string, TypeParent, TContext>;

templateTimelineId?: TemplateTimelineIdResolver<Maybe<string>, TypeParent, TContext>;

templateTimelineVersion?: TemplateTimelineVersionResolver<Maybe<number>, TypeParent, TContext>;

timelineType?: TimelineTypeResolver<Maybe<TimelineType>, TypeParent, TContext>;

version?: VersionResolver<string, TypeParent, TContext>;

favorite?: FavoriteResolver<Maybe<FavoriteTimelineResult[]>, TypeParent, TContext>;
Expand All @@ -3512,6 +3536,21 @@ export namespace ResponseFavoriteTimelineResolvers {
Parent = ResponseFavoriteTimeline,
TContext = SiemContext
> = Resolver<R, Parent, TContext>;
export type TemplateTimelineIdResolver<
R = Maybe<string>,
Parent = ResponseFavoriteTimeline,
TContext = SiemContext
> = Resolver<R, Parent, TContext>;
export type TemplateTimelineVersionResolver<
R = Maybe<number>,
Parent = ResponseFavoriteTimeline,
TContext = SiemContext
> = Resolver<R, Parent, TContext>;
export type TimelineTypeResolver<
R = Maybe<TimelineType>,
Parent = ResponseFavoriteTimeline,
TContext = SiemContext
> = Resolver<R, Parent, TContext>;
export type VersionResolver<
R = string,
Parent = ResponseFavoriteTimeline,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ export interface Timeline {

persistFavorite: (
request: FrameworkRequest,
timelineId: string | null
timelineId: string | null,
templateTimelineId: string | null,
templateTimelineVersion: number | null,
timelineType: TimelineType
) => Promise<ResponseFavoriteTimeline>;

persistTimeline: (
Expand Down Expand Up @@ -281,7 +284,10 @@ export const getDraftTimeline = async (

export const persistFavorite = async (
request: FrameworkRequest,
timelineId: string | null
timelineId: string | null,
templateTimelineId: string | null,
templateTimelineVersion: number | null,
timelineType: TimelineType
): Promise<ResponseFavoriteTimeline> => {
const userName = request.user?.username ?? UNAUTHENTICATED_USER;
const fullName = request.user?.full_name ?? '';
Expand Down Expand Up @@ -324,14 +330,22 @@ export const persistFavorite = async (
timeline.favorite = [userFavoriteTimeline];
}

const persistResponse = await persistTimeline(request, timelineId, null, timeline);
const persistResponse = await persistTimeline(request, timelineId, null, {
...timeline,
templateTimelineId,
templateTimelineVersion,
timelineType,
});
return {
savedObjectId: persistResponse.timeline.savedObjectId,
version: persistResponse.timeline.version,
favorite:
persistResponse.timeline.favorite != null
? persistResponse.timeline.favorite.filter((fav) => fav.userName === userName)
: [],
templateTimelineId,
templateTimelineVersion,
timelineType,
};
} catch (err) {
if (getOr(null, 'output.statusCode', err) === 403) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,19 @@ export const timelineEventsDetails: SecuritySolutionTimelineFactory<TimelineEven
const inspect = {
dsl: [inspectStringifyObject(buildTimelineDetailsQuery(indexName, eventId, docValueFields))],
};

if (response.isRunning) {
return {
...response,
data: [],
inspect,
};
}

const sourceData = getDataFromSourceHits(_source);
const fieldsData = getDataFromFieldsHits(merge(fields, hitsData));

const data = unionBy('field', fieldsData, sourceData);

return {
...response,
data,
Expand Down
Loading

0 comments on commit ca3fe07

Please sign in to comment.