[Endpoint] Sample data generator for endpoint app (#58936)
* scaffolding and notes.md * add skeleton event generator to kibana * add optional entityID param to generateEvent * add tree generation * add tests * working tests * fix up tests * fix linting * fix event types * make process parent types consistent * make generator match types * move test resolver node out of common types * fix random string generation * fix typecheck errors * remove extraneous stuff * address PR comments * add test for full resolver tree * cleanup * make tests clearer * add seedrandom to endpoint plugin. contains DONOTMERGE example code * remove robs test * start replacing random with seedrandom * use seeded random for uuidv4 * separate out IP randomization * typecheck fixes Co-authored-by: oatkiller <robert.austin@elastic.co> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
0ed7176e4d
commit
435cb0b959
168
x-pack/plugins/endpoint/common/generate_data.test.ts
Normal file
168
x-pack/plugins/endpoint/common/generate_data.test.ts
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
* 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 { EndpointDocGenerator, Event } from './generate_data';
|
||||||
|
|
||||||
|
interface Node {
|
||||||
|
events: Event[];
|
||||||
|
children: Node[];
|
||||||
|
parent_entity_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('data generator', () => {
|
||||||
|
let generator: EndpointDocGenerator;
|
||||||
|
beforeEach(() => {
|
||||||
|
generator = new EndpointDocGenerator('seed');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates the same documents with same random seed', () => {
|
||||||
|
const generator1 = new EndpointDocGenerator('seed');
|
||||||
|
const generator2 = new EndpointDocGenerator('seed');
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const metadata1 = generator1.generateEndpointMetadata(timestamp);
|
||||||
|
const metadata2 = generator2.generateEndpointMetadata(timestamp);
|
||||||
|
expect(metadata1).toEqual(metadata2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates different documents with different random seeds', () => {
|
||||||
|
const generator1 = new EndpointDocGenerator('seed');
|
||||||
|
const generator2 = new EndpointDocGenerator('different seed');
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const metadata1 = generator1.generateEndpointMetadata(timestamp);
|
||||||
|
const metadata2 = generator2.generateEndpointMetadata(timestamp);
|
||||||
|
expect(metadata1).not.toEqual(metadata2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates endpoint metadata documents', () => {
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const metadata = generator.generateEndpointMetadata(timestamp);
|
||||||
|
expect(metadata['@timestamp']).toEqual(timestamp);
|
||||||
|
expect(metadata.event.created).toEqual(timestamp);
|
||||||
|
expect(metadata.endpoint).not.toBeNull();
|
||||||
|
expect(metadata.agent).not.toBeNull();
|
||||||
|
expect(metadata.host).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates alert event documents', () => {
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const alert = generator.generateAlert(timestamp);
|
||||||
|
expect(alert['@timestamp']).toEqual(timestamp);
|
||||||
|
expect(alert.event.action).not.toBeNull();
|
||||||
|
expect(alert.endpoint).not.toBeNull();
|
||||||
|
expect(alert.agent).not.toBeNull();
|
||||||
|
expect(alert.host).not.toBeNull();
|
||||||
|
expect(alert.process.entity_id).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates process event documents', () => {
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const processEvent = generator.generateEvent({ timestamp });
|
||||||
|
expect(processEvent['@timestamp']).toEqual(timestamp);
|
||||||
|
expect(processEvent.event.category).toEqual('process');
|
||||||
|
expect(processEvent.event.kind).toEqual('event');
|
||||||
|
expect(processEvent.event.type).toEqual('creation');
|
||||||
|
expect(processEvent.agent).not.toBeNull();
|
||||||
|
expect(processEvent.host).not.toBeNull();
|
||||||
|
expect(processEvent.process.entity_id).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates other event documents', () => {
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const processEvent = generator.generateEvent({ timestamp, eventCategory: 'dns' });
|
||||||
|
expect(processEvent['@timestamp']).toEqual(timestamp);
|
||||||
|
expect(processEvent.event.category).toEqual('dns');
|
||||||
|
expect(processEvent.event.kind).toEqual('event');
|
||||||
|
expect(processEvent.event.type).toEqual('creation');
|
||||||
|
expect(processEvent.agent).not.toBeNull();
|
||||||
|
expect(processEvent.host).not.toBeNull();
|
||||||
|
expect(processEvent.process.entity_id).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('creates alert ancestor tree', () => {
|
||||||
|
let events: Event[];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
events = generator.generateAlertEventAncestry(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with n-1 process events', () => {
|
||||||
|
for (let i = 1; i < events.length - 1; i++) {
|
||||||
|
expect(events[i].process.parent?.entity_id).toEqual(events[i - 1].process.entity_id);
|
||||||
|
expect(events[i].event.kind).toEqual('event');
|
||||||
|
expect(events[i].event.category).toEqual('process');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with a corresponding alert at the end', () => {
|
||||||
|
// The alert should be last and have the same entity_id as the previous process event
|
||||||
|
expect(events[events.length - 1].process.entity_id).toEqual(
|
||||||
|
events[events.length - 2].process.entity_id
|
||||||
|
);
|
||||||
|
expect(events[events.length - 1].process.parent?.entity_id).toEqual(
|
||||||
|
events[events.length - 2].process.parent?.entity_id
|
||||||
|
);
|
||||||
|
expect(events[events.length - 1].event.kind).toEqual('alert');
|
||||||
|
expect(events[events.length - 1].event.category).toEqual('malware');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildResolverTree(events: Event[]): Node {
|
||||||
|
// First pass we gather up all the events by entity_id
|
||||||
|
const tree: Record<string, Node> = {};
|
||||||
|
events.forEach(event => {
|
||||||
|
if (event.process.entity_id in tree) {
|
||||||
|
tree[event.process.entity_id].events.push(event);
|
||||||
|
} else {
|
||||||
|
tree[event.process.entity_id] = {
|
||||||
|
events: [event],
|
||||||
|
children: [],
|
||||||
|
parent_entity_id: event.process.parent?.entity_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Second pass add child references to each node
|
||||||
|
for (const value of Object.values(tree)) {
|
||||||
|
if (value.parent_entity_id) {
|
||||||
|
tree[value.parent_entity_id].children.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The root node must be first in the array or this fails
|
||||||
|
return tree[events[0].process.entity_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function countResolverEvents(rootNode: Node, generations: number): number {
|
||||||
|
// Start at the root, traverse N levels of the tree and check that we found all nodes
|
||||||
|
let nodes = [rootNode];
|
||||||
|
let visitedEvents = 0;
|
||||||
|
for (let i = 0; i < generations + 1; i++) {
|
||||||
|
let nextNodes: Node[] = [];
|
||||||
|
nodes.forEach(node => {
|
||||||
|
nextNodes = nextNodes.concat(node.children);
|
||||||
|
visitedEvents += node.events.length;
|
||||||
|
});
|
||||||
|
nodes = nextNodes;
|
||||||
|
}
|
||||||
|
return visitedEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
it('creates tree of process children', () => {
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const root = generator.generateEvent({ timestamp });
|
||||||
|
const generations = 2;
|
||||||
|
const events = generator.generateDescendantsTree(root, generations);
|
||||||
|
const rootNode = buildResolverTree(events);
|
||||||
|
const visitedEvents = countResolverEvents(rootNode, generations);
|
||||||
|
expect(visitedEvents).toEqual(events.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates full resolver tree', () => {
|
||||||
|
const alertAncestors = 3;
|
||||||
|
const generations = 2;
|
||||||
|
const events = generator.generateFullResolverTree(alertAncestors, generations);
|
||||||
|
const rootNode = buildResolverTree(events);
|
||||||
|
const visitedEvents = countResolverEvents(rootNode, alertAncestors + generations);
|
||||||
|
expect(visitedEvents).toEqual(events.length);
|
||||||
|
});
|
||||||
|
});
|
431
x-pack/plugins/endpoint/common/generate_data.ts
Normal file
431
x-pack/plugins/endpoint/common/generate_data.ts
Normal file
|
@ -0,0 +1,431 @@
|
||||||
|
/*
|
||||||
|
* 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 uuid from 'uuid';
|
||||||
|
import seedrandom from 'seedrandom';
|
||||||
|
import { AlertEvent, EndpointEvent, EndpointMetadata, OSFields } from './types';
|
||||||
|
|
||||||
|
export type Event = AlertEvent | EndpointEvent;
|
||||||
|
|
||||||
|
interface EventOptions {
|
||||||
|
timestamp?: number;
|
||||||
|
entityID?: string;
|
||||||
|
parentEntityID?: string;
|
||||||
|
eventType?: string;
|
||||||
|
eventCategory?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Windows: OSFields[] = [
|
||||||
|
{
|
||||||
|
name: 'windows 10.0',
|
||||||
|
full: 'Windows 10',
|
||||||
|
version: '10.0',
|
||||||
|
variant: 'Windows Pro',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'windows 10.0',
|
||||||
|
full: 'Windows Server 2016',
|
||||||
|
version: '10.0',
|
||||||
|
variant: 'Windows Server',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'windows 6.2',
|
||||||
|
full: 'Windows Server 2012',
|
||||||
|
version: '6.2',
|
||||||
|
variant: 'Windows Server',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'windows 6.3',
|
||||||
|
full: 'Windows Server 2012R2',
|
||||||
|
version: '6.3',
|
||||||
|
variant: 'Windows Server Release 2',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Linux: OSFields[] = [];
|
||||||
|
|
||||||
|
const Mac: OSFields[] = [];
|
||||||
|
|
||||||
|
const OS: OSFields[] = [...Windows, ...Mac, ...Linux];
|
||||||
|
|
||||||
|
const POLICIES: Array<{ name: string; id: string }> = [
|
||||||
|
{
|
||||||
|
name: 'Default',
|
||||||
|
id: '00000000-0000-0000-0000-000000000000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'With Eventing',
|
||||||
|
id: 'C2A9093E-E289-4C0A-AA44-8C32A414FA7A',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const FILE_OPERATIONS: string[] = ['creation', 'open', 'rename', 'execution', 'deletion'];
|
||||||
|
|
||||||
|
// These are from the v1 schemas and aren't all valid ECS event categories, still in flux
|
||||||
|
const OTHER_EVENT_CATEGORIES: string[] = ['driver', 'file', 'library', 'network', 'registry'];
|
||||||
|
|
||||||
|
export class EndpointDocGenerator {
|
||||||
|
agentId: string;
|
||||||
|
hostId: string;
|
||||||
|
hostname: string;
|
||||||
|
macAddress: string[];
|
||||||
|
ip: string[];
|
||||||
|
agentVersion: string;
|
||||||
|
os: OSFields;
|
||||||
|
policy: { name: string; id: string };
|
||||||
|
random: seedrandom.prng;
|
||||||
|
|
||||||
|
constructor(seed = Math.random().toString()) {
|
||||||
|
this.random = seedrandom(seed);
|
||||||
|
this.hostId = this.seededUUIDv4();
|
||||||
|
this.agentId = this.seededUUIDv4();
|
||||||
|
this.hostname = this.randomHostname();
|
||||||
|
this.ip = this.randomArray(3, () => this.randomIP());
|
||||||
|
this.macAddress = this.randomArray(3, () => this.randomMac());
|
||||||
|
this.agentVersion = this.randomVersion();
|
||||||
|
this.os = this.randomChoice(OS);
|
||||||
|
this.policy = this.randomChoice(POLICIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public randomizeIPs() {
|
||||||
|
this.ip = this.randomArray(3, () => this.randomIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateEndpointMetadata(ts = new Date().getTime()): EndpointMetadata {
|
||||||
|
return {
|
||||||
|
'@timestamp': ts,
|
||||||
|
event: {
|
||||||
|
created: ts,
|
||||||
|
},
|
||||||
|
endpoint: {
|
||||||
|
policy: {
|
||||||
|
id: this.policy.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
agent: {
|
||||||
|
version: this.agentVersion,
|
||||||
|
id: this.agentId,
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
id: this.hostId,
|
||||||
|
hostname: this.hostname,
|
||||||
|
ip: this.ip,
|
||||||
|
mac: this.macAddress,
|
||||||
|
os: this.os,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateAlert(
|
||||||
|
ts = new Date().getTime(),
|
||||||
|
entityID = this.randomString(10),
|
||||||
|
parentEntityID?: string
|
||||||
|
): AlertEvent {
|
||||||
|
return {
|
||||||
|
'@timestamp': ts,
|
||||||
|
agent: {
|
||||||
|
id: this.agentId,
|
||||||
|
version: this.agentVersion,
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
action: this.randomChoice(FILE_OPERATIONS),
|
||||||
|
kind: 'alert',
|
||||||
|
category: 'malware',
|
||||||
|
id: this.seededUUIDv4(),
|
||||||
|
dataset: 'endpoint',
|
||||||
|
module: 'endpoint',
|
||||||
|
type: 'creation',
|
||||||
|
},
|
||||||
|
endpoint: {
|
||||||
|
policy: {
|
||||||
|
id: this.policy.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
owner: 'SYSTEM',
|
||||||
|
name: 'fake_malware.exe',
|
||||||
|
path: 'C:/fake_malware.exe',
|
||||||
|
accessed: ts,
|
||||||
|
mtime: ts,
|
||||||
|
created: ts,
|
||||||
|
size: 3456,
|
||||||
|
hash: {
|
||||||
|
md5: 'fake file md5',
|
||||||
|
sha1: 'fake file sha1',
|
||||||
|
sha256: 'fake file sha256',
|
||||||
|
},
|
||||||
|
code_signature: {
|
||||||
|
trusted: false,
|
||||||
|
subject_name: 'bad signer',
|
||||||
|
},
|
||||||
|
malware_classifier: {
|
||||||
|
identifier: 'endpointpe',
|
||||||
|
score: 1,
|
||||||
|
threshold: 0.66,
|
||||||
|
version: '3.0.33',
|
||||||
|
},
|
||||||
|
temp_file_path: 'C:/temp/fake_malware.exe',
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
id: this.hostId,
|
||||||
|
hostname: this.hostname,
|
||||||
|
ip: this.ip,
|
||||||
|
mac: this.macAddress,
|
||||||
|
os: this.os,
|
||||||
|
},
|
||||||
|
process: {
|
||||||
|
pid: 2,
|
||||||
|
name: 'malware writer',
|
||||||
|
start: ts,
|
||||||
|
uptime: 0,
|
||||||
|
user: 'SYSTEM',
|
||||||
|
entity_id: entityID,
|
||||||
|
executable: 'C:/malware.exe',
|
||||||
|
parent: parentEntityID ? { entity_id: parentEntityID, pid: 1 } : undefined,
|
||||||
|
token: {
|
||||||
|
domain: 'NT AUTHORITY',
|
||||||
|
integrity_level: 16384,
|
||||||
|
integrity_level_name: 'system',
|
||||||
|
privileges: [
|
||||||
|
{
|
||||||
|
description: 'Replace a process level token',
|
||||||
|
enabled: false,
|
||||||
|
name: 'SeAssignPrimaryTokenPrivilege',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sid: 'S-1-5-18',
|
||||||
|
type: 'tokenPrimary',
|
||||||
|
user: 'SYSTEM',
|
||||||
|
},
|
||||||
|
code_signature: {
|
||||||
|
trusted: false,
|
||||||
|
subject_name: 'bad signer',
|
||||||
|
},
|
||||||
|
hash: {
|
||||||
|
md5: 'fake md5',
|
||||||
|
sha1: 'fake sha1',
|
||||||
|
sha256: 'fake sha256',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dll: [
|
||||||
|
{
|
||||||
|
pe: {
|
||||||
|
architecture: 'x64',
|
||||||
|
imphash: 'c30d230b81c734e82e86e2e2fe01cd01',
|
||||||
|
},
|
||||||
|
code_signature: {
|
||||||
|
subject_name: 'Cybereason Inc',
|
||||||
|
trusted: true,
|
||||||
|
},
|
||||||
|
compile_time: 1534424710,
|
||||||
|
hash: {
|
||||||
|
md5: '1f2d082566b0fc5f2c238a5180db7451',
|
||||||
|
sha1: 'ca85243c0af6a6471bdaa560685c51eefd6dbc0d',
|
||||||
|
sha256: '8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2',
|
||||||
|
},
|
||||||
|
malware_classifier: {
|
||||||
|
identifier: 'Whitelisted',
|
||||||
|
score: 0,
|
||||||
|
threshold: 0,
|
||||||
|
version: '3.0.0',
|
||||||
|
},
|
||||||
|
mapped_address: 5362483200,
|
||||||
|
mapped_size: 0,
|
||||||
|
path: 'C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateEvent(options: EventOptions = {}): EndpointEvent {
|
||||||
|
return {
|
||||||
|
'@timestamp': options.timestamp ? options.timestamp : new Date().getTime(),
|
||||||
|
agent: {
|
||||||
|
id: this.agentId,
|
||||||
|
version: this.agentVersion,
|
||||||
|
type: 'endpoint',
|
||||||
|
},
|
||||||
|
ecs: {
|
||||||
|
version: '1.4.0',
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
category: options.eventCategory ? options.eventCategory : 'process',
|
||||||
|
kind: 'event',
|
||||||
|
type: options.eventType ? options.eventType : 'creation',
|
||||||
|
id: this.seededUUIDv4(),
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
id: this.hostId,
|
||||||
|
hostname: this.hostname,
|
||||||
|
ip: this.ip,
|
||||||
|
mac: this.macAddress,
|
||||||
|
os: this.os,
|
||||||
|
},
|
||||||
|
process: {
|
||||||
|
entity_id: options.entityID ? options.entityID : this.randomString(10),
|
||||||
|
parent: options.parentEntityID ? { entity_id: options.parentEntityID } : undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateFullResolverTree(
|
||||||
|
alertAncestors?: number,
|
||||||
|
childGenerations?: number,
|
||||||
|
maxChildrenPerNode?: number,
|
||||||
|
relatedEventsPerNode?: number,
|
||||||
|
percentNodesWithRelated?: number,
|
||||||
|
percentChildrenTerminated?: number
|
||||||
|
): Event[] {
|
||||||
|
const ancestry = this.generateAlertEventAncestry(alertAncestors);
|
||||||
|
// ancestry will always have at least 2 elements, and the second to last element will be the process associated with the alert
|
||||||
|
const descendants = this.generateDescendantsTree(
|
||||||
|
ancestry[ancestry.length - 2],
|
||||||
|
childGenerations,
|
||||||
|
maxChildrenPerNode,
|
||||||
|
relatedEventsPerNode,
|
||||||
|
percentNodesWithRelated,
|
||||||
|
percentChildrenTerminated
|
||||||
|
);
|
||||||
|
return ancestry.concat(descendants);
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateAlertEventAncestry(alertAncestors = 3): Event[] {
|
||||||
|
const events = [];
|
||||||
|
const startDate = new Date().getTime();
|
||||||
|
const root = this.generateEvent({ timestamp: startDate + 1000 });
|
||||||
|
events.push(root);
|
||||||
|
let ancestor = root;
|
||||||
|
for (let i = 0; i < alertAncestors; i++) {
|
||||||
|
ancestor = this.generateEvent({
|
||||||
|
timestamp: startDate + 1000 * (i + 1),
|
||||||
|
parentEntityID: ancestor.process.entity_id,
|
||||||
|
});
|
||||||
|
events.push(ancestor);
|
||||||
|
}
|
||||||
|
events.push(
|
||||||
|
this.generateAlert(
|
||||||
|
startDate + 1000 * alertAncestors,
|
||||||
|
ancestor.process.entity_id,
|
||||||
|
ancestor.process.parent?.entity_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateDescendantsTree(
|
||||||
|
root: Event,
|
||||||
|
generations = 2,
|
||||||
|
maxChildrenPerNode = 2,
|
||||||
|
relatedEventsPerNode = 3,
|
||||||
|
percentNodesWithRelated = 100,
|
||||||
|
percentChildrenTerminated = 100
|
||||||
|
): Event[] {
|
||||||
|
let events: Event[] = [root];
|
||||||
|
let parents = [root];
|
||||||
|
let timestamp = root['@timestamp'];
|
||||||
|
for (let i = 0; i < generations; i++) {
|
||||||
|
const newParents: EndpointEvent[] = [];
|
||||||
|
parents.forEach(element => {
|
||||||
|
// const numChildren = randomN(maxChildrenPerNode);
|
||||||
|
const numChildren = maxChildrenPerNode;
|
||||||
|
for (let j = 0; j < numChildren; j++) {
|
||||||
|
timestamp = timestamp + 1000;
|
||||||
|
const child = this.generateEvent({
|
||||||
|
timestamp,
|
||||||
|
parentEntityID: element.process.entity_id,
|
||||||
|
});
|
||||||
|
newParents.push(child);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
events = events.concat(newParents);
|
||||||
|
parents = newParents;
|
||||||
|
}
|
||||||
|
const terminationEvents: EndpointEvent[] = [];
|
||||||
|
let relatedEvents: EndpointEvent[] = [];
|
||||||
|
events.forEach(element => {
|
||||||
|
if (this.randomN(100) < percentChildrenTerminated) {
|
||||||
|
timestamp = timestamp + 1000;
|
||||||
|
terminationEvents.push(
|
||||||
|
this.generateEvent({
|
||||||
|
timestamp,
|
||||||
|
entityID: element.process.entity_id,
|
||||||
|
parentEntityID: element.process.parent?.entity_id,
|
||||||
|
eventCategory: 'process',
|
||||||
|
eventType: 'end',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.randomN(100) < percentNodesWithRelated) {
|
||||||
|
relatedEvents = relatedEvents.concat(
|
||||||
|
this.generateRelatedEvents(element, relatedEventsPerNode)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
events = events.concat(terminationEvents);
|
||||||
|
events = events.concat(relatedEvents);
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateRelatedEvents(node: Event, numRelatedEvents = 10): EndpointEvent[] {
|
||||||
|
const ts = node['@timestamp'] + 1000;
|
||||||
|
const relatedEvents: EndpointEvent[] = [];
|
||||||
|
for (let i = 0; i < numRelatedEvents; i++) {
|
||||||
|
relatedEvents.push(
|
||||||
|
this.generateEvent({
|
||||||
|
timestamp: ts,
|
||||||
|
entityID: node.process.entity_id,
|
||||||
|
parentEntityID: node.process.parent?.entity_id,
|
||||||
|
eventCategory: this.randomChoice(OTHER_EVENT_CATEGORIES),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return relatedEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomN(n: number): number {
|
||||||
|
return Math.floor(this.random() * n);
|
||||||
|
}
|
||||||
|
|
||||||
|
private *randomNGenerator(max: number, count: number) {
|
||||||
|
while (count > 0) {
|
||||||
|
yield this.randomN(max);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomArray<T>(lengthLimit: number, generator: () => T): T[] {
|
||||||
|
const rand = this.randomN(lengthLimit) + 1;
|
||||||
|
return [...Array(rand).keys()].map(generator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomMac(): string {
|
||||||
|
return [...this.randomNGenerator(255, 6)].map(x => x.toString(16)).join('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomIP(): string {
|
||||||
|
return [10, ...this.randomNGenerator(255, 3)].map(x => x.toString()).join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomVersion(): string {
|
||||||
|
return [6, ...this.randomNGenerator(10, 2)].map(x => x.toString()).join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomChoice<T>(choices: T[]): T {
|
||||||
|
return choices[this.randomN(choices.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomString(length: number): string {
|
||||||
|
return [...this.randomNGenerator(36, length)].map(x => x.toString(36)).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomHostname(): string {
|
||||||
|
return `Host-${this.randomString(10)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private seededUUIDv4(): string {
|
||||||
|
return uuid.v4({ random: [...this.randomNGenerator(255, 16)] });
|
||||||
|
}
|
||||||
|
}
|
|
@ -167,29 +167,34 @@ export type AlertEvent = Immutable<{
|
||||||
module: string;
|
module: string;
|
||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
|
endpoint: {
|
||||||
|
policy: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
process: {
|
process: {
|
||||||
code_signature: {
|
code_signature: {
|
||||||
subject_name: string;
|
subject_name: string;
|
||||||
trusted: boolean;
|
trusted: boolean;
|
||||||
};
|
};
|
||||||
command_line: string;
|
command_line?: string;
|
||||||
domain: string;
|
domain?: string;
|
||||||
pid: number;
|
pid: number;
|
||||||
ppid: number;
|
ppid?: number;
|
||||||
entity_id: string;
|
entity_id: string;
|
||||||
parent: {
|
parent?: {
|
||||||
pid: number;
|
pid: number;
|
||||||
entity_id: string;
|
entity_id: string;
|
||||||
};
|
};
|
||||||
name: string;
|
name: string;
|
||||||
hash: HashFields;
|
hash: HashFields;
|
||||||
pe: {
|
pe?: {
|
||||||
imphash: string;
|
imphash: string;
|
||||||
};
|
};
|
||||||
executable: string;
|
executable: string;
|
||||||
sid: string;
|
sid?: string;
|
||||||
start: number;
|
start: number;
|
||||||
malware_classifier: MalwareClassifierFields;
|
malware_classifier?: MalwareClassifierFields;
|
||||||
token: {
|
token: {
|
||||||
domain: string;
|
domain: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
@ -197,9 +202,9 @@ export type AlertEvent = Immutable<{
|
||||||
sid: string;
|
sid: string;
|
||||||
integrity_level: number;
|
integrity_level: number;
|
||||||
integrity_level_name: string;
|
integrity_level_name: string;
|
||||||
privileges: PrivilegesFields[];
|
privileges?: PrivilegesFields[];
|
||||||
};
|
};
|
||||||
thread: ThreadFields[];
|
thread?: ThreadFields[];
|
||||||
uptime: number;
|
uptime: number;
|
||||||
user: string;
|
user: string;
|
||||||
};
|
};
|
||||||
|
@ -212,32 +217,20 @@ export type AlertEvent = Immutable<{
|
||||||
created: number;
|
created: number;
|
||||||
size: number;
|
size: number;
|
||||||
hash: HashFields;
|
hash: HashFields;
|
||||||
pe: {
|
pe?: {
|
||||||
imphash: string;
|
imphash: string;
|
||||||
};
|
};
|
||||||
code_signature: {
|
code_signature: {
|
||||||
trusted: boolean;
|
trusted: boolean;
|
||||||
subject_name: string;
|
subject_name: string;
|
||||||
};
|
};
|
||||||
malware_classifier: {
|
malware_classifier: MalwareClassifierFields;
|
||||||
features: {
|
|
||||||
data: {
|
|
||||||
buffer: string;
|
|
||||||
decompressed_size: number;
|
|
||||||
encoding: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} & MalwareClassifierFields;
|
|
||||||
temp_file_path: string;
|
temp_file_path: string;
|
||||||
};
|
};
|
||||||
host: HostFields;
|
host: HostFields;
|
||||||
thread: {};
|
dll?: DllFields[];
|
||||||
dll: DllFields[];
|
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
/**
|
|
||||||
* Metadata associated with an alert event.
|
|
||||||
*/
|
|
||||||
interface AlertMetadata {
|
interface AlertMetadata {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
|
@ -252,9 +245,9 @@ interface AlertMetadata {
|
||||||
export type AlertData = AlertEvent & AlertMetadata;
|
export type AlertData = AlertEvent & AlertMetadata;
|
||||||
|
|
||||||
export interface EndpointMetadata {
|
export interface EndpointMetadata {
|
||||||
'@timestamp': string;
|
'@timestamp': number;
|
||||||
event: {
|
event: {
|
||||||
created: Date;
|
created: number;
|
||||||
};
|
};
|
||||||
endpoint: {
|
endpoint: {
|
||||||
policy: {
|
policy: {
|
||||||
|
@ -262,8 +255,8 @@ export interface EndpointMetadata {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
agent: {
|
agent: {
|
||||||
version: string;
|
|
||||||
id: string;
|
id: string;
|
||||||
|
version: string;
|
||||||
};
|
};
|
||||||
host: HostFields;
|
host: HostFields;
|
||||||
}
|
}
|
||||||
|
@ -310,22 +303,32 @@ export interface LegacyEndpointEvent {
|
||||||
|
|
||||||
export interface EndpointEvent {
|
export interface EndpointEvent {
|
||||||
'@timestamp': number;
|
'@timestamp': number;
|
||||||
|
agent: {
|
||||||
|
id: string;
|
||||||
|
version: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
ecs: {
|
||||||
|
version: string;
|
||||||
|
};
|
||||||
event: {
|
event: {
|
||||||
category: string;
|
category: string;
|
||||||
type: string;
|
type: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
kind: string;
|
||||||
};
|
};
|
||||||
endpoint: {
|
host: {
|
||||||
process: {
|
|
||||||
entity_id: string;
|
|
||||||
parent: {
|
|
||||||
entity_id: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
agent: {
|
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
hostname: string;
|
||||||
|
ip: string[];
|
||||||
|
mac: string[];
|
||||||
|
os: OSFields;
|
||||||
|
};
|
||||||
|
process: {
|
||||||
|
entity_id: string;
|
||||||
|
parent?: {
|
||||||
|
entity_id: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
"license": "Elastic-License",
|
"license": "Elastic-License",
|
||||||
"scripts": {},
|
"scripts": {},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-redux": "^7.1.0"
|
"react-redux": "^7.1.0",
|
||||||
|
"seedrandom": "^3.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/seedrandom": ">=2.0.0 <4.0.0",
|
||||||
"@types/react-redux": "^7.1.0",
|
"@types/react-redux": "^7.1.0",
|
||||||
"redux-devtools-extension": "^2.13.8"
|
"redux-devtools-extension": "^2.13.8"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AlertResultList } from '../../../../../common/types';
|
import { AlertResultList } from '../../../../../common/types';
|
||||||
|
import { EndpointDocGenerator } from '../../../../../common/generate_data';
|
||||||
|
|
||||||
export const mockAlertResultList: (options?: {
|
export const mockAlertResultList: (options?: {
|
||||||
total?: number;
|
total?: number;
|
||||||
|
@ -24,160 +25,15 @@ export const mockAlertResultList: (options?: {
|
||||||
const actualCountToReturn = Math.max(Math.min(total - numberToSkip, requestPageSize), 0);
|
const actualCountToReturn = Math.max(Math.min(total - numberToSkip, requestPageSize), 0);
|
||||||
|
|
||||||
const alerts = [];
|
const alerts = [];
|
||||||
|
const generator = new EndpointDocGenerator();
|
||||||
for (let index = 0; index < actualCountToReturn; index++) {
|
for (let index = 0; index < actualCountToReturn; index++) {
|
||||||
alerts.push({
|
alerts.push({
|
||||||
'@timestamp': 1542341895000,
|
...generator.generateAlert(new Date().getTime() + index * 1000),
|
||||||
id: 'xDUYMHABAJk0XnHd8rrd',
|
...{
|
||||||
agent: {
|
id: 'xDUYMHABAJk0XnHd8rrd' + index,
|
||||||
id: 'ced9c68e-b94a-4d66-bb4c-6106514f0a2f',
|
prev: null,
|
||||||
version: '3.0.0',
|
next: null,
|
||||||
},
|
},
|
||||||
host: {
|
|
||||||
id: 'xrctvybuni',
|
|
||||||
hostname: 'HD-c15-bc09190a',
|
|
||||||
ip: ['10.179.244.14'],
|
|
||||||
mac: ['xsertcyvbunimkn56edtyf'],
|
|
||||||
os: {
|
|
||||||
full: 'Windows 10',
|
|
||||||
name: 'windows',
|
|
||||||
version: '10',
|
|
||||||
variant: '3',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
thread: {},
|
|
||||||
prev: null,
|
|
||||||
next: null,
|
|
||||||
event: {
|
|
||||||
id: '2f1c0928-3876-4e11-acbb-9199257c7b1c',
|
|
||||||
action: 'creation',
|
|
||||||
category: 'malware',
|
|
||||||
dataset: 'endpoint',
|
|
||||||
kind: 'alert',
|
|
||||||
module: 'endpoint',
|
|
||||||
type: 'creation',
|
|
||||||
},
|
|
||||||
file: {
|
|
||||||
accessed: 1542789400,
|
|
||||||
created: 1542789400,
|
|
||||||
hash: {
|
|
||||||
md5: '4ace3baaa509d08510405e1b169e325b',
|
|
||||||
sha1: '27fb21cf5db95ffca43b234affa99becc4023b9d',
|
|
||||||
sha256: '6ed1c836dbf099be7845bdab7671def2c157643761b52251e04e9b6ee109ec75',
|
|
||||||
},
|
|
||||||
pe: {
|
|
||||||
imphash: '835d619dfdf3cc727cebd91300ab3462',
|
|
||||||
},
|
|
||||||
mtime: 1542789400,
|
|
||||||
owner: 'Administrators',
|
|
||||||
name: 'test name',
|
|
||||||
path: 'C:\\Windows\\TEMP\\tmp0000008f\\tmp00001be5',
|
|
||||||
size: 188416,
|
|
||||||
code_signature: {
|
|
||||||
subject_name: 'Cybereason Inc',
|
|
||||||
trusted: false,
|
|
||||||
},
|
|
||||||
malware_classifier: {
|
|
||||||
features: {
|
|
||||||
data: {
|
|
||||||
buffer:
|
|
||||||
'eAHtnU1oHHUUwHsQ7MGDiIIUD4sH8WBBxJtopiLoUY0pYo2ZTbJJ0yQ17m4+ms/NRzeVWpuUWCL4sWlEYvFQ8KJQ6NCTEA8eRD30sIo3PdSriLi7837Pko3LbHZ2M5m+XObHm/d/X////83O7jCZvzacHBpPplNdfalkdjSdyty674Ft59dN71Dpb9v5eKh8LMEHjsCF2wIfVlRKsHROYPGkQO5+gY2vBSYYdWZFYGwEO/cITHMqkxPYnBBY+07gtCuQ9gSGigJ5lPPYGXcE+jA4z3Ad1ZtAUiDUyrEEPYzqRnIKgxd/Rgc7gygPo5wn95PouN7OeEYJ1UXiJgRmvscgp/LOziIkkSyT+xRVnXhZ4DKh5goCkzidRHkGO4uvCyw9LDDtCay8ILCAzrJOJaGuZwUuvSewivJVIPsklq8JbL4qMJsTSCcExrGs83WKU295ZFo5lr2TaZbcUw5FeJy8tgTeLpCy2iGeS67ABXzlgbEi1UC5FxcZnA4y/CLK82Qxi847FGGZRTLsCUxR1aWEwOp1AmOjDRYYzgwusL9WfqBiGJxnVAanixTq7Dp22LBdlWMJzlOx8wmBK2Rx5WmBLJIRwtAijOQE+ooCb2B5xBOYRtlfNeXpLpA7oyZRTqHzGenkmIJPnhBIMrzTwSA6H93CO5l+c1NA99f6IwLH8fUKdjTmDpTbgS50+gGVnECnE4PpooC2guPoaPADSHrcncNHmEHtAFkq3+EI+A37zsrrTvH3WTkvJLoOTyBp10wx2JcgVCRahA4NrICE4a+hrMXsA3qAHItW188E8ejO7XV3eh/KCYwxlamEwCgL8lN2wTntfrhY/U0g/5KAdvUpT+AszWqBdqH7VLeeZrExK9Cv1UgIDKA8g/cx7QAEP+AhAfRaMKB2HOJh+BSFSqKjSytNGBlc6PrpxvK7lCVDxbSG3Z7AhCMwx6gelwgLAltXBXJUTH29j+U1LHdipx/QprfKfGnF0sBpdBYxmEQyTzW0h6/0khcuhhJYRufym+i4VKMocJMs/KvfoW3/UJb4PeZOSZVONThZz4djP/75TAXa/CVfOvX3RgVLIDreLPN1pP1osW7lGmHsEhjBOzf+EPBE4vndvWz5xb/cChxGcv1LAb+tluALKnZ47isf1MXvz1ZMlsCXbXtPceqhrcp1ps6YHwQeBXLEPCf7q23tl9uJui0bGBgYRAccv7uXr/g5Af+2oNTrpgTa/vnpjBvpLAwM4gRBPvIZGBgYGBgYGBgYGBgYGBgYGBgYGBgYNAOc9oMXs4GBgYFBcNBnww5QzDXgRtPSaZ5lg/itsRaslgZ3bnWEEVnhMetIBwiiVnlbCbWrEftrt11zdwWnseFW1QO63w1is3ptD1pV9xG0t+zvfUrzrvh380qwXWAVCw6h78GIfG7ZlzltXu6hd+y92fECRFhjuH3bXG8N43oXEHperdzvUbteaDxhVTUeq25fqhG1X6Ai8mtF6BDXz2wR+dzSgg4Qsxls5T11XMG+82y8GkG+b7kL69xg7mF1SFvhBgYGsYH/Xi7HE+PVkiB2jt1bNZxT+k4558jR53ydz5//1m1KOgYGBgYGBgYGEQfnsYaG2z1sdPJS79XQSu91ndobOAHCaN5vNzUk1bceQVzUpbw3iOuT+UFmR18bHrp3gyhDC56lCd1y85w2+HSNUwVhhdGC7blLf+bV/fqtvhMg1NDjCcugB1QXswbs8ekj/v1BgzFHBIIsyP+HfwFdMpzu',
|
|
||||||
decompressed_size: 27831,
|
|
||||||
encoding: 'zlib',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
identifier: 'endpointpe',
|
|
||||||
score: 1,
|
|
||||||
threshold: 0.66,
|
|
||||||
version: '3.0.33',
|
|
||||||
},
|
|
||||||
temp_file_path: 'C:\\Windows\\TEMP\\1bb9abfc-ca14-47b2-9f2c-10c323df42f9',
|
|
||||||
},
|
|
||||||
process: {
|
|
||||||
pid: 1076,
|
|
||||||
ppid: 432,
|
|
||||||
entity_id: 'wertqwer',
|
|
||||||
parent: {
|
|
||||||
pid: 432,
|
|
||||||
entity_id: 'adsfsdaf',
|
|
||||||
},
|
|
||||||
name: 'test name',
|
|
||||||
code_signature: {
|
|
||||||
subject_name: 'Cybereason Inc',
|
|
||||||
trusted: true,
|
|
||||||
},
|
|
||||||
command_line: '"C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe"',
|
|
||||||
domain: 'NT AUTHORITY',
|
|
||||||
executable: 'C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe',
|
|
||||||
hash: {
|
|
||||||
md5: '1f2d082566b0fc5f2c238a5180db7451',
|
|
||||||
sha1: 'ca85243c0af6a6471bdaa560685c51eefd6dbc0d',
|
|
||||||
sha256: '8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2',
|
|
||||||
},
|
|
||||||
pe: {
|
|
||||||
imphash: 'c30d230b81c734e82e86e2e2fe01cd01',
|
|
||||||
},
|
|
||||||
malware_classifier: {
|
|
||||||
identifier: 'Whitelisted',
|
|
||||||
score: 0,
|
|
||||||
threshold: 0,
|
|
||||||
version: '3.0.0',
|
|
||||||
},
|
|
||||||
thread: [
|
|
||||||
{
|
|
||||||
id: 1652,
|
|
||||||
service_name: 'CybereasonAntiMalware',
|
|
||||||
start: 1542788400,
|
|
||||||
start_address: 8791698721056,
|
|
||||||
start_address_module: 'C:\\Program Files\\Cybereason ActiveProbe\\gzfltum.dll',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
sid: 'S-1-5-18',
|
|
||||||
start: 1542788400,
|
|
||||||
token: {
|
|
||||||
domain: 'NT AUTHORITY',
|
|
||||||
integrity_level: 16384,
|
|
||||||
integrity_level_name: 'system',
|
|
||||||
privileges: [
|
|
||||||
{
|
|
||||||
description: 'Replace a process level token',
|
|
||||||
enabled: false,
|
|
||||||
name: 'SeAssignPrimaryTokenPrivilege',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
sid: 'S-1-5-18',
|
|
||||||
type: 'tokenPrimary',
|
|
||||||
user: 'SYSTEM',
|
|
||||||
},
|
|
||||||
uptime: 1025,
|
|
||||||
user: 'SYSTEM',
|
|
||||||
},
|
|
||||||
dll: [
|
|
||||||
{
|
|
||||||
pe: {
|
|
||||||
architecture: 'x64',
|
|
||||||
imphash: 'c30d230b81c734e82e86e2e2fe01cd01',
|
|
||||||
},
|
|
||||||
code_signature: {
|
|
||||||
subject_name: 'Cybereason Inc',
|
|
||||||
trusted: true,
|
|
||||||
},
|
|
||||||
compile_time: 1534424710,
|
|
||||||
hash: {
|
|
||||||
md5: '1f2d082566b0fc5f2c238a5180db7451',
|
|
||||||
sha1: 'ca85243c0af6a6471bdaa560685c51eefd6dbc0d',
|
|
||||||
sha256: '8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2',
|
|
||||||
},
|
|
||||||
malware_classifier: {
|
|
||||||
identifier: 'Whitelisted',
|
|
||||||
score: 0,
|
|
||||||
threshold: 0,
|
|
||||||
version: '3.0.0',
|
|
||||||
},
|
|
||||||
mapped_address: 5362483200,
|
|
||||||
mapped_size: 0,
|
|
||||||
path: 'C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const mock: AlertResultList = {
|
const mock: AlertResultList = {
|
||||||
|
|
|
@ -7,44 +7,20 @@
|
||||||
import { createStore, Dispatch, Store } from 'redux';
|
import { createStore, Dispatch, Store } from 'redux';
|
||||||
import { ManagementAction, managementListReducer } from './index';
|
import { ManagementAction, managementListReducer } from './index';
|
||||||
import { EndpointMetadata } from '../../../../../common/types';
|
import { EndpointMetadata } from '../../../../../common/types';
|
||||||
|
import { EndpointDocGenerator } from '../../../../../common/generate_data';
|
||||||
import { ManagementListState } from '../../types';
|
import { ManagementListState } from '../../types';
|
||||||
import { listData } from './selectors';
|
import { listData } from './selectors';
|
||||||
|
|
||||||
describe('endpoint_list store concerns', () => {
|
describe('endpoint_list store concerns', () => {
|
||||||
let store: Store<ManagementListState>;
|
let store: Store<ManagementListState>;
|
||||||
let dispatch: Dispatch<ManagementAction>;
|
let dispatch: Dispatch<ManagementAction>;
|
||||||
|
const generator = new EndpointDocGenerator();
|
||||||
const createTestStore = () => {
|
const createTestStore = () => {
|
||||||
store = createStore(managementListReducer);
|
store = createStore(managementListReducer);
|
||||||
dispatch = store.dispatch;
|
dispatch = store.dispatch;
|
||||||
};
|
};
|
||||||
const generateEndpoint = (): EndpointMetadata => {
|
const generateEndpoint = (): EndpointMetadata => {
|
||||||
return {
|
return generator.generateEndpointMetadata(new Date().getTime());
|
||||||
'@timestamp': new Date(1582231151055).toString(),
|
|
||||||
event: {
|
|
||||||
created: new Date(0),
|
|
||||||
},
|
|
||||||
endpoint: {
|
|
||||||
policy: {
|
|
||||||
id: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
agent: {
|
|
||||||
version: '',
|
|
||||||
id: '',
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
id: '',
|
|
||||||
hostname: '',
|
|
||||||
ip: [''],
|
|
||||||
mac: [''],
|
|
||||||
os: {
|
|
||||||
name: '',
|
|
||||||
full: '',
|
|
||||||
version: '',
|
|
||||||
variant: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
const loadDataToStore = () => {
|
const loadDataToStore = () => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { coreMock } from '../../../../../../../../src/core/public/mocks';
|
||||||
import { History, createBrowserHistory } from 'history';
|
import { History, createBrowserHistory } from 'history';
|
||||||
import { managementListReducer, managementMiddlewareFactory } from './index';
|
import { managementListReducer, managementMiddlewareFactory } from './index';
|
||||||
import { EndpointMetadata, EndpointResultList } from '../../../../../common/types';
|
import { EndpointMetadata, EndpointResultList } from '../../../../../common/types';
|
||||||
|
import { EndpointDocGenerator } from '../../../../../common/generate_data';
|
||||||
import { ManagementListState } from '../../types';
|
import { ManagementListState } from '../../types';
|
||||||
import { AppAction } from '../action';
|
import { AppAction } from '../action';
|
||||||
import { listData } from './selectors';
|
import { listData } from './selectors';
|
||||||
|
@ -19,38 +20,14 @@ describe('endpoint list saga', () => {
|
||||||
let store: Store<ManagementListState>;
|
let store: Store<ManagementListState>;
|
||||||
let getState: typeof store['getState'];
|
let getState: typeof store['getState'];
|
||||||
let dispatch: Dispatch<AppAction>;
|
let dispatch: Dispatch<AppAction>;
|
||||||
let history: History<never>;
|
|
||||||
|
|
||||||
|
const generator = new EndpointDocGenerator();
|
||||||
// https://github.com/elastic/endpoint-app-team/issues/131
|
// https://github.com/elastic/endpoint-app-team/issues/131
|
||||||
const generateEndpoint = (): EndpointMetadata => {
|
const generateEndpoint = (): EndpointMetadata => {
|
||||||
return {
|
return generator.generateEndpointMetadata(new Date().getTime());
|
||||||
'@timestamp': new Date(1582231151055).toString(),
|
|
||||||
event: {
|
|
||||||
created: new Date(0),
|
|
||||||
},
|
|
||||||
endpoint: {
|
|
||||||
policy: {
|
|
||||||
id: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
agent: {
|
|
||||||
version: '',
|
|
||||||
id: '',
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
id: '',
|
|
||||||
hostname: '',
|
|
||||||
ip: [''],
|
|
||||||
mac: [''],
|
|
||||||
os: {
|
|
||||||
name: '',
|
|
||||||
full: '',
|
|
||||||
version: '',
|
|
||||||
variant: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let history: History<never>;
|
||||||
const getEndpointListApiResponse = (): EndpointResultList => {
|
const getEndpointListApiResponse = (): EndpointResultList => {
|
||||||
return {
|
return {
|
||||||
endpoints: [generateEndpoint()],
|
endpoints: [generateEndpoint()],
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EndpointResultList } from '../../../../../common/types';
|
import { EndpointResultList } from '../../../../../common/types';
|
||||||
|
import { EndpointDocGenerator } from '../../../../../common/generate_data';
|
||||||
|
|
||||||
export const mockHostResultList: (options?: {
|
export const mockHostResultList: (options?: {
|
||||||
total?: number;
|
total?: number;
|
||||||
|
@ -25,33 +26,8 @@ export const mockHostResultList: (options?: {
|
||||||
|
|
||||||
const endpoints = [];
|
const endpoints = [];
|
||||||
for (let index = 0; index < actualCountToReturn; index++) {
|
for (let index = 0; index < actualCountToReturn; index++) {
|
||||||
endpoints.push({
|
const generator = new EndpointDocGenerator('seed');
|
||||||
'@timestamp': new Date(1582231151055).toString(),
|
endpoints.push(generator.generateEndpointMetadata());
|
||||||
event: {
|
|
||||||
created: new Date('2020-02-20T20:39:11.055Z'),
|
|
||||||
},
|
|
||||||
endpoint: {
|
|
||||||
policy: {
|
|
||||||
id: '00000000-0000-0000-0000-000000000000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
agent: {
|
|
||||||
version: '6.9.2',
|
|
||||||
id: '9a87fdac-e6c0-4f27-a25c-e349e7093cb1',
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
id: '3ca26fe5-1c7d-42b8-8763-98256d161c9f',
|
|
||||||
hostname: 'bea-0.example.com',
|
|
||||||
ip: ['10.154.150.114', '10.43.37.62', '10.217.73.149'],
|
|
||||||
mac: ['ea-5a-a8-c0-5-95', '7e-d8-fe-7f-b6-4e', '23-31-5d-af-e6-2b'],
|
|
||||||
os: {
|
|
||||||
name: 'windows 6.2',
|
|
||||||
full: 'Windows Server 2012',
|
|
||||||
version: '6.2',
|
|
||||||
variant: 'Windows Server Release 2',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
const mock: EndpointResultList = {
|
const mock: EndpointResultList = {
|
||||||
endpoints,
|
endpoints,
|
||||||
|
|
|
@ -51,13 +51,13 @@ export const SourceProcessAccordion = memo(({ alertData }: { alertData: Immutabl
|
||||||
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.malwareScore', {
|
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.malwareScore', {
|
||||||
defaultMessage: 'MalwareScore',
|
defaultMessage: 'MalwareScore',
|
||||||
}),
|
}),
|
||||||
description: alertData.process.malware_classifier.score,
|
description: alertData.process.malware_classifier?.score || '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.parentProcessID', {
|
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.parentProcessID', {
|
||||||
defaultMessage: 'Parent Process ID',
|
defaultMessage: 'Parent Process ID',
|
||||||
}),
|
}),
|
||||||
description: alertData.process.parent.pid,
|
description: alertData.process.parent?.pid || '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.signer', {
|
title: i18n.translate('xpack.endpoint.application.endpoint.alertDetails.signer', {
|
||||||
|
|
|
@ -21,7 +21,7 @@ export function extractEntityID(event: ResolverEvent) {
|
||||||
if (isLegacyData(event)) {
|
if (isLegacyData(event)) {
|
||||||
return String(event.endgame.unique_pid);
|
return String(event.endgame.unique_pid);
|
||||||
}
|
}
|
||||||
return event.endpoint.process.entity_id;
|
return event.process.entity_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractParentEntityID(event: ResolverEvent) {
|
export function extractParentEntityID(event: ResolverEvent) {
|
||||||
|
@ -29,5 +29,5 @@ export function extractParentEntityID(event: ResolverEvent) {
|
||||||
const ppid = event.endgame.unique_ppid;
|
const ppid = event.endgame.unique_ppid;
|
||||||
return ppid && String(ppid); // if unique_ppid is undefined return undefined
|
return ppid && String(ppid); // if unique_ppid is undefined return undefined
|
||||||
}
|
}
|
||||||
return event.endpoint.process.parent?.entity_id;
|
return event.process.parent?.entity_id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5169,6 +5169,11 @@
|
||||||
"@types/tough-cookie" "*"
|
"@types/tough-cookie" "*"
|
||||||
form-data "^2.5.0"
|
form-data "^2.5.0"
|
||||||
|
|
||||||
|
"@types/seedrandom@>=2.0.0 <4.0.0":
|
||||||
|
version "2.4.28"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.28.tgz#9ce8fa048c1e8c85cb71d7fe4d704e000226036f"
|
||||||
|
integrity sha512-SMA+fUwULwK7sd/ZJicUztiPs8F1yCPwF3O23Z9uQ32ME5Ha0NmDK9+QTsYE4O2tHXChzXomSWWeIhCnoN1LqA==
|
||||||
|
|
||||||
"@types/selenium-webdriver@^4.0.5":
|
"@types/selenium-webdriver@^4.0.5":
|
||||||
version "4.0.5"
|
version "4.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.5.tgz#23041a4948c82daf2df9836e4d2358fec10d3e24"
|
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.5.tgz#23041a4948c82daf2df9836e4d2358fec10d3e24"
|
||||||
|
|
Loading…
Reference in a new issue