-
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
[Security Solution][Resolver] Handle disabled process collection #73592
Changes from 4 commits
9424a64
7e3f9d8
f6f41d2
37b884d
4801974
21eee4f
d33b537
62d55fb
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 |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* | ||
* 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 expect from '@kbn/expect'; | ||
import { SearchResponse } from 'elasticsearch'; | ||
import { eventsIndexPattern } from '../../../../plugins/security_solution/common/endpoint/constants'; | ||
import { | ||
ResolverTree, | ||
ResolverEntityIndex, | ||
} from '../../../../plugins/security_solution/common/endpoint/types'; | ||
import { FtrProviderContext } from '../../ftr_provider_context'; | ||
import { | ||
EndpointDocGenerator, | ||
Event, | ||
} from '../../../../plugins/security_solution/common/endpoint/generate_data'; | ||
import { GeneratedEvents } from '../../services/resolver'; | ||
|
||
export default function resolverAPIIntegrationTests({ getService }: FtrProviderContext) { | ||
const supertest = getService('supertest'); | ||
const resolver = getService('resolverGenerator'); | ||
const es = getService('es'); | ||
const generator = new EndpointDocGenerator('resolver'); | ||
|
||
describe('Resolver handling of entity ids', () => { | ||
describe('entity api', () => { | ||
let origin: Event; | ||
let genData: GeneratedEvents; | ||
before(async () => { | ||
origin = generator.generateEvent({ parentEntityID: 'a' }); | ||
origin.process.entity_id = ''; | ||
genData = await resolver.insertEvents([origin]); | ||
}); | ||
|
||
after(async () => { | ||
await resolver.deleteData(genData); | ||
}); | ||
|
||
it('excludes events that have an empty entity_id field', async () => { | ||
// first lets get the _id of the document using the parent.process.entity_id | ||
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. nothing to block over, but can't you set 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. Yeah good point. I'm using a helper function that inserts an array of documents so it's doing a bulk request. Later we can refactor it so it specifies the |
||
// then we'll use the API to search for that specific document | ||
const res = await es.search<SearchResponse<Event>>({ | ||
index: genData.indices[0], | ||
body: { | ||
query: { | ||
bool: { | ||
filter: [ | ||
{ | ||
term: { 'process.parent.entity_id': origin.process.parent!.entity_id }, | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
}); | ||
const { body }: { body: ResolverEntityIndex } = await supertest.get( | ||
// using the same indices value here twice to force the query parameter to be an array | ||
// for some reason using supertest's query() function doesn't construct a parsable array | ||
`/api/endpoint/resolver/entity?_id=${res.body.hits.hits[0]._id}&indices=${eventsIndexPattern}&indices=${eventsIndexPattern}` | ||
); | ||
expect(body).to.be.empty(); | ||
}); | ||
}); | ||
|
||
describe('children', () => { | ||
let origin: Event; | ||
let childNoEntityID: Event; | ||
let childWithEntityID: Event; | ||
let events: Event[]; | ||
let genData: GeneratedEvents; | ||
|
||
before(async () => { | ||
// construct a tree with an origin and two direct children. One child will not have an entity_id. That child | ||
// should not be returned by the backend. | ||
origin = generator.generateEvent({ entityID: 'a' }); | ||
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. we should add tests of this kind to the UI too eventually |
||
childNoEntityID = generator.generateEvent({ | ||
parentEntityID: origin.process.entity_id, | ||
ancestry: [origin.process.entity_id], | ||
}); | ||
// force it to be empty | ||
childNoEntityID.process.entity_id = ''; | ||
|
||
childWithEntityID = generator.generateEvent({ | ||
entityID: 'b', | ||
parentEntityID: origin.process.entity_id, | ||
ancestry: [origin.process.entity_id], | ||
}); | ||
events = [origin, childNoEntityID, childWithEntityID]; | ||
genData = await resolver.insertEvents(events); | ||
}); | ||
|
||
after(async () => { | ||
await resolver.deleteData(genData); | ||
}); | ||
|
||
it('does not find children without a process entity_id', async () => { | ||
const { body }: { body: ResolverTree } = await supertest | ||
.get(`/api/endpoint/resolver/${origin.process.entity_id}`) | ||
.expect(200); | ||
expect(body.children.childNodes.length).to.be(1); | ||
expect(body.children.childNodes[0].entityID).to.be(childWithEntityID.process.entity_id); | ||
}); | ||
}); | ||
|
||
describe('ancestors', () => { | ||
let origin: Event; | ||
let ancestor1: Event; | ||
let ancestor2: Event; | ||
let ancestorNoEntityID: Event; | ||
let events: Event[]; | ||
let genData: GeneratedEvents; | ||
|
||
before(async () => { | ||
// construct a tree with an origin that has two ancestors. The origin will have an empty string as one of the | ||
// entity_ids in the ancestry array. This is to make sure that the backend will not query for that event. | ||
ancestor2 = generator.generateEvent({ | ||
entityID: '2', | ||
}); | ||
ancestor1 = generator.generateEvent({ | ||
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. having trouble following what 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. Yeah it was more of a sanity check. The origin node in that test has its |
||
entityID: '1', | ||
parentEntityID: ancestor2.process.entity_id, | ||
ancestry: [ancestor2.process.entity_id], | ||
}); | ||
|
||
// we'll insert an event that doesn't have an entity id so if the backend does search for it, it should be | ||
// returned and our test should fail | ||
ancestorNoEntityID = generator.generateEvent({ | ||
ancestry: [ancestor2.process.entity_id], | ||
}); | ||
ancestorNoEntityID.process.entity_id = ''; | ||
|
||
origin = generator.generateEvent({ | ||
entityID: 'a', | ||
parentEntityID: ancestor1.process.entity_id, | ||
ancestry: ['', ancestor2.process.entity_id], | ||
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. you could just make the first one here 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. Yeah good point. I added that late. I wanted to make sure that the backend wouldn't return the event even if ES actually did have a document with entity_id as an empty string |
||
}); | ||
|
||
events = [origin, ancestor1, ancestor2, ancestorNoEntityID]; | ||
genData = await resolver.insertEvents(events); | ||
}); | ||
|
||
after(async () => { | ||
await resolver.deleteData(genData); | ||
}); | ||
|
||
it('does not query for ancestors that have an empty string for the entity_id', async () => { | ||
const { body }: { body: ResolverTree } = await supertest | ||
.get(`/api/endpoint/resolver/${origin.process.entity_id}`) | ||
.expect(200); | ||
expect(body.ancestry.ancestors.length).to.be(1); | ||
expect(body.ancestry.ancestors[0].entityID).to.be(ancestor2.process.entity_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.
fyi, this is missing the empty array
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 thanks. I actually check that case below. Must be an accidental copy paste. I'll remove it.