Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SecuritySolution] Fix behavior of pinnend events and comments on unsaved timelines #178212

Conversation

janmonschke
Copy link
Contributor

@janmonschke janmonschke commented Mar 7, 2024

This PR is the implementation of the results in the discussion around [ADR] 0001 - Saving of timeline-associated saved objects

Summary

As described in #178182, the removal of autosave on timeline resulted in a regression in which pinned events and comments on unsaved timelines are lost.

In this PR, we're re-introducing the previous behavior by saving the timeline when a comment is made / an event is pinned on an unsaved timeline. The timeline will then be auto-saved in a draft state instead of an active state that would persist it permanently.

Fixes #178182

Checklist

@janmonschke janmonschke added release_note:fix Team:Threat Hunting:Investigations Security Solution Investigations Team backport:prev-minor Backport to (8.x) the previous minor version (i.e. one version back from main) labels Mar 7, 2024
@janmonschke janmonschke self-assigned this Mar 7, 2024
@janmonschke janmonschke requested a review from a team as a code owner March 7, 2024 12:53
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-threat-hunting-investigations (Team:Threat Hunting:Investigations)

@PhilippeOberti
Copy link
Contributor

@janmonschke I haven't looked at the code itself yet, but have pulled down the branch and tested locally. While the fix seems to be working just fine, I'm not sure the approach is what I would have done.
It feels a bit weird to have the timeline magically saved when adding comments or notes. I think I would have maybe either:

  • disabled all the features we do not want to be done on an unsaved timeline (so for this PR it would just be disabling the Notes tab and the Add note button). This is the approach I took when I fix a similar issue where users could favorite an unsaved timeline, which makes no sense (see this PR)
  • instead of silently saving, maybe we could show the save modal? That way users wouldn't end up with tons of Untitled timeline timelines like I just did during testing 😆

@janmonschke
Copy link
Contributor Author

@PhilippeOberti Agreed, wdyt about #178525 ?

@janmonschke janmonschke removed this from the 8.14 milestone Mar 12, 2024
@janmonschke janmonschke reopened this Apr 2, 2024
@janmonschke
Copy link
Contributor Author

Reopened this PR and updated/improved the tests.

@janmonschke
Copy link
Contributor Author

@elasticmachine merge upstream

@janmonschke janmonschke requested a review from a team as a code owner April 5, 2024 06:41
const kibanaServer = getService('kibanaServer');
const supertest = getService('supertest');

describe('Draft timeline - Saved Objects', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were no FTR tests for the draft timeline route at all and parts of it were actually broken (see 633b8b6).

@@ -15,7 +15,7 @@ export const persistPinnedEvent = async ({
}: {
eventId: string;
pinnedEventId?: string | null;
timelineId?: string | null;
timelineId: string;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The presence of timelineId is now enforced on the API.

@@ -51,9 +51,6 @@ export const NoteRuntimeType = runtimeTypes.intersection([
noteId: runtimeTypes.string,
version: runtimeTypes.string,
}),
runtimeTypes.partial({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timelineVersion is obsolete now.

@@ -14,10 +14,10 @@ export const pinnedEventIds = unionWithNullType(runtimeTypes.array(runtimeTypes.
export const persistPinnedEventSchema = runtimeTypes.intersection([
runtimeTypes.type({
eventId: runtimeTypes.string,
timelineId: runtimeTypes.string,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, timelineId is not optional anymore

@@ -51,9 +51,6 @@ export const PinnedEventRuntimeType = runtimeTypes.intersection([
version: runtimeTypes.string,
}),
BarePinnedEventType,
runtimeTypes.partial({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here as well, no more need for timelineVersion

@@ -366,13 +366,6 @@ describe('Body', () => {
}).type,
})
);
expect(mockDispatch).toHaveBeenNthCalledWith(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The business logic of automatic pinning of events with a note has been moved to the redux middleware.


const currentTimeline = selectTimelineById(store.getState(), localTimelineId);

// Automatically pin an associated event if it's not pinned yet
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The automatic pin logic moved here

@@ -34,7 +34,7 @@ describe('saved_object', () => {
});

describe('Set create / update time correctly ', () => {
test('Creating a timeline', () => {
test('Creating a note', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a referring to the wrong object in the entire file.

const shallowCopyOfNote = { ...note };
let timelineVersion: string | undefined;

if (note.timelineId == null) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the piece of code that would create a timeline when no timelineId was provided. Which is not needed anymore.

@@ -49,8 +48,7 @@ export const deleteAllPinnedEventsOnTimeline = async (
const savedObjectsClient = (await request.context.core).savedObjects.client;
const options: SavedObjectsFindOptions = {
type: pinnedEventSavedObjectType,
search: timelineId,
searchFields: ['timelineId'],
hasReference: { type: timelineSavedObjectType, id: timelineId },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleting pinned events was actually not working before. There are tests for this in the new draft timeline ftr tests.

Copy link
Contributor

@kqualters-elastic kqualters-elastic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Desk tested this lightly and everything seemed to work as intended, 👍 lgtm

@janmonschke janmonschke enabled auto-merge (squash) April 8, 2024 13:25
@janmonschke
Copy link
Contributor Author

@elasticmachine merge upstream

@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #93 / serverless observability UI Serverless Observability Cases Cases persistable attachments lens visualization adds lens visualization to a new case

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 17.0MB 17.0MB +697.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @janmonschke

@janmonschke janmonschke merged commit 8e9fa4a into elastic:main Apr 8, 2024
37 checks passed
@kibanamachine
Copy link
Contributor

💔 All backports failed

Status Branch Result
8.13 Backport failed because of merge conflicts

Manual backport

To create the backport manually run:

node scripts/backport --pr 178212

Questions ?

Please refer to the Backport tool documentation

@kibanamachine kibanamachine added the backport missing Added to PRs automatically when the are determined to be missing a backport. label Apr 9, 2024
@kibanamachine
Copy link
Contributor

Friendly reminder: Looks like this PR hasn’t been backported yet.
To create automatically backports add the label auto-backport or prevent reminders by adding the backport:skip label.
You can also create backports manually by running node scripts/backport --pr 178212 locally

@janmonschke janmonschke removed backport missing Added to PRs automatically when the are determined to be missing a backport. backport:prev-minor Backport to (8.x) the previous minor version (i.e. one version back from main) labels Apr 11, 2024
@kibanamachine kibanamachine added backport:skip This commit does not require backporting labels Apr 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting release_note:fix Team:Threat Hunting:Investigations Security Solution Investigations Team v8.14.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Security Solution] Comments and pins on unsaved timeline are lost when timeline is not manually saved
7 participants