-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Case] Detection rules for case #88726
[Case] Detection rules for case #88726
Conversation
}; | ||
|
||
const requestsUpdatingTypeField = requests.filter((req) => req.type === CaseType.collection); | ||
const casesAlertTotals = await Promise.all( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
}); | ||
|
||
return subCases.saved_objects.reduce((acc, subCase) => { | ||
// log about the sub cases that we couldn't find |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a Todo
to notify the user about situations where there is an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it's really a TODO to add logging later
let status: CaseStatuses = CaseStatuses.open; | ||
if (alertComment.attributes.associationType === AssociationType.case) { | ||
const id = getID(alertComment, CASE_SAVED_OBJECT); | ||
// We should log if we can't find the status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another log comment. I agree, maybe a parameter sent with the response errors: ['We were unable to retrieve x, y, and z']
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'll add the logging in a follow up PR. I need to pass the plugin's logger around to do it I think.
/** | ||
* This class is a pass through for common case functionality (like creating, get a case). | ||
*/ | ||
export class CaseClientHandler implements CaseClient { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clean 👌🏾
}); | ||
|
||
// An alert cannot be attach to a closed case. | ||
if (query.type === CommentType.alert && myCase.attributes.status === CaseStatuses.closed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to keep this check though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it should be in CommentableCase
now haha.
commentReq: query, | ||
}); | ||
|
||
if (newComment.attributes.type === CommentType.alert && updatedCase.settings.syncAlerts) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not necessary for this PR, but could be helpful to just have all these checks encapsulated in functions like isAlert()
isCollection()
isGeneratedAlert
etc... especially if the criteria for any of these changes in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea. I'll add it to the refactoring list 👍
import { CaseClientGetAlertsResponse } from './alerts/types'; | ||
|
||
export interface CaseClientCreate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More of a question. We seem to be passing in the post and patch request types while the others are defined here? Is there a reason they're separated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that might have been from more of a convenience thing where some parameter types were defined already by the io-ts types and we just pass those fields around where as others don't strictly align with an io-ts type.
}): Promise<NewCommentResp> { | ||
if (commentReq.type === CommentType.alert) { | ||
if (this.status === CaseStatuses.closed) { | ||
throw Boom.badRequest('Alert cannot be attached to a closed case'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore my previous comment about the removed check 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha
if (alert.id) { | ||
const totalAlerts = acc.get(alert.id); | ||
if (totalAlerts !== undefined) { | ||
acc.set(alert.id, totalAlerts + countAlerts(alertsInfo)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can cache countAlerts const alertCount = countAlerts(alertsInfo)
and use that on 105 maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, will update
); | ||
}; | ||
|
||
export const isCommentAlert = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice 👍🏾, this was the idea for all the other types of checks as well that I mentioned earlier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah got it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I see that the type is not used anywhere. Maybe we can remove it.
💚 Build SucceededMetrics [docs]Module Count
Async chunks
Page load bundle
Saved Objects .kibana field count
History
To update your PR or re-run it, just comment with: |
}); | ||
} | ||
|
||
decodeCommentRequest(comment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment for another PR: TypeScript thinks that the comment is of type user
and not alert | user
.
} = await commentableCase.createComment({ createdDate, user: userDetails, commentReq: query }); | ||
|
||
if ( | ||
(newComment.attributes.type === CommentType.alert || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you throw an error before if comment.type !== CommentType.generatedAlert
it should be impossible the new comment to be of type anything other than CommentType.generatedAlert
. Never hurts to double check though 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha good point.
}); | ||
|
||
return CollectWithSubCaseResponseRt.encode({ | ||
subCase: flattenSubCaseSavedObject({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we return subCases: [flattenSubCaseSavedObject(...)]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I talked with Xavier about this and we thought for now we'd keep it as a single entry rather than an array of sub cases for the add comment response.
response: kibanaResponseFactory, | ||
scopedClusterClient, | ||
// we might want the user information to be passed as part of the action request | ||
user: nullUser, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found out that you can scopedClusterClient.security.getUser()
. Just for future reference in case we need it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh interesting! I'll add it to the list of stuff to refactor 👍
): comment is ContextTypeGeneratedAlertType => { | ||
return ( | ||
comment.type === CommentType.generatedAlert && | ||
'alerts' in comment && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the type check is enough, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just being extra careful since we need to access the alerts
field.
const args = query | ||
? { | ||
caseService, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
const args = {caseService, client, id, options: {
page: defaultPage,
perPage: defaultPerPage,
sortField: 'created_at',
...(query ? query : {})
}, associationType}
|
||
await Promise.all( | ||
subCasesForCaseIds.saved_objects.map((subCaseSO) => | ||
caseService.deleteSubCase(client, subCaseSO.id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For another PR: I think maybe is better to first delete the subcase and then the comments if the corresponding subcase has been deleted successfully. This will prevent a use case where all the comments of a subcase have been deleted and the deletion of the subcase faild.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point
/** | ||
* Builds an AlertInfo object accumulating the alert IDs and indices for the passed in alerts. | ||
*/ | ||
export const getAlertIndicesAndIDs = (comments: CommentAttributes[] | undefined): AlertInfo => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: getAlertIndicesAndIDs
and getAlertIndicesAndIDsFromSO
are almost identical. They can be combined in one function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently I don't even use getAlertIndicesAndIDsFromSO
anywhere haha 🤦 I'll remove it in the next PR.
|
||
/** | ||
* This is used to test if the posted comment is an generated alert. A generated alert will have one or many alerts. | ||
* An alert is essentially an object with a _id field. This differs from a regular attached alert because the _id is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: generated alerts do not have an _id
field any more. Fields of alert
and generated_alert
is the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep thanks.
@@ -5,24 +5,26 @@ | |||
* 2.0. | |||
*/ | |||
|
|||
import _ from 'lodash'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Better to use import { isEmpty } from lodash/fp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good PR! The code is very clean and readable. Very important for the complexity of this feature. Thank you for the effort you put on this. Great job!
I left some nit/code enhancement comments. Let's work together on another PR to do them.
Tests I preformed:
- Add a user comment to a collection ✅
- Add an alert to a collection: 400 error: Alert cannot be attached to a collection case ✅
- Add a generated alert to a collection. The generated alert is added to the subcase and not to the collection ✅
- Attach an alert and a user comment to a subcase ✅
- Attach a generated alert to a sub case using the cases route: 404 error, case not found ✅.
- Add an alert and user comment to an individual case ✅
- Add generated alert to an individual case: 400 error ✅
- Add connector to an individual case and to a collection case ✅
- Add connector to a subcase: 406: All update fields are identical to current version. ✅
- Push individual case to external service with alerts & user comments ✅
- Push subcase to external service using the case route: 404 error ✅
- Patching a subcase using the case route: 404 error ✅
- Push a collection to an external service ✅
- Update the status of an individual case with sync turned off does not update the alerts attached ✅
- Updating the status of an individual case with sync turned on updates the alerts correctly ✅
- Updating the status of a collection is not allowed ✅
- Update the status of a subcase ✅
- Case collection: Turn sync off, change the status of a subcase, turn sync on, all alerts attach to the subcase change their status accordingly ✅
- Attach a generated_alert to a collection creates another sub case if all subcases are closed ✅
- Attach a generated_alert to a collection does NOT creates another sub case if there is an open subcase ✅
- Case collection, sync alert is off: two subcases, one in-progress, one closed. Turn sync on. All alerts are updated accordingly ✅.
- Two subcases: one in-progess, one open. Attaching
generated_alerts
to the collection is added to the most recent subcase ✅ - Update collection & individual case fields like title, tags, comments, connector fields etc from the UI ✅
- Push updates to external service correctly ✅
- Creates a case correctly from the UI. ✅
- Converting a collection to individual throws an error ✅
- Converting an individual case to a collection when having alerts attached throws an error ✅
Notes:
- If I am working on a collection case (in the UI) and a subcase is generate behind the scene I have to refresh for me to be able to do a change. One day we have to have an observable/websocket to watch for cases updates and update on the fly as Github does.
- We should use
excess
in the future when patching subcases & cases.
* Adding type field to client * Removing context and adding association type * Handle alerts from multiple indices * Adding flow for adding a sub case * Making progress on creating alerts from rules * Refactored add comment to handle case and sub case * Starting sub case API and refactoring of case client * Fleshing out find cases * Finished the find cases api * Filtering comments by association type * Fixing tests and types * Updating snapshots * Cleaning up comment references * Working unit tests * Fixing integration tests and got ES to work * Unit tests and api integration test working * Refactoring find and get_status * Starting patch, and update * script for sub cases * Removing converted_by and fixing type errors * Adding docs for script * Removing converted_by and fixing integration test * Adding sub case id to comment routes * Removing stringify comparison * Adding delete api and tests * Updating license * missed license files * Integration tests passing * Adding more tests for sub cases * Find int tests, scoped client, patch sub user actions * fixing types and call cluster * fixing get sub case param issue * Adding user actions for sub cases * Preventing alerts on collections and refactoring user * Allowing type to be updated for ind cases * Refactoring and writing tests * Fixing sub case status filtering * Adding more tests not allowing gen alerts patch * Working unit tests * Push to connector gets all sub case comments * Writing more tests and cleaning up * Updating push functionality for generated alerts and sub cases * Adding comment about updating collection sync * Refactoring update alert status for sub cases and removing request and cleaning up * Addressing alert service feedback * Fixing sub case sync bug and cleaning up comment types * Addressing more feedback Co-authored-by: Kibana Machine <[email protected]> Co-authored-by: Kibana Machine <[email protected]>
This reverts commit f8b8d5b.
This PR adds support in the case backend for attaching generated alerts from detection rules to a case.
Notable changes:
force
flag which defaults tofalse
generated_alert
(this allows the UI to distinguish between generated alerts and user added alerts)