-
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
[Cases] Remove case id from alerts when deleting a case #154829
Changes from all commits
fdb9c86
5e32a59
7aa65ea
387ce0b
8d04581
935ca81
2364a3d
f3b904f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,7 +105,7 @@ export interface BulkUpdateCasesOptions { | |
caseIds: string[]; | ||
} | ||
|
||
export interface RemoveAlertsFromCaseOptions { | ||
export interface RemoveCaseIdFromAlertsOptions { | ||
alerts: MgetAndAuditAlert[]; | ||
caseId: string; | ||
} | ||
|
@@ -851,33 +851,33 @@ export class AlertsClient { | |
}); | ||
} | ||
|
||
public async removeCaseIdFromAlerts({ caseId, alerts }: RemoveAlertsFromCaseOptions) { | ||
public async removeCaseIdFromAlerts({ caseId, alerts }: RemoveCaseIdFromAlertsOptions) { | ||
/** | ||
* We intentionally do not perform any authorization | ||
* on the alerts. Users should be able to remove | ||
* cases from alerts when deleting a case or an | ||
* attachment | ||
*/ | ||
try { | ||
if (alerts.length === 0) { | ||
return; | ||
} | ||
|
||
const mgetRes = await this.ensureAllAlertsAuthorized({ | ||
alerts, | ||
operation: ReadOperations.Get, | ||
}); | ||
|
||
const painlessScript = `if (ctx._source['${ALERT_CASE_IDS}'] != null) { | ||
for (int i=0; i < ctx._source['${ALERT_CASE_IDS}'].length; i++) { | ||
if (ctx._source['${ALERT_CASE_IDS}'][i].equals('${caseId}')) { | ||
ctx._source['${ALERT_CASE_IDS}'].remove(i); | ||
} | ||
if (ctx._source['${ALERT_CASE_IDS}'].contains('${caseId}')) { | ||
int index = ctx._source['${ALERT_CASE_IDS}'].indexOf('${caseId}'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Great catch, I totally forgot about that in Java: https://stackoverflow.com/questions/10431981/remove-elements-from-collection-while-iterating |
||
ctx._source['${ALERT_CASE_IDS}'].remove(index); | ||
} | ||
}`; | ||
|
||
const bulkUpdateRequest = []; | ||
|
||
for (const doc of mgetRes.docs) { | ||
for (const alert of alerts) { | ||
bulkUpdateRequest.push( | ||
{ | ||
update: { | ||
_index: doc._index, | ||
_id: doc._id, | ||
_index: alert.index, | ||
_id: alert.id, | ||
}, | ||
}, | ||
{ | ||
|
@@ -891,11 +891,61 @@ export class AlertsClient { | |
body: bulkUpdateRequest, | ||
}); | ||
} catch (error) { | ||
this.logger.error(`Error to remove case ${caseId} from alerts: ${error}`); | ||
this.logger.error(`Error removing case ${caseId} from alerts: ${error}`); | ||
throw error; | ||
} | ||
} | ||
|
||
public async removeCaseIdsFromAllAlerts({ caseIds }: { caseIds: string[] }) { | ||
/** | ||
* We intentionally do not perform any authorization | ||
* on the alerts. Users should be able to remove | ||
* cases from alerts when deleting a case or an | ||
* attachment | ||
*/ | ||
try { | ||
if (caseIds.length === 0) { | ||
return; | ||
} | ||
|
||
const index = `${this.ruleDataService.getResourcePrefix()}-*`; | ||
cnasikas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const query = `${ALERT_CASE_IDS}: (${caseIds.join(' or ')})`; | ||
const esQuery = buildEsQuery(undefined, { query, language: 'kuery' }, []); | ||
|
||
const SCRIPT_PARAMS_ID = 'caseIds'; | ||
|
||
const painlessScript = `if (ctx._source['${ALERT_CASE_IDS}'] != null && ctx._source['${ALERT_CASE_IDS}'].length > 0 && params['${SCRIPT_PARAMS_ID}'] != null && params['${SCRIPT_PARAMS_ID}'].length > 0) { | ||
List storedCaseIds = ctx._source['${ALERT_CASE_IDS}']; | ||
List caseIdsToRemove = params['${SCRIPT_PARAMS_ID}']; | ||
|
||
for (int i=0; i < caseIdsToRemove.length; i++) { | ||
if (storedCaseIds.contains(caseIdsToRemove[i])) { | ||
int index = storedCaseIds.indexOf(caseIdsToRemove[i]); | ||
storedCaseIds.remove(index); | ||
} | ||
} | ||
}`; | ||
|
||
await this.esClient.updateByQuery({ | ||
index, | ||
conflicts: 'proceed', | ||
refresh: true, | ||
body: { | ||
script: { | ||
source: painlessScript, | ||
lang: 'painless', | ||
params: { caseIds }, | ||
} as InlineScript, | ||
query: esQuery, | ||
}, | ||
ignore_unavailable: true, | ||
}); | ||
} catch (err) { | ||
this.logger.error(`Failed removing ${caseIds} from all alerts: ${err}`); | ||
throw err; | ||
} | ||
} | ||
|
||
public async find<Params extends RuleTypeParams = never>({ | ||
aggs, | ||
featureIds, | ||
|
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.
In the future it might be interesting to investigate if we can skip some cases that we're pretty confident do not have any alerts attached to them. I think we could leverage our
total_alerts
field and ignore cases that have it set to0
. Not something we should do in this PR and might not even be worth doing in general 🤷♂️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 idea! We can do it when we bound our delete API so the number of cases to retrieve is also bounded.