-
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
[Detections] EQL query validation: Separate syntax errors into a own error type (#10181) #190149
Merged
e40pud
merged 11 commits into
elastic:main
from
e40pud:security/feature/EQL-query-validation
Aug 15, 2024
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
b11642e
[Detections] EQL query validation: Separate syntax errors into a own …
e40pud f106eca
EQL error code namings
e40pud 7d75286
Add `MISSING_DATA_SOURCE` validation error
e40pud d2eb8da
Fix types
e40pud 5ca831b
Fix tests
e40pud 7b11a6e
Merge branch 'main' into security/feature/EQL-query-validation
e40pud 7c31ac6
Merge branch 'main' into security/feature/EQL-query-validation
e40pud 6992dba
Merge branch 'main' into security/feature/EQL-query-validation
elasticmachine c178c76
Merge branch 'main' into security/feature/EQL-query-validation
e40pud da821b0
Review feedback: add jest tests for EQL validation response handler
e40pud 48742a1
Merge branch 'main' into security/feature/EQL-query-validation
e40pud File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
x-pack/plugins/security_solution/public/common/hooks/eql/api.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { of } from 'rxjs'; | ||
|
||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; | ||
import { searchServiceMock } from '@kbn/data-plugin/public/search/mocks'; | ||
|
||
import { validateEql } from './api'; | ||
import { | ||
getEqlResponseWithMappingError, | ||
getEqlResponseWithNonValidationError, | ||
getEqlResponseWithParsingError, | ||
getEqlResponseWithValidationError, | ||
getEqlResponseWithValidationErrors, | ||
} from '../../../../common/search_strategy/eql/validation/helpers.mock'; | ||
|
||
const searchMock = searchServiceMock.createStartContract(); | ||
|
||
const mockDataService = { | ||
...dataPluginMock.createStartContract(), | ||
search: searchMock, | ||
}; | ||
|
||
const triggerValidateEql = () => { | ||
const signal = new AbortController().signal; | ||
return validateEql({ | ||
data: mockDataService, | ||
dataViewTitle: 'logs-*', | ||
query: 'any where true', | ||
signal, | ||
runtimeMappings: undefined, | ||
options: undefined, | ||
}); | ||
}; | ||
|
||
describe('validateEql', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
describe('handle EqlSearchStrategyResponse', () => { | ||
it('should return valid set to true if validation response is not an error', async () => { | ||
searchMock.search.mockImplementation(() => of({ rawResponse: 'Successful validation!' })); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ valid: true }); | ||
}); | ||
|
||
it('should return EQL_ERR_INVALID_EQL error in case of `verification_exception` error', async () => { | ||
searchMock.search.mockImplementation(() => | ||
of({ rawResponse: getEqlResponseWithValidationError() }) | ||
); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ | ||
valid: false, | ||
error: { | ||
code: 'EQL_ERR_INVALID_EQL', | ||
messages: [ | ||
'Found 2 problems\nline 1:1: Unknown column [event.category]\nline 1:13: Unknown column [event.name]', | ||
], | ||
}, | ||
}); | ||
}); | ||
|
||
it('should return EQL_ERR_INVALID_EQL error in case of multiple `verification_exception` errors', async () => { | ||
searchMock.search.mockImplementation(() => | ||
of({ rawResponse: getEqlResponseWithValidationErrors() }) | ||
); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ | ||
valid: false, | ||
error: { | ||
code: 'EQL_ERR_INVALID_EQL', | ||
messages: [ | ||
'Found 2 problems\nline 1:1: Unknown column [event.category]\nline 1:13: Unknown column [event.name]', | ||
"line 1:4: mismatched input '<EOF>' expecting 'where'", | ||
], | ||
}, | ||
}); | ||
}); | ||
|
||
it('should return EQL_ERR_INVALID_EQL error in case of `mapping_exception` error', async () => { | ||
searchMock.search.mockImplementation(() => | ||
of({ rawResponse: getEqlResponseWithMappingError() }) | ||
); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ | ||
valid: false, | ||
error: { code: 'EQL_ERR_INVALID_EQL', messages: ["Inaccessible index 'restricted-*'"] }, | ||
}); | ||
}); | ||
|
||
it('should return EQL_ERR_INVALID_SYNTAX error in case of `parsing_exception` error', async () => { | ||
searchMock.search.mockImplementation(() => | ||
of({ rawResponse: getEqlResponseWithParsingError() }) | ||
); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ | ||
valid: false, | ||
error: { | ||
code: 'EQL_ERR_INVALID_SYNTAX', | ||
messages: ["line 1:5: missing 'where' at 'demo'"], | ||
}, | ||
}); | ||
}); | ||
|
||
it('should return EQL_ERR_FAILED_REQUEST error in case of non-validation error', async () => { | ||
searchMock.search.mockImplementation(() => | ||
of({ rawResponse: getEqlResponseWithNonValidationError() }) | ||
); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ | ||
valid: false, | ||
error: { | ||
code: 'EQL_ERR_FAILED_REQUEST', | ||
error: expect.objectContaining( | ||
new Error(JSON.stringify(getEqlResponseWithNonValidationError())) | ||
), | ||
}, | ||
}); | ||
}); | ||
|
||
it('should return EQL_ERR_MISSING_DATA_SOURCE error in case `data.search` throws an error which starts with `index_not_found_exception`', async () => { | ||
const message = 'index_not_found_exception Found 1 problem line -1:-1: Unknown index [*,-*]'; | ||
searchMock.search.mockImplementation(() => { | ||
throw new Error(message); | ||
}); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ | ||
valid: false, | ||
error: { code: 'EQL_ERR_MISSING_DATA_SOURCE', messages: [message] }, | ||
}); | ||
}); | ||
|
||
it('should return EQL_ERR_FAILED_REQUEST error in case `data.search` throws an error', async () => { | ||
const message = 'Internal exception'; | ||
searchMock.search.mockImplementation(() => { | ||
throw new Error(message); | ||
}); | ||
const response = await triggerValidateEql(); | ||
|
||
expect(response).toEqual({ | ||
valid: false, | ||
error: { | ||
code: 'EQL_ERR_FAILED_REQUEST', | ||
error: expect.objectContaining(new Error(message)), | ||
}, | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Since this function is growing in complexity, it's probably time to add some unit tests around it (more for documentation of behavior than anything else); maybe extract a function that receives a response and test that? That would also allow us to document the shape of response(s) we handle.
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 point! I will add tests for this functionality