Skip to content

Commit c4510ea

Browse files
authored
[Security Solution] Update rule's last run on early exit due to error (elastic#264286)
## Summary Follow-up fix for elastic#257203 where an early-exit path was missed when migrating security rule execution logging. - Closes the rule execution logger when the rule exits early because `getInputIndex` fails (data view not found or unexpected error), so the rule's last run object gets updated for that execution. ## Details In [`create_security_rule_type_wrapper.ts`](x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts) the executor returns early when resolving the input index (data view / index pattern) throws. Before this change, `ruleExecutionLogger.close()` was not called on that branch, which meant `setRuleLastRun` was never invoked and the rule's last run object was left stale for the execution. ## Test plan - [ ] Unit tests in `create_query_alert_type.test.ts` cover both early-exit branches (data view not found, generic error resolving the input index) and assert that `ruleExecutionLogger.close()` is invoked. - [ ] Manual: configure a rule with a `dataViewId` that does not exist, run the rule, and verify its last run shows the error instead of remaining stale. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent cad8fb1 commit c4510ea

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
269269
ruleExecutionLogger.error(`Check for indices to search failed.\nError: ${exc}`);
270270
}
271271

272+
// Closing the logger due to early exit
273+
await ruleExecutionLogger.close();
274+
272275
return { state: result.state };
273276
}
274277
}

x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { getQueryRuleParams } from '../../rule_schema/mocks';
1717
import { licensingMock } from '@kbn/licensing-plugin/server/mocks';
1818
import { QUERY_RULE_TYPE_ID } from '@kbn/securitysolution-rules';
1919
import { docLinksServiceMock } from '@kbn/core/server/mocks';
20+
import { SavedObjectsErrorHelpers } from '@kbn/core/server';
2021
import { IndexPatternsFetcher } from '@kbn/data-views-plugin/server';
2122
import { hasTimestampFields } from '../utils/utils';
2223
import { createMockEndpointAppContextService } from '../../../../endpoint/mocks';
@@ -295,4 +296,46 @@ describe('Custom Query Alerts', () => {
295296
"The rule's max alerts per run setting (10000) is greater than the Kibana alerting limit (1000). The rule will only write a maximum of 1000 alerts per rule run."
296297
);
297298
});
299+
300+
describe('when exiting early due to an error resolving the input index', () => {
301+
const dataViewId = 'missing-data-view-id';
302+
303+
const registerAndRun = async () => {
304+
const queryAlertType = securityRuleTypeWrapper(
305+
createQueryAlertType({
306+
id: QUERY_RULE_TYPE_ID,
307+
name: 'Custom Query Rule',
308+
})
309+
);
310+
311+
alerting.registerType(queryAlertType);
312+
313+
await executor({ params: getQueryRuleParams({ dataViewId }) });
314+
};
315+
316+
it('closes the rule execution logger when the data view is not found, so the last run object is updated', async () => {
317+
services.savedObjectsClient.get.mockRejectedValueOnce(
318+
SavedObjectsErrorHelpers.createGenericNotFoundError('index-pattern', dataViewId)
319+
);
320+
321+
await registerAndRun();
322+
323+
expect(mockedStatusLogger.error).toHaveBeenCalledWith(
324+
expect.stringContaining('Data view is not found.'),
325+
expect.objectContaining({ userError: true })
326+
);
327+
expect(mockedStatusLogger.close).toHaveBeenCalledTimes(1);
328+
});
329+
330+
it('closes the rule execution logger when resolving the input index fails unexpectedly, so the last run object is updated', async () => {
331+
services.savedObjectsClient.get.mockRejectedValueOnce(new Error('Unexpected failure'));
332+
333+
await registerAndRun();
334+
335+
expect(mockedStatusLogger.error).toHaveBeenCalledWith(
336+
expect.stringContaining('Check for indices to search failed.')
337+
);
338+
expect(mockedStatusLogger.close).toHaveBeenCalledTimes(1);
339+
});
340+
});
298341
});

0 commit comments

Comments
 (0)