Skip to content

Commit

Permalink
Merge branch 'master' into integrations-kibana-assets
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Nov 3, 2020
2 parents c206f21 + 1117800 commit 8e774ef
Show file tree
Hide file tree
Showing 28 changed files with 392 additions and 71 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,21 @@ target
.idea
*.iml
*.log

# Ignore certain functional test runner artifacts
/test/*/failure_debug
/test/*/screenshots/diff
/test/*/screenshots/failure
/test/*/screenshots/session
/test/*/screenshots/visual_regression_gallery.html

# Ignore the same artifacts in x-pack
/x-pack/test/*/failure_debug
/x-pack/test/*/screenshots/diff
/x-pack/test/*/screenshots/failure
/x-pack/test/*/screenshots/session
/x-pack/test/*/screenshots/visual_regression_gallery.html

/html_docs
.eslintcache
/plugins/
Expand Down
2 changes: 2 additions & 0 deletions test/functional/services/common/screenshots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export async function ScreenshotsProvider({ getService }: FtrProviderContext) {

if (updateBaselines) {
log.debug('Updating baseline snapshot');
// Make the directory if it doesn't exist
await mkdirAsync(dirname(baselinePath), { recursive: true });
await writeFileAsync(baselinePath, readFileSync(sessionPath));
return 0;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ export function mockTreeWithNoAncestorsAnd2Children({
const secondChild: SafeResolverEvent = mockEndpointEvent({
pid: 2,
entityID: secondChildID,
processName: 'e',
processName:
'really_really_really_really_really_really_really_really_really_really_really_really_really_really_long_node_name',
parentEntityID: originID,
timestamp: 1600863932318,
});
Expand Down Expand Up @@ -388,5 +389,31 @@ export function mockTreeWithNoAncestorsAndTwoChildrenAndRelatedEventsOnOrigin({
eventCategory: 'registry',
}),
];
// Add one additional event for each category
const categories: string[] = [
'authentication',
'database',
'driver',
'file',
'host',
'iam',
'intrusion_detection',
'malware',
'network',
'package',
'process',
'web',
];
for (const category of categories) {
relatedEvents.push(
mockEndpointEvent({
entityID: originID,
parentEntityID,
eventID: `${relatedEvents.length}`,
eventType: 'access',
eventCategory: category,
})
);
}
return withRelatedEventsOnOrigin(baseTree, relatedEvents);
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ describe('Resolver, when analyzing a tree that has no ancestors and 2 children',
});
});

describe('Resolver, when analyzing a tree that has two related events for the origin', () => {
describe('Resolver, when analyzing a tree that has 2 related registry and 1 related event of all other categories for the origin node', () => {
beforeEach(async () => {
// create a mock data access layer with related events
const {
Expand Down Expand Up @@ -282,7 +282,21 @@ describe('Resolver, when analyzing a tree that has two related events for the or
simulator.map(() =>
simulator.testSubject('resolver:map:node-submenu-item').map((node) => node.text())
)
).toYieldEqualTo(['2 registry']);
).toYieldEqualTo([
'1 authentication',
'1 database',
'1 driver',
'1 file',
'1 host',
'1 iam',
'1 intrusion_detection',
'1 malware',
'1 network',
'1 package',
'1 process',
'2 registry',
'1 web',
]);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { urlSearch } from '../test_utilities/url_search';
// the resolver component instance ID, used by the react code to distinguish piece of global state from those used by other resolver instances
const resolverComponentInstanceID = 'resolverComponentInstanceID';

describe(`Resolver: when analyzing a tree with no ancestors and two children and two related registry event on the origin, and when the component instance ID is ${resolverComponentInstanceID}`, () => {
describe(`Resolver: when analyzing a tree with no ancestors and two children and 2 related registry events and 1 event of each other category on the origin, and when the component instance ID is ${resolverComponentInstanceID}`, () => {
/**
* Get (or lazily create and get) the simulator.
*/
Expand Down Expand Up @@ -272,22 +272,33 @@ describe(`Resolver: when analyzing a tree with no ancestors and two children and
await expect(
simulator().map(() => {
// The link text is split across two columns. The first column is the count and the second column has the type.
const typesAndCounts: Array<{ type: string; link: string }> = [];
const type = simulator().testSubject('resolver:panel:node-events:event-type-count');
const link = simulator().testSubject('resolver:panel:node-events:event-type-link');
return {
typeLength: type.length,
linkLength: link.length,
typeText: type.text(),
linkText: link.text(),
};
for (let index = 0; index < type.length; index++) {
typesAndCounts.push({
type: type.at(index).text(),
link: link.at(index).text(),
});
}
return typesAndCounts;
})
).toYieldEqualTo({
typeLength: 1,
linkLength: 1,
linkText: 'registry',
// EUI's Table adds the column name to the value.
typeText: 'Count2',
});
).toYieldEqualTo([
// Because there is no printed whitespace after "Count", the count immediately follows it.
{ link: 'registry', type: 'Count2' },
{ link: 'authentication', type: 'Count1' },
{ link: 'database', type: 'Count1' },
{ link: 'driver', type: 'Count1' },
{ link: 'file', type: 'Count1' },
{ link: 'host', type: 'Count1' },
{ link: 'iam', type: 'Count1' },
{ link: 'intrusion_detection', type: 'Count1' },
{ link: 'malware', type: 'Count1' },
{ link: 'network', type: 'Count1' },
{ link: 'package', type: 'Count1' },
{ link: 'process', type: 'Count1' },
{ link: 'web', type: 'Count1' },
]);
});
describe('and when the user clicks the registry events link', () => {
beforeEach(async () => {
Expand Down Expand Up @@ -377,7 +388,11 @@ describe(`Resolver: when analyzing a tree with no ancestors and two children and
.testSubject('resolver:node-list:node-link:title')
.map((node) => node.text());
})
).toYieldEqualTo(['c.ext', 'd', 'e']);
).toYieldEqualTo([
'c.ext',
'd',
'really_really_really_really_really_really_really_really_really_really_really_really_really_really_long_node_name',
]);
});
});
});
Expand Down
34 changes: 3 additions & 31 deletions x-pack/plugins/security_solution/public/resolver/view/submenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,15 @@ import { ResolverNodeStats } from '../../../common/endpoint/types';
import { useRelatedEventByCategoryNavigation } from './use_related_event_by_category_navigation';
import { useColors } from './use_colors';

/**
* i18n-translated titles for submenus and identifiers for display of states:
* initialMenuStatus: submenu before it has been opened / requested data
* menuError: if the submenu requested data, but received an error
*/
export const subMenuAssets = {
initialMenuStatus: i18n.translate(
'xpack.securitySolution.endpoint.resolver.relatedNotRetrieved',
{
defaultMessage: 'Related Events have not yet been retrieved.',
}
),
menuError: i18n.translate('xpack.securitySolution.endpoint.resolver.relatedRetrievalError', {
defaultMessage: 'There was an error retrieving related events.',
}),
relatedEvents: {
title: i18n.translate('xpack.securitySolution.endpoint.resolver.relatedEvents', {
defaultMessage: 'Events',
}),
},
};

interface ResolverSubmenuOption {
optionTitle: string;
action: () => unknown;
prefix?: number | JSX.Element;
}

/**
* Until browser support accomodates the `notation="compact"` feature of Intl.NumberFormat...
* exported for testing
* @param num The number to format
* @returns [mantissa ("12" in "12k+"), Scalar of compact notation (k,M,B,T), remainder indicator ("+" in "12k+")]
*/
export function compactNotationParts(num: number): [number, string, string] {
export function compactNotationParts(
num: number
): [mantissa: number, compactNotation: string, remainderIndicator: string] {
if (!Number.isFinite(num)) {
return [num, '', ''];
}
Expand Down Expand Up @@ -85,8 +59,6 @@ export function compactNotationParts(num: number): [number, string, string] {
return [Math.floor(num / scale), prefix, (num / scale) % 1 > Number.EPSILON ? hasRemainder : ''];
}

export type ResolverSubmenuOptionList = ResolverSubmenuOption[] | string;

/**
* A Submenu that displays a collection of "pills" for each related event
* category it has events for.
Expand Down
20 changes: 20 additions & 0 deletions x-pack/plugins/security_solution/server/lib/hosts/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('#buildFieldsTermAggregation', () => {
const fields: readonly string[] = [
'host.architecture',
'host.id',
'host.ip',
'host.name',
'host.os.family',
'host.os.name',
Expand Down Expand Up @@ -50,6 +51,25 @@ describe('#buildFieldsTermAggregation', () => {
},
},
},
host_ip: {
terms: {
script: {
source: "doc['host.ip']",
lang: 'painless',
},
size: 10,
order: {
timestamp: 'desc',
},
},
aggs: {
timestamp: {
max: {
field: '@timestamp',
},
},
},
},
host_name: {
terms: {
field: 'host.name',
Expand Down
24 changes: 24 additions & 0 deletions x-pack/plugins/security_solution/server/lib/hosts/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,30 @@ export const buildFieldsTermAggregation = (esFields: readonly string[]): Aggrega
);

const getTermsAggregationTypeFromField = (field: string): AggregationRequest => {
if (field === 'host.ip') {
return {
host_ip: {
terms: {
script: {
source: "doc['host.ip']",
lang: 'painless',
},
size: 10,
order: {
timestamp: 'desc',
},
},
aggs: {
timestamp: {
max: {
field: '@timestamp',
},
},
},
},
};
}

return {
[field.replace(/\./g, '_')]: {
terms: {
Expand Down
7 changes: 6 additions & 1 deletion x-pack/plugins/security_solution/server/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,13 @@ export interface MSearchHeader {
export interface AggregationRequest {
[aggField: string]: {
terms?: {
field: string;
field?: string;
missing?: string;
size?: number;
script?: {
source: string;
lang: string;
};
order?: {
[aggSortField: string]: SortRequestDirection;
};
Expand Down
Loading

0 comments on commit 8e774ef

Please sign in to comment.