-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* adds route for querying signals index, also updates signal status type names * first pass at happy path tests * fixes stuff after rebase with master * utilizes removes search_query from payload and replaces it with just query, adds aggs to signals search api, updates route and validation tests * removes _headers parameter from route handler and updates comment for aggs script
- Loading branch information
Showing
12 changed files
with
323 additions
and
17 deletions.
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
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
39 changes: 39 additions & 0 deletions
39
...lugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.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,39 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { querySignalsSchema } from './query_signals_index_schema'; | ||
import { SignalsQueryRestParams } from '../../signals/types'; | ||
|
||
describe('query and aggs on signals index', () => { | ||
test('query and aggs simultaneously', () => { | ||
expect( | ||
querySignalsSchema.validate<Partial<SignalsQueryRestParams>>({ | ||
query: {}, | ||
aggs: {}, | ||
}).error | ||
).toBeFalsy(); | ||
}); | ||
|
||
test('query only', () => { | ||
expect( | ||
querySignalsSchema.validate<Partial<SignalsQueryRestParams>>({ | ||
query: {}, | ||
}).error | ||
).toBeFalsy(); | ||
}); | ||
|
||
test('aggs only', () => { | ||
expect( | ||
querySignalsSchema.validate<Partial<SignalsQueryRestParams>>({ | ||
aggs: {}, | ||
}).error | ||
).toBeFalsy(); | ||
}); | ||
|
||
test('missing query and aggs is invalid', () => { | ||
expect(querySignalsSchema.validate<Partial<SignalsQueryRestParams>>({}).error).toBeTruthy(); | ||
}); | ||
}); |
12 changes: 12 additions & 0 deletions
12
...acy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.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,12 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import Joi from 'joi'; | ||
|
||
export const querySignalsSchema = Joi.object({ | ||
query: Joi.object(), | ||
aggs: Joi.object(), | ||
}).min(1); |
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
129 changes: 129 additions & 0 deletions
129
...egacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.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,129 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { createMockServer } from '../__mocks__/_mock_server'; | ||
import { querySignalsRoute } from './query_signals_route'; | ||
import * as myUtils from '../utils'; | ||
import { ServerInjectOptions } from 'hapi'; | ||
import { | ||
getSignalsQueryRequest, | ||
getSignalsAggsQueryRequest, | ||
typicalSignalsQuery, | ||
typicalSignalsQueryAggs, | ||
} from '../__mocks__/request_responses'; | ||
import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; | ||
|
||
describe('query for signal', () => { | ||
let { server, elasticsearch } = createMockServer(); | ||
|
||
beforeEach(() => { | ||
jest.resetAllMocks(); | ||
jest.spyOn(myUtils, 'getIndex').mockReturnValue('fakeindex'); | ||
({ server, elasticsearch } = createMockServer()); | ||
elasticsearch.getCluster = jest.fn(() => ({ | ||
callWithRequest: jest.fn(() => true), | ||
})); | ||
querySignalsRoute(server); | ||
}); | ||
|
||
describe('query and agg on signals index', () => { | ||
test('returns 200 when using single query', async () => { | ||
elasticsearch.getCluster = jest.fn(() => ({ | ||
callWithRequest: jest.fn( | ||
(_req, _type: string, queryBody: { index: string; body: object }) => { | ||
expect(queryBody.body).toMatchObject({ ...typicalSignalsQueryAggs() }); | ||
return true; | ||
} | ||
), | ||
})); | ||
const { statusCode } = await server.inject(getSignalsAggsQueryRequest()); | ||
expect(statusCode).toBe(200); | ||
expect(myUtils.getIndex).toHaveReturnedWith('fakeindex'); | ||
}); | ||
|
||
test('returns 200 when using single agg', async () => { | ||
elasticsearch.getCluster = jest.fn(() => ({ | ||
callWithRequest: jest.fn( | ||
(_req, _type: string, queryBody: { index: string; body: object }) => { | ||
expect(queryBody.body).toMatchObject({ ...typicalSignalsQueryAggs() }); | ||
return true; | ||
} | ||
), | ||
})); | ||
const { statusCode } = await server.inject(getSignalsAggsQueryRequest()); | ||
expect(statusCode).toBe(200); | ||
expect(myUtils.getIndex).toHaveReturnedWith('fakeindex'); | ||
}); | ||
|
||
test('returns 200 when using aggs and query together', async () => { | ||
const allTogether = getSignalsQueryRequest(); | ||
allTogether.payload = { ...typicalSignalsQueryAggs(), ...typicalSignalsQuery() }; | ||
elasticsearch.getCluster = jest.fn(() => ({ | ||
callWithRequest: jest.fn( | ||
(_req, _type: string, queryBody: { index: string; body: object }) => { | ||
expect(queryBody.body).toMatchObject({ | ||
...typicalSignalsQueryAggs(), | ||
...typicalSignalsQuery(), | ||
}); | ||
return true; | ||
} | ||
), | ||
})); | ||
const { statusCode } = await server.inject(allTogether); | ||
expect(statusCode).toBe(200); | ||
expect(myUtils.getIndex).toHaveReturnedWith('fakeindex'); | ||
}); | ||
|
||
test('returns 400 when missing aggs and query', async () => { | ||
const allTogether = getSignalsQueryRequest(); | ||
allTogether.payload = {}; | ||
const { statusCode } = await server.inject(allTogether); | ||
expect(statusCode).toBe(400); | ||
}); | ||
}); | ||
|
||
describe('validation', () => { | ||
test('returns 200 if query present', async () => { | ||
const request: ServerInjectOptions = { | ||
method: 'POST', | ||
url: DETECTION_ENGINE_QUERY_SIGNALS_URL, | ||
payload: typicalSignalsQuery(), | ||
}; | ||
const { statusCode } = await server.inject(request); | ||
expect(statusCode).toBe(200); | ||
}); | ||
|
||
test('returns 200 if aggs is present', async () => { | ||
const request: ServerInjectOptions = { | ||
method: 'POST', | ||
url: DETECTION_ENGINE_QUERY_SIGNALS_URL, | ||
payload: typicalSignalsQueryAggs(), | ||
}; | ||
const { statusCode } = await server.inject(request); | ||
expect(statusCode).toBe(200); | ||
}); | ||
|
||
test('returns 200 if aggs and query are present', async () => { | ||
const request: ServerInjectOptions = { | ||
method: 'POST', | ||
url: DETECTION_ENGINE_QUERY_SIGNALS_URL, | ||
payload: { ...typicalSignalsQueryAggs(), ...typicalSignalsQuery() }, | ||
}; | ||
const { statusCode } = await server.inject(request); | ||
expect(statusCode).toBe(200); | ||
}); | ||
|
||
test('returns 400 if aggs and query are NOT present', async () => { | ||
const request: ServerInjectOptions = { | ||
method: 'POST', | ||
url: DETECTION_ENGINE_QUERY_SIGNALS_URL, | ||
payload: {}, | ||
}; | ||
const { statusCode } = await server.inject(request); | ||
expect(statusCode).toBe(400); | ||
}); | ||
}); | ||
}); |
47 changes: 47 additions & 0 deletions
47
x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.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,47 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import Hapi from 'hapi'; | ||
import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; | ||
import { SignalsQueryRequest } from '../../signals/types'; | ||
import { querySignalsSchema } from '../schemas/query_signals_index_schema'; | ||
import { ServerFacade } from '../../../../types'; | ||
import { transformError, getIndex } from '../utils'; | ||
|
||
export const querySignalsRouteDef = (server: ServerFacade): Hapi.ServerRoute => { | ||
return { | ||
method: 'POST', | ||
path: DETECTION_ENGINE_QUERY_SIGNALS_URL, | ||
options: { | ||
tags: ['access:siem'], | ||
validate: { | ||
options: { | ||
abortEarly: false, | ||
}, | ||
payload: querySignalsSchema, | ||
}, | ||
}, | ||
async handler(request: SignalsQueryRequest) { | ||
const { query, aggs } = request.payload; | ||
const body = { query, aggs }; | ||
const index = getIndex(request, server); | ||
const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); | ||
try { | ||
return callWithRequest(request, 'search', { | ||
index, | ||
body, | ||
}); | ||
} catch (exc) { | ||
// error while getting or updating signal with id: id in signal index .siem-signals | ||
return transformError(exc); | ||
} | ||
}, | ||
}; | ||
}; | ||
|
||
export const querySignalsRoute = (server: ServerFacade) => { | ||
server.route(querySignalsRouteDef(server)); | ||
}; |
Oops, something went wrong.