Siem Overview page (#34108)

overview page
This commit is contained in:
Steph Milovic 2019-04-02 12:59:38 -06:00 committed by GitHub
parent 41c2ab38a3
commit 5869552272
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 8869 additions and 11 deletions

View file

@ -0,0 +1,33 @@
/*
* 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 { EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui';
import React from 'react';
import { pure } from 'recompose';
import { OverviewHostQuery } from '../../../../containers/overview/overview_host';
import { OverviewHostStats } from '../overview_host_stats';
import * as i18n from '../translations';
export interface OwnProps {
poll: number;
startDate: number;
endDate: number;
}
export const OverviewHost = pure<OwnProps>(({ endDate, poll, startDate }) => (
<EuiFlexItem>
<EuiPanel>
<EuiTitle>
<h2>{i18n.HOSTS_HEADING}</h2>
</EuiTitle>
<OverviewHostQuery endDate={endDate} poll={poll} sourceId="default" startDate={startDate}>
{({ overviewHost }) => <OverviewHostStats data={overviewHost} />}
</OverviewHostQuery>
</EuiPanel>
</EuiFlexItem>
));

View file

@ -0,0 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Overview Host Data rendering it renders the default OverviewHostStats 1`] = `
<Component
data={
Object {
"auditbeatAuditd": 73847,
"auditbeatFIM": 107307,
"auditbeatLogin": 60015,
"auditbeatPackage": 2003,
"auditbeatProcess": 1200,
"auditbeatUser": 1979,
}
}
/>
`;

View file

@ -0,0 +1,21 @@
/*
* 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 { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import * as React from 'react';
import { OverviewHostStats } from '.';
import { mockData } from './mock';
describe('Overview Host Data', () => {
describe('rendering', () => {
test('it renders the default OverviewHostStats', () => {
const wrapper = shallow(<OverviewHostStats data={mockData.OverviewHost} />);
expect(toJson(wrapper)).toMatchSnapshot();
});
});
});

View file

@ -0,0 +1,80 @@
/*
* 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 {
// @ts-ignore
EuiStat,
} from '@elastic/eui';
import numeral from '@elastic/numeral';
import { has } from 'lodash/fp';
import React from 'react';
import { pure } from 'recompose';
import { OverviewHostData } from '../../../../graphql/types';
import { getEmptyTagValue } from '../../../empty_value';
import * as i18n from '../translations';
interface OverviewHostProps {
data: OverviewHostData;
}
const overviewHostStats = (data: OverviewHostData) => [
{
title:
has('auditbeatAuditd', data) && data.auditbeatAuditd !== null
? numeral(data.auditbeatAuditd).format('0,0')
: getEmptyTagValue(),
description: i18n.AUDITBEAT_AUDITD,
},
{
title:
has('auditbeatFIM', data) && data.auditbeatFIM !== null
? numeral(data.auditbeatFIM).format('0,0')
: getEmptyTagValue(),
description: i18n.AUDITBEAT_FIM,
},
{
title:
has('auditbeatLogin', data) && data.auditbeatLogin !== null
? numeral(data.auditbeatLogin).format('0,0')
: getEmptyTagValue(),
description: i18n.AUDITBEAT_LOGIN,
},
{
title:
has('auditbeatPackage', data) && data.auditbeatPackage !== null
? numeral(data.auditbeatPackage).format('0,0')
: getEmptyTagValue(),
description: i18n.AUDITBEAT_PACKAGE,
},
{
title:
has('auditbeatProcess', data) && data.auditbeatProcess !== null
? numeral(data.auditbeatProcess).format('0,0')
: getEmptyTagValue(),
description: i18n.AUDITBEAT_PROCESS,
},
{
title:
has('auditbeatUser', data) && data.auditbeatUser !== null
? numeral(data.auditbeatUser).format('0,0')
: getEmptyTagValue(),
description: i18n.AUDITBEAT_USER,
},
];
export const OverviewHostStats = pure<OverviewHostProps>(({ data }) => (
<>
{overviewHostStats(data).map(item => (
<EuiStat
key={item.description}
textAlign="center"
title={item.title}
description={item.description}
/>
))}
</>
));

View file

@ -0,0 +1,18 @@
/*
* 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 { OverviewHostData } from '../../../../graphql/types';
export const mockData: { OverviewHost: OverviewHostData } = {
OverviewHost: {
auditbeatAuditd: 73847,
auditbeatFIM: 107307,
auditbeatLogin: 60015,
auditbeatPackage: 2003,
auditbeatProcess: 1200,
auditbeatUser: 1979,
},
};

View file

@ -0,0 +1,33 @@
/*
* 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 { EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui';
import React from 'react';
import { pure } from 'recompose';
import { OverviewNetworkQuery } from '../../../../containers/overview/overview_network';
import { OverviewNetworkStats } from '../overview_network_stats';
import * as i18n from '../translations';
export interface OwnProps {
poll: number;
startDate: number;
endDate: number;
}
export const OverviewNetwork = pure<OwnProps>(({ endDate, poll, startDate }) => (
<EuiFlexItem>
<EuiPanel>
<EuiTitle>
<h2>{i18n.NETWORK_HEADING}</h2>
</EuiTitle>
<OverviewNetworkQuery endDate={endDate} poll={poll} sourceId="default" startDate={startDate}>
{({ overviewNetwork }) => <OverviewNetworkStats data={overviewNetwork} />}
</OverviewNetworkQuery>
</EuiPanel>
</EuiFlexItem>
));

View file

@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Overview Network Data rendering it renders the default OverviewNetworkStats 1`] = `
<Component
data={
Object {
"auditbeatSocket": 12,
"filebeatSuricata": 60015,
"filebeatZeek": 2003,
"packetbeatDNS": 10277307,
"packetbeatFlow": 16,
}
}
/>
`;

View file

@ -0,0 +1,21 @@
/*
* 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 { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import * as React from 'react';
import { OverviewNetworkStats } from '.';
import { mockData } from './mock';
describe('Overview Network Data', () => {
describe('rendering', () => {
test('it renders the default OverviewNetworkStats', () => {
const wrapper = shallow(<OverviewNetworkStats data={mockData.OverviewNetwork} />);
expect(toJson(wrapper)).toMatchSnapshot();
});
});
});

View file

@ -0,0 +1,73 @@
/*
* 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 {
// @ts-ignore
EuiStat,
} from '@elastic/eui';
import numeral from '@elastic/numeral';
import { has } from 'lodash/fp';
import React from 'react';
import { pure } from 'recompose';
import { OverviewNetworkData } from '../../../../graphql/types';
import { getEmptyTagValue } from '../../../empty_value';
import * as i18n from '../translations';
interface OverviewNetworkProps {
data: OverviewNetworkData;
}
const overviewNetworkStats = (data: OverviewNetworkData) => [
{
title:
has('packetbeatFlow', data) && data.packetbeatFlow !== null
? numeral(data.packetbeatFlow).format('0,0')
: getEmptyTagValue(),
description: i18n.PACKETBEAT_FLOW,
},
{
title:
has('packetbeatDNS', data) && data.packetbeatDNS !== null
? numeral(data.packetbeatDNS).format('0,0')
: getEmptyTagValue(),
description: i18n.PACKETBEAT_DNS,
},
{
title:
has('filebeatSuricata', data) && data.filebeatSuricata !== null
? numeral(data.filebeatSuricata).format('0,0')
: getEmptyTagValue(),
description: i18n.FILEBEAT_SURICATA,
},
{
title:
has('filebeatZeek', data) && data.filebeatZeek !== null
? numeral(data.filebeatZeek).format('0,0')
: getEmptyTagValue(),
description: i18n.FILEBEAT_ZEEK,
},
{
title:
has('auditbeatSocket', data) && data.auditbeatSocket !== null
? numeral(data.auditbeatSocket).format('0,0')
: getEmptyTagValue(),
description: i18n.AUDITBEAT_SOCKET,
},
];
export const OverviewNetworkStats = pure<OverviewNetworkProps>(({ data }) => (
<>
{overviewNetworkStats(data).map(item => (
<EuiStat
key={item.description}
textAlign="center"
title={item.title}
description={item.description}
/>
))}
</>
));

View file

@ -0,0 +1,17 @@
/*
* 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 { OverviewNetworkData } from '../../../../graphql/types';
export const mockData: { OverviewNetwork: OverviewNetworkData } = {
OverviewNetwork: {
packetbeatFlow: 16,
packetbeatDNS: 10277307,
filebeatSuricata: 60015,
filebeatZeek: 2003,
auditbeatSocket: 12,
},
};

View file

@ -0,0 +1,92 @@
/*
* 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 { i18n } from '@kbn/i18n';
export const PACKETBEAT_FLOW = i18n.translate(
'xpack.secops.overviewNetwork.source.packetbeatFlowTitle',
{
defaultMessage: 'Packetbeat Flow',
}
);
export const PACKETBEAT_DNS = i18n.translate(
'xpack.secops.overviewNetwork.source.packetbeatDNSTitle',
{
defaultMessage: 'Packetbeat DNS',
}
);
export const FILEBEAT_SURICATA = i18n.translate(
'xpack.secops.overviewNetwork.source.filebeatSuricataTitle',
{
defaultMessage: 'Filebeat Suricata',
}
);
export const FILEBEAT_ZEEK = i18n.translate(
'xpack.secops.overviewNetwork.source.filebeatZeekTitle',
{
defaultMessage: 'Filebeat Zeek',
}
);
export const AUDITBEAT_SOCKET = i18n.translate(
'xpack.secops.overviewNetwork.source.auditbeatSocketTitle',
{
defaultMessage: 'Auditbeat Socket',
}
);
export const HOSTS_HEADING = i18n.translate('xpack.secops.overview.hosts.headingTitle', {
defaultMessage: 'Hosts',
});
export const NETWORK_HEADING = i18n.translate('xpack.secops.overview.network.headingTitle', {
defaultMessage: 'Network',
});
export const AUDITBEAT_AUDITD = i18n.translate(
'xpack.secops.overviewNetwork.source.auditbeatAuditdTitle',
{
defaultMessage: 'Auditbeat Auditd',
}
);
export const AUDITBEAT_FIM = i18n.translate(
'xpack.secops.overviewNetwork.source.auditbeatFIMTitle',
{
defaultMessage: 'Auditbeat FIM',
}
);
export const AUDITBEAT_LOGIN = i18n.translate(
'xpack.secops.overviewNetwork.source.auditbeatLoginTitle',
{
defaultMessage: 'Auditbeat Login',
}
);
export const AUDITBEAT_PACKAGE = i18n.translate(
'xpack.secops.overviewNetwork.source.auditbeatPackageTitle',
{
defaultMessage: 'Auditbeat Package',
}
);
export const AUDITBEAT_PROCESS = i18n.translate(
'xpack.secops.overviewNetwork.source.auditbeatProcessTitle',
{
defaultMessage: 'Auditbeat Process',
}
);
export const AUDITBEAT_USER = i18n.translate(
'xpack.secops.overviewNetwork.source.auditbeatUserTitle',
{
defaultMessage: 'Auditbeat User',
}
);

View file

@ -0,0 +1,23 @@
/*
* 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 gql from 'graphql-tag';
export const overviewHostQuery = gql`
query GetOverviewHostQuery($sourceId: ID!, $timerange: TimerangeInput!, $filterQuery: String) {
source(id: $sourceId) {
id
OverviewHost(timerange: $timerange, filterQuery: $filterQuery) {
auditbeatAuditd
auditbeatFIM
auditbeatLogin
auditbeatPackage
auditbeatProcess
auditbeatUser
}
}
}
`;

View file

@ -0,0 +1,55 @@
/*
* 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 { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { pure } from 'recompose';
import { GetOverviewHostQuery, OverviewHostData } from '../../../graphql/types';
import { createFilter } from '../../helpers';
import { QueryTemplateProps } from '../../query_template';
import { overviewHostQuery } from './index.gql_query';
export interface OverviewHostArgs {
id: string;
overviewHost: OverviewHostData;
}
export interface OverviewHostProps extends QueryTemplateProps {
children: (args: OverviewHostArgs) => React.ReactNode;
sourceId: string;
endDate: number;
poll: number;
startDate: number;
}
export const OverviewHostQuery = pure<OverviewHostProps>(
({ id = 'overviewHostQuery', children, filterQuery, sourceId, startDate, endDate }) => (
<Query<GetOverviewHostQuery.Query, GetOverviewHostQuery.Variables>
query={overviewHostQuery}
fetchPolicy="cache-and-network"
variables={{
sourceId,
timerange: {
interval: '12h',
from: startDate,
to: endDate,
},
filterQuery: createFilter(filterQuery),
}}
>
{({ data }) => {
const overviewHost = getOr({}, `source.OverviewHost`, data);
return children({
id,
overviewHost,
});
}}
</Query>
)
);

View file

@ -0,0 +1,22 @@
/*
* 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 gql from 'graphql-tag';
export const overviewNetworkQuery = gql`
query GetOverviewNetworkQuery($sourceId: ID!, $timerange: TimerangeInput!, $filterQuery: String) {
source(id: $sourceId) {
id
OverviewNetwork(timerange: $timerange, filterQuery: $filterQuery) {
packetbeatFlow
packetbeatDNS
filebeatSuricata
filebeatZeek
auditbeatSocket
}
}
}
`;

View file

@ -0,0 +1,56 @@
/*
* 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 { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { pure } from 'recompose';
import { GetOverviewNetworkQuery, OverviewNetworkData } from '../../../graphql/types';
import { createFilter } from '../../helpers';
import { QueryTemplateProps } from '../../query_template';
import { overviewNetworkQuery } from './index.gql_query';
export interface OverviewNetworkArgs {
id: string;
overviewNetwork: OverviewNetworkData;
}
export interface OverviewNetworkProps extends QueryTemplateProps {
children: (args: OverviewNetworkArgs) => React.ReactNode;
sourceId: string;
endDate: number;
poll: number;
startDate: number;
}
export const OverviewNetworkQuery = pure<OverviewNetworkProps>(
({ id = 'overviewNetworkQuery', children, filterQuery, sourceId, startDate, endDate }) => (
<Query<GetOverviewNetworkQuery.Query, GetOverviewNetworkQuery.Variables>
query={overviewNetworkQuery}
fetchPolicy="cache-and-network"
notifyOnNetworkStatusChange
variables={{
sourceId,
timerange: {
interval: '12h',
from: startDate,
to: endDate,
},
filterQuery: createFilter(filterQuery),
}}
>
{({ data }) => {
const overviewNetwork = getOr({}, `source.OverviewNetwork`, data);
return children({
id,
overviewNetwork,
});
}}
</Query>
)
);

View file

@ -544,6 +544,68 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "OverviewNetwork",
"description": "",
"args": [
{
"name": "id",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"defaultValue": null
},
{
"name": "timerange",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null }
},
"defaultValue": null
},
{
"name": "filterQuery",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"defaultValue": null
}
],
"type": { "kind": "OBJECT", "name": "OverviewNetworkData", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "OverviewHost",
"description": "",
"args": [
{
"name": "id",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"defaultValue": null
},
{
"name": "timerange",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null }
},
"defaultValue": null
},
{
"name": "filterQuery",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"defaultValue": null
}
],
"type": { "kind": "OBJECT", "name": "OverviewHostData", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "UncommonProcesses",
"description": "Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified",
@ -4987,6 +5049,140 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "OverviewNetworkData",
"description": "",
"fields": [
{
"name": "packetbeatFlow",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "packetbeatDNS",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "filebeatSuricata",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "filebeatZeek",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "auditbeatSocket",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "OverviewHostData",
"description": "",
"fields": [
{
"name": "auditbeatAuditd",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "auditbeatFIM",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "auditbeatLogin",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "auditbeatPackage",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "auditbeatProcess",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "auditbeatUser",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "UncommonProcessesData",

View file

@ -55,6 +55,10 @@ export interface Source {
NetworkTopNFlow: NetworkTopNFlowData;
NetworkDns: NetworkDnsData;
OverviewNetwork?: OverviewNetworkData | null;
OverviewHost?: OverviewHostData | null;
/** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */
UncommonProcesses: UncommonProcessesData;
/** Just a simple example to get the app name */
@ -873,6 +877,32 @@ export interface NetworkDnsItem {
uniqueDomains?: number | null;
}
export interface OverviewNetworkData {
packetbeatFlow: number;
packetbeatDNS: number;
filebeatSuricata: number;
filebeatZeek?: number | null;
auditbeatSocket?: number | null;
}
export interface OverviewHostData {
auditbeatAuditd: number;
auditbeatFIM: number;
auditbeatLogin: number;
auditbeatPackage?: number | null;
auditbeatProcess?: number | null;
auditbeatUser?: number | null;
}
export interface UncommonProcessesData {
edges: UncommonProcessesEdges[];
@ -1035,6 +1065,20 @@ export interface NetworkDnsSourceArgs {
timerange: TimerangeInput;
}
export interface OverviewNetworkSourceArgs {
id?: string | null;
timerange: TimerangeInput;
filterQuery?: string | null;
}
export interface OverviewHostSourceArgs {
id?: string | null;
timerange: TimerangeInput;
filterQuery?: string | null;
}
export interface UncommonProcessesSourceArgs {
timerange: TimerangeInput;
@ -2070,6 +2114,80 @@ export namespace GetNetworkTopNFlowQuery {
};
}
export namespace GetOverviewHostQuery {
export type Variables = {
sourceId: string;
timerange: TimerangeInput;
filterQuery?: string | null;
};
export type Query = {
__typename?: 'Query';
source: Source;
};
export type Source = {
__typename?: 'Source';
id: string;
OverviewHost?: OverviewHost | null;
};
export type OverviewHost = {
__typename?: 'OverviewHostData';
auditbeatAuditd: number;
auditbeatFIM: number;
auditbeatLogin: number;
auditbeatPackage?: number | null;
auditbeatProcess?: number | null;
auditbeatUser?: number | null;
};
}
export namespace GetOverviewNetworkQuery {
export type Variables = {
sourceId: string;
timerange: TimerangeInput;
filterQuery?: string | null;
};
export type Query = {
__typename?: 'Query';
source: Source;
};
export type Source = {
__typename?: 'Source';
id: string;
OverviewNetwork?: OverviewNetwork | null;
};
export type OverviewNetwork = {
__typename?: 'OverviewNetworkData';
packetbeatFlow: number;
packetbeatDNS: number;
filebeatSuricata: number;
filebeatZeek?: number | null;
auditbeatSocket?: number | null;
};
}
export namespace SourceQuery {
export type Variables = {
sourceId?: string | null;

View file

@ -7,15 +7,6 @@
import React from 'react';
import { pure } from 'recompose';
import { Pane, Pane1FlexContent, PaneScrollContainer } from '../../components/page';
import { Placeholders } from '../../components/visualization_placeholder';
import { OverviewComponent } from './overview';
export const Overview = pure(() => (
<Pane data-test-subj="pane">
<PaneScrollContainer data-test-subj="pane1ScrollContainer">
<Pane1FlexContent>
<Placeholders count={10} myRoute="Overview" />
</Pane1FlexContent>
</PaneScrollContainer>
</Pane>
));
export const Overview = pure(() => <OverviewComponent />);

View file

@ -0,0 +1,34 @@
/*
* 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 { EuiFlexGroup } from '@elastic/eui';
import React from 'react';
import { pure } from 'recompose';
import { OverviewHost } from '../../components/page/overview/overview_host';
import { OverviewNetwork } from '../../components/page/overview/overview_network';
import { GlobalTime } from '../../containers/global_time';
import { PageContent, PageContentBody } from '../styles';
import { Summary } from './summary';
import { Welcome } from './welcome';
export const OverviewComponent = pure(() => (
<PageContent>
<Welcome />
<PageContentBody>
<Summary />
<GlobalTime>
{({ poll, to, from }) => (
<EuiFlexGroup>
<OverviewHost poll={poll} endDate={to} startDate={from} />
<OverviewNetwork poll={poll} endDate={to} startDate={from} />
</EuiFlexGroup>
)}
</GlobalTime>
</PageContentBody>
</PageContent>
));

View file

@ -0,0 +1,103 @@
/*
* 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 { EuiFlexGroup, EuiFlexItem, EuiLink, EuiText, EuiTitle } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { pure } from 'recompose';
import styled from 'styled-components';
import * as i18n from './translations';
interface ListItemType {
label: JSX.Element;
}
const listContent: ListItemType[] = [
{
label: (
<FormattedMessage
id="xpack.secops.overview.feature.documentation"
defaultMessage="Check out the {link}"
values={{
link: (
<EuiLink href="#">
<FormattedMessage
id="xpack.secops.overview.feature.documentation.link"
defaultMessage="Documentation"
/>
</EuiLink>
),
}}
/>
),
},
{
label: (
<FormattedMessage
id="xpack.secops.overview.feature.dataIngestion"
defaultMessage="Learn about {link}"
values={{
link: (
<EuiLink href="#">
<FormattedMessage
id="xpack.secops.overview.feature.dataIngestion.link"
defaultMessage="Data Ingestion"
/>
</EuiLink>
),
}}
/>
),
},
{
label: (
<FormattedMessage
id="xpack.secops.overview.feature.blog"
defaultMessage="Go to {blog} and {video}"
values={{
blog: (
<EuiLink href="#">
<FormattedMessage
id="xpack.secops.overview.feature.blog.blog"
defaultMessage="Blog Posts"
/>
</EuiLink>
),
video: (
<EuiLink href="#">
<FormattedMessage
id="xpack.secops.overview.feature.blog.video"
defaultMessage="Videos"
/>
</EuiLink>
),
}}
/>
),
},
];
export const Summary = pure(() => (
<EuiFlexGroup justifyContent="spaceAround">
<StyledEuiFlexItem grow={false}>
<EuiTitle size="s">
<h3>{i18n.FEATURE_OVERVIEW_HEADING}</h3>
</EuiTitle>
<EuiText>
<ol>
{listContent.map(({ label }, i) => (
<li key={`${i}-${label}`}>{label}</li>
))}
</ol>
</EuiText>
</StyledEuiFlexItem>
</EuiFlexGroup>
));
const StyledEuiFlexItem = styled(EuiFlexItem)`
min-width: 350px;
`;

View file

@ -0,0 +1,19 @@
/*
* 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 { i18n } from '@kbn/i18n';
export const OVERVIEW_TITLE = i18n.translate('xpack.secops.overview.sectionTitle', {
defaultMessage: 'Welcome to the SIEM App!',
});
export const OVERVIEW_SUBTITLE = i18n.translate('xpack.secops.overview.subTitle', {
defaultMessage: 'Security Information and Event Management with the Elastic Stack',
});
export const FEATURE_OVERVIEW_HEADING = i18n.translate('xpack.secops.overview.featureTitle', {
defaultMessage: 'What you can do here:',
});

View file

@ -0,0 +1,26 @@
/*
* 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 { EuiFlexGroup, EuiFlexItem, EuiText, EuiTextAlign, EuiTitle } from '@elastic/eui';
import React from 'react';
import { pure } from 'recompose';
import * as i18n from './translations';
export const Welcome = pure(() => (
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<EuiTextAlign textAlign="center">
<EuiTitle size="l">
<h1>{i18n.OVERVIEW_TITLE}</h1>
</EuiTitle>
<EuiText>
<p>{i18n.OVERVIEW_SUBTITLE}</p>
</EuiText>
</EuiTextAlign>
</EuiFlexItem>
</EuiFlexGroup>
));

View file

@ -17,6 +17,7 @@ import { hostsSchema } from './hosts';
import { ipOverviewSchema } from './ip_overview';
import { kpiNetworkSchema } from './kpi_network';
import { networkSchema } from './network';
import { overviewSchema } from './overview';
import { dateSchema } from './scalar_date';
import { sourceStatusSchema } from './source_status';
import { sourcesSchema } from './sources';
@ -32,6 +33,7 @@ export const schemas = [
ipOverviewSchema,
kpiNetworkSchema,
networkSchema,
overviewSchema,
rootSchema,
sourcesSchema,
sourceStatusSchema,

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export { createOverviewResolvers } from './resolvers';
export { overviewSchema } from './schema.gql';

View file

@ -0,0 +1,62 @@
/*
* 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 { Logger } from '../../utils/logger';
import { SecOpsContext } from '../index';
import { OverviewHostData, OverviewNetworkData } from '../types';
export const mockOverviewNetworkData: { OverviewNetwork: OverviewNetworkData } = {
OverviewNetwork: {
packetbeatFlow: 0,
packetbeatDNS: 0,
filebeatSuricata: 0,
filebeatZeek: 0,
auditbeatSocket: 0,
},
};
export const getOverviewNetworkQueryMock = (logger: Logger) => ({
source: (root: unknown, args: unknown, context: SecOpsContext) => {
logger.info('Mock source');
const operationName = context.req.payload.operationName.toLowerCase();
switch (operationName) {
case 'test': {
logger.info(`Using mock for test ${mockOverviewNetworkData}`);
return mockOverviewNetworkData;
}
default: {
return {};
}
}
},
});
export const mockOverviewHostData: { OverviewHost: OverviewHostData } = {
OverviewHost: {
auditbeatAuditd: 0,
auditbeatFIM: 0,
auditbeatLogin: 0,
auditbeatPackage: 0,
auditbeatProcess: 0,
auditbeatUser: 0,
},
};
export const getOverviewHostQueryMock = (logger: Logger) => ({
source: (root: unknown, args: unknown, context: SecOpsContext) => {
logger.info('Mock source');
const operationName = context.req.payload.operationName.toLowerCase();
switch (operationName) {
case 'test': {
logger.info(`Using mock for test ${mockOverviewHostData}`);
return mockOverviewHostData;
}
default: {
return {};
}
}
},
});

View file

@ -0,0 +1,111 @@
/*
* 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 { GraphQLResolveInfo } from 'graphql';
import { Source } from '../../graphql/types';
import { FrameworkRequest, internalFrameworkRequest } from '../../lib/framework';
import { Overview } from '../../lib/overview';
import { OverviewAdapter } from '../../lib/overview/types';
import { SourceStatus } from '../../lib/source_status';
import { Sources } from '../../lib/sources';
import { createSourcesResolvers } from '../sources';
import { SourcesResolversDeps } from '../sources/resolvers';
import { mockSourcesAdapter, mockSourceStatusAdapter } from '../sources/resolvers.test';
import { mockOverviewHostData, mockOverviewNetworkData } from './overview.mock';
import { createOverviewResolvers, OverviewResolversDeps } from './resolvers';
const mockGetOverviewNetwork = jest.fn();
mockGetOverviewNetwork.mockResolvedValue({
OverviewNetwork: {
...mockOverviewNetworkData.OverviewNetwork,
},
});
const mockGetOverviewHost = jest.fn();
mockGetOverviewHost.mockResolvedValue({
OverviewHost: {
...mockOverviewHostData.OverviewHost,
},
});
const mockOverviewAdapter: OverviewAdapter = {
getOverviewHost: mockGetOverviewHost,
getOverviewNetwork: mockGetOverviewNetwork,
};
const mockOverviewLibs: OverviewResolversDeps = {
overview: new Overview(mockOverviewAdapter),
};
const mockSrcLibs: SourcesResolversDeps = {
sources: new Sources(mockSourcesAdapter),
sourceStatus: new SourceStatus(mockSourceStatusAdapter, new Sources(mockSourcesAdapter)),
};
const req: FrameworkRequest = {
[internalFrameworkRequest]: {
params: {},
query: {},
payload: {
operationName: 'test',
},
},
params: {},
query: {},
payload: {
operationName: 'test',
},
};
const context = { req };
describe('Test Overview SIEM Resolvers', () => {
test('Make sure that getOverviewNetwork have been called', async () => {
const source = await createSourcesResolvers(mockSrcLibs).Query.source(
{},
{ id: 'default' },
context,
{} as GraphQLResolveInfo
);
const data = await createOverviewResolvers(mockOverviewLibs).Source.OverviewNetwork(
source as Source,
{
timerange: {
interval: '12h',
to: 1514782800000,
from: 1546318799999,
},
},
context,
{} as GraphQLResolveInfo
);
expect(mockOverviewAdapter.getOverviewNetwork).toHaveBeenCalled();
expect(data).toEqual(mockOverviewNetworkData);
});
test('Make sure that getOverviewHost have been called', async () => {
const source = await createSourcesResolvers(mockSrcLibs).Query.source(
{},
{ id: 'default' },
context,
{} as GraphQLResolveInfo
);
const data = await createOverviewResolvers(mockOverviewLibs).Source.OverviewHost(
source as Source,
{
timerange: {
interval: '12h',
to: 1514782800000,
from: 1546318799999,
},
},
context,
{} as GraphQLResolveInfo
);
expect(mockOverviewAdapter.getOverviewHost).toHaveBeenCalled();
expect(data).toEqual(mockOverviewHostData);
});
});

View file

@ -0,0 +1,45 @@
/*
* 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 { SourceResolvers } from '../../graphql/types';
import { AppResolverOf, ChildResolverOf } from '../../lib/framework';
import { Overview } from '../../lib/overview';
import { createOptions } from '../../utils/build_query/create_options';
import { QuerySourceResolver } from '../sources/resolvers';
export type QueryOverviewNetworkResolver = ChildResolverOf<
AppResolverOf<SourceResolvers.OverviewNetworkResolver>,
QuerySourceResolver
>;
export type QueryOverviewHostResolver = ChildResolverOf<
AppResolverOf<SourceResolvers.OverviewHostResolver>,
QuerySourceResolver
>;
export interface OverviewResolversDeps {
overview: Overview;
}
export const createOverviewResolvers = (
libs: OverviewResolversDeps
): {
Source: {
OverviewHost: QueryOverviewHostResolver;
OverviewNetwork: QueryOverviewNetworkResolver;
};
} => ({
Source: {
async OverviewNetwork(source, args, { req }, info) {
const options = { ...createOptions(source, args, info) };
return libs.overview.getOverviewNetwork(req, options);
},
async OverviewHost(source, args, { req }, info) {
const options = { ...createOptions(source, args, info) };
return libs.overview.getOverviewHost(req, options);
},
},
});

View file

@ -0,0 +1,35 @@
/*
* 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 gql from 'graphql-tag';
export const overviewSchema = gql`
type OverviewNetworkData {
packetbeatFlow: Float!
packetbeatDNS: Float!
filebeatSuricata: Float!
filebeatZeek: Float
auditbeatSocket: Float
}
type OverviewHostData {
auditbeatAuditd: Float!
auditbeatFIM: Float!
auditbeatLogin: Float!
auditbeatPackage: Float
auditbeatProcess: Float
auditbeatUser: Float
}
extend type Source {
OverviewNetwork(
id: String
timerange: TimerangeInput!
filterQuery: String
): OverviewNetworkData
OverviewHost(id: String, timerange: TimerangeInput!, filterQuery: String): OverviewHostData
}
`;

View file

@ -0,0 +1,191 @@
/*
* 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 { graphql } from 'graphql';
import { addMockFunctionsToSchema, makeExecutableSchema } from 'graphql-tools';
import { rootSchema } from '../../../common/graphql/root/schema.gql';
import { sharedSchema } from '../../../common/graphql/shared';
import { Logger } from '../../utils/logger';
import { ecsSchema } from '../ecs';
import { dateSchema } from '../scalar_date';
import { sourceStatusSchema } from '../source_status/schema.gql';
import { sourcesSchema } from '../sources/schema.gql';
import {
getOverviewHostQueryMock,
getOverviewNetworkQueryMock,
mockOverviewHostData,
mockOverviewNetworkData,
} from './overview.mock';
import { overviewSchema } from './schema.gql';
const testOverviewNetworkSource = {
id: 'Test case to query Siem Overview Network data',
query: `
query GetOverviewNetworkQuery(
$timerange: TimerangeInput!
$filterQuery: String
) {
source(id: "default") {
OverviewNetwork(timerange: $timerange, filterQuery: $filterQuery) {
packetbeatFlow
packetbeatDNS
filebeatSuricata
filebeatZeek
auditbeatSocket
}
}
}
`,
variables: {
timerange: {
interval: '12h',
to: 1514782800000,
from: 1546318799999,
},
},
context: {
req: {
payload: {
operationName: 'test',
},
},
},
expected: {
data: {
source: {
...mockOverviewNetworkData,
},
},
},
};
const testOverviewHostSource = {
id: 'Test case to query Siem Overview Host data',
query: `
query GetOverviewHostQuery(
$timerange: TimerangeInput!
$filterQuery: String
) {
source(id: "default") {
OverviewHost(timerange: $timerange, filterQuery: $filterQuery) {
auditbeatAuditd
auditbeatFIM
auditbeatLogin
auditbeatPackage
auditbeatProcess
auditbeatUser
}
}
}
`,
variables: {
timerange: {
interval: '12h',
to: 1514782800000,
from: 1546318799999,
},
},
context: {
req: {
payload: {
operationName: 'test',
},
},
},
expected: {
data: {
source: {
...mockOverviewHostData,
},
},
},
};
describe('SIEM Overview GQL Schema', () => {
describe('Test Host Schema', () => {
// Array of case types
const cases = [testOverviewHostSource];
const typeDefs = [
rootSchema,
sharedSchema,
sourcesSchema,
sourceStatusSchema,
ecsSchema,
overviewSchema,
dateSchema,
];
const mockSchema = makeExecutableSchema({ typeDefs });
// Here we specify the return payloads of mocked types
const logger: Logger = {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
};
const mocks = {
Query: () => ({
...getOverviewHostQueryMock(logger),
}),
};
addMockFunctionsToSchema({
schema: mockSchema,
mocks,
});
cases.forEach(obj => {
const { id, query, variables, context, expected } = obj;
test(`${id}`, async () => {
const result = await graphql(mockSchema, query, null, context, variables);
return await expect(result).toEqual(expected);
});
});
});
describe('Test Network Schema', () => {
// Array of case types
const cases = [testOverviewNetworkSource];
const typeDefs = [
rootSchema,
sharedSchema,
sourcesSchema,
sourceStatusSchema,
ecsSchema,
overviewSchema,
dateSchema,
];
const mockSchema = makeExecutableSchema({ typeDefs });
// Here we specify the return payloads of mocked types
const logger: Logger = {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
};
const mocks = {
Query: () => ({
...getOverviewNetworkQueryMock(logger),
}),
};
addMockFunctionsToSchema({
schema: mockSchema,
mocks,
});
cases.forEach(obj => {
const { id, query, variables, context, expected } = obj;
test(`${id}`, async () => {
const result = await graphql(mockSchema, query, null, context, variables);
return await expect(result).toEqual(expected);
});
});
});
});

View file

@ -84,6 +84,10 @@ export interface Source {
NetworkTopNFlow: NetworkTopNFlowData;
NetworkDns: NetworkDnsData;
OverviewNetwork?: OverviewNetworkData | null;
OverviewHost?: OverviewHostData | null;
/** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */
UncommonProcesses: UncommonProcessesData;
/** Just a simple example to get the app name */
@ -902,6 +906,32 @@ export interface NetworkDnsItem {
uniqueDomains?: number | null;
}
export interface OverviewNetworkData {
packetbeatFlow: number;
packetbeatDNS: number;
filebeatSuricata: number;
filebeatZeek?: number | null;
auditbeatSocket?: number | null;
}
export interface OverviewHostData {
auditbeatAuditd: number;
auditbeatFIM: number;
auditbeatLogin: number;
auditbeatPackage?: number | null;
auditbeatProcess?: number | null;
auditbeatUser?: number | null;
}
export interface UncommonProcessesData {
edges: UncommonProcessesEdges[];
@ -1064,6 +1094,20 @@ export interface NetworkDnsSourceArgs {
timerange: TimerangeInput;
}
export interface OverviewNetworkSourceArgs {
id?: string | null;
timerange: TimerangeInput;
filterQuery?: string | null;
}
export interface OverviewHostSourceArgs {
id?: string | null;
timerange: TimerangeInput;
filterQuery?: string | null;
}
export interface UncommonProcessesSourceArgs {
timerange: TimerangeInput;
@ -1193,6 +1237,10 @@ export namespace SourceResolvers {
NetworkTopNFlow?: NetworkTopNFlowResolver<NetworkTopNFlowData, TypeParent, Context>;
NetworkDns?: NetworkDnsResolver<NetworkDnsData, TypeParent, Context>;
OverviewNetwork?: OverviewNetworkResolver<OverviewNetworkData | null, TypeParent, Context>;
OverviewHost?: OverviewHostResolver<OverviewHostData | null, TypeParent, Context>;
/** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */
UncommonProcesses?: UncommonProcessesResolver<UncommonProcessesData, TypeParent, Context>;
/** Just a simple example to get the app name */
@ -1353,6 +1401,32 @@ export namespace SourceResolvers {
timerange: TimerangeInput;
}
export type OverviewNetworkResolver<
R = OverviewNetworkData | null,
Parent = Source,
Context = SecOpsContext
> = Resolver<R, Parent, Context, OverviewNetworkArgs>;
export interface OverviewNetworkArgs {
id?: string | null;
timerange: TimerangeInput;
filterQuery?: string | null;
}
export type OverviewHostResolver<
R = OverviewHostData | null,
Parent = Source,
Context = SecOpsContext
> = Resolver<R, Parent, Context, OverviewHostArgs>;
export interface OverviewHostArgs {
id?: string | null;
timerange: TimerangeInput;
filterQuery?: string | null;
}
export type UncommonProcessesResolver<
R = UncommonProcessesData,
Parent = Source,
@ -4076,6 +4150,93 @@ export namespace NetworkDnsItemResolvers {
> = Resolver<R, Parent, Context>;
}
export namespace OverviewNetworkDataResolvers {
export interface Resolvers<Context = SecOpsContext, TypeParent = OverviewNetworkData> {
packetbeatFlow?: PacketbeatFlowResolver<number, TypeParent, Context>;
packetbeatDNS?: PacketbeatDnsResolver<number, TypeParent, Context>;
filebeatSuricata?: FilebeatSuricataResolver<number, TypeParent, Context>;
filebeatZeek?: FilebeatZeekResolver<number | null, TypeParent, Context>;
auditbeatSocket?: AuditbeatSocketResolver<number | null, TypeParent, Context>;
}
export type PacketbeatFlowResolver<
R = number,
Parent = OverviewNetworkData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type PacketbeatDnsResolver<
R = number,
Parent = OverviewNetworkData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type FilebeatSuricataResolver<
R = number,
Parent = OverviewNetworkData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type FilebeatZeekResolver<
R = number | null,
Parent = OverviewNetworkData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type AuditbeatSocketResolver<
R = number | null,
Parent = OverviewNetworkData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
}
export namespace OverviewHostDataResolvers {
export interface Resolvers<Context = SecOpsContext, TypeParent = OverviewHostData> {
auditbeatAuditd?: AuditbeatAuditdResolver<number, TypeParent, Context>;
auditbeatFIM?: AuditbeatFimResolver<number, TypeParent, Context>;
auditbeatLogin?: AuditbeatLoginResolver<number, TypeParent, Context>;
auditbeatPackage?: AuditbeatPackageResolver<number | null, TypeParent, Context>;
auditbeatProcess?: AuditbeatProcessResolver<number | null, TypeParent, Context>;
auditbeatUser?: AuditbeatUserResolver<number | null, TypeParent, Context>;
}
export type AuditbeatAuditdResolver<
R = number,
Parent = OverviewHostData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type AuditbeatFimResolver<
R = number,
Parent = OverviewHostData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type AuditbeatLoginResolver<
R = number,
Parent = OverviewHostData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type AuditbeatPackageResolver<
R = number | null,
Parent = OverviewHostData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type AuditbeatProcessResolver<
R = number | null,
Parent = OverviewHostData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
export type AuditbeatUserResolver<
R = number | null,
Parent = OverviewHostData,
Context = SecOpsContext
> = Resolver<R, Parent, Context>;
}
export namespace UncommonProcessesDataResolvers {
export interface Resolvers<Context = SecOpsContext, TypeParent = UncommonProcessesData> {
edges?: EdgesResolver<UncommonProcessesEdges[], TypeParent, Context>;

View file

@ -13,6 +13,7 @@ import { createHostsResolvers } from './graphql/hosts';
import { createIpOverviewResolvers } from './graphql/ip_overview';
import { createKpiNetworkResolvers } from './graphql/kpi_network';
import { createNetworkResolvers } from './graphql/network';
import { createOverviewResolvers } from './graphql/overview';
import { createScalarDateResolvers } from './graphql/scalar_date';
import { createSourceStatusResolvers } from './graphql/source_status';
import { createSourcesResolvers } from './graphql/sources';
@ -37,6 +38,7 @@ export const initServer = (libs: AppBackendLibs, config: Config) => {
createIpOverviewResolvers(libs) as IResolvers,
createSourcesResolvers(libs) as IResolvers,
createScalarToStringArrayValueResolvers() as IResolvers,
createOverviewResolvers(libs) as IResolvers,
createNetworkResolvers(libs) as IResolvers,
createScalarDateResolvers() as IResolvers,
createSourcesResolvers(libs) as IResolvers,

View file

@ -17,6 +17,8 @@ import { ElasticsearchIpOverviewAdapter, IpOverview } from '../ip_overview';
import { KpiNetwork } from '../kpi_network';
import { ElasticsearchKpiNetworkAdapter } from '../kpi_network/elasticsearch_adapter';
import { ElasticsearchNetworkAdapter, Network } from '../network';
import { Overview } from '../overview';
import { ElasticsearchOverviewAdapter } from '../overview/elasticsearch_adapter';
import { ElasticsearchSourceStatusAdapter, SourceStatus } from '../source_status';
import { ConfigurationSourcesAdapter, Sources } from '../sources';
import { AppBackendLibs, AppDomainLibs, Configuration } from '../types';
@ -36,6 +38,7 @@ export function compose(server: Server): AppBackendLibs {
ipOverview: new IpOverview(new ElasticsearchIpOverviewAdapter(framework)),
kpiNetwork: new KpiNetwork(new ElasticsearchKpiNetworkAdapter(framework)),
network: new Network(new ElasticsearchNetworkAdapter(framework)),
overview: new Overview(new ElasticsearchOverviewAdapter(framework)),
uncommonProcesses: new UncommonProcesses(new ElasticsearchUncommonProcessesAdapter(framework)),
};

View file

@ -0,0 +1,149 @@
/*
* 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 { cloneDeep } from 'lodash/fp';
import { OverviewHostData, OverviewNetworkData } from '../../graphql/types';
import { FrameworkAdapter, FrameworkRequest } from '../framework';
import { ElasticsearchOverviewAdapter } from './elasticsearch_adapter';
import {
mockOptionsHost,
mockOptionsNetwork,
mockRequestHost,
mockRequestNetwork,
mockResponseHost,
mockResponseNetwork,
mockResultHost,
mockResultNetwork,
} from './mock';
describe('Siem Overview elasticsearch_adapter', () => {
describe('Network Stats', () => {
describe('Happy Path - get Data', () => {
const mockCallWithRequest = jest.fn();
mockCallWithRequest.mockResolvedValue(mockResponseNetwork);
const mockFramework: FrameworkAdapter = {
version: 'mock',
callWithRequest: mockCallWithRequest,
exposeStaticDir: jest.fn(),
registerGraphQLEndpoint: jest.fn(),
getIndexPatternsService: jest.fn(),
};
jest.mock('../framework', () => ({
callWithRequest: mockCallWithRequest,
}));
test('getOverviewNetwork', async () => {
const EsOverviewNetwork = new ElasticsearchOverviewAdapter(mockFramework);
const data: OverviewNetworkData = await EsOverviewNetwork.getOverviewNetwork(
mockRequestNetwork as FrameworkRequest,
mockOptionsNetwork
);
expect(data).toEqual(mockResultNetwork);
});
});
describe('Unhappy Path - No data', () => {
const mockNoDataResponse = cloneDeep(mockResponseNetwork);
mockNoDataResponse.aggregations.unique_flow_count.doc_count = 0;
mockNoDataResponse.aggregations.unique_dns_count.doc_count = 0;
mockNoDataResponse.aggregations.unique_suricata_count.doc_count = 0;
mockNoDataResponse.aggregations.unique_zeek_count.doc_count = 0;
mockNoDataResponse.aggregations.unique_socket_count.doc_count = 0;
const mockCallWithRequest = jest.fn();
mockCallWithRequest.mockResolvedValue(mockNoDataResponse);
const mockFramework: FrameworkAdapter = {
version: 'mock',
callWithRequest: mockCallWithRequest,
exposeStaticDir: jest.fn(),
registerGraphQLEndpoint: jest.fn(),
getIndexPatternsService: jest.fn(),
};
jest.mock('../framework', () => ({
callWithRequest: mockCallWithRequest,
}));
test('getOverviewNetwork', async () => {
const EsOverviewNetwork = new ElasticsearchOverviewAdapter(mockFramework);
const data: OverviewNetworkData = await EsOverviewNetwork.getOverviewNetwork(
mockRequestNetwork as FrameworkRequest,
mockOptionsNetwork
);
expect(data).toEqual({
packetbeatFlow: 0,
packetbeatDNS: 0,
filebeatSuricata: 0,
filebeatZeek: 0,
auditbeatSocket: 0,
});
});
});
});
describe('Host Stats', () => {
describe('Happy Path - get Data', () => {
const mockCallWithRequest = jest.fn();
mockCallWithRequest.mockResolvedValue(mockResponseHost);
const mockFramework: FrameworkAdapter = {
version: 'mock',
callWithRequest: mockCallWithRequest,
exposeStaticDir: jest.fn(),
registerGraphQLEndpoint: jest.fn(),
getIndexPatternsService: jest.fn(),
};
jest.mock('../framework', () => ({
callWithRequest: mockCallWithRequest,
}));
test('getOverviewHost', async () => {
const EsOverviewHost = new ElasticsearchOverviewAdapter(mockFramework);
const data: OverviewHostData = await EsOverviewHost.getOverviewHost(
mockRequestHost as FrameworkRequest,
mockOptionsHost
);
expect(data).toEqual(mockResultHost);
});
});
describe('Unhappy Path - No data', () => {
const mockNoDataResponse = cloneDeep(mockResponseHost);
mockNoDataResponse.aggregations.auditd_count.doc_count = 0;
mockNoDataResponse.aggregations.fim_count.doc_count = 0;
mockNoDataResponse.aggregations.system_module.login_count.doc_count = 0;
mockNoDataResponse.aggregations.system_module.package_count.doc_count = 0;
mockNoDataResponse.aggregations.system_module.process_count.doc_count = 0;
mockNoDataResponse.aggregations.system_module.user_count.doc_count = 0;
const mockCallWithRequest = jest.fn();
mockCallWithRequest.mockResolvedValue(mockNoDataResponse);
const mockFramework: FrameworkAdapter = {
version: 'mock',
callWithRequest: mockCallWithRequest,
exposeStaticDir: jest.fn(),
registerGraphQLEndpoint: jest.fn(),
getIndexPatternsService: jest.fn(),
};
jest.mock('../framework', () => ({
callWithRequest: mockCallWithRequest,
}));
test('getOverviewHost', async () => {
const EsOverviewHost = new ElasticsearchOverviewAdapter(mockFramework);
const data: OverviewHostData = await EsOverviewHost.getOverviewHost(
mockRequestHost as FrameworkRequest,
mockOptionsHost
);
expect(data).toEqual({
auditbeatAuditd: 0,
auditbeatFIM: 0,
auditbeatLogin: 0,
auditbeatPackage: 0,
auditbeatProcess: 0,
auditbeatUser: 0,
});
});
});
});
});

View file

@ -0,0 +1,57 @@
/*
* 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 { getOr } from 'lodash/fp';
import { OverviewHostData, OverviewNetworkData } from '../../graphql/types';
import { FrameworkAdapter, FrameworkRequest, RequestBasicOptions } from '../framework';
import { TermAggregation } from '../types';
import { buildOverviewHostQuery, buildOverviewNetworkQuery } from './query.dsl';
import { OverviewAdapter, OverviewHostHit, OverviewNetworkHit } from './types';
export class ElasticsearchOverviewAdapter implements OverviewAdapter {
constructor(private readonly framework: FrameworkAdapter) {}
public async getOverviewNetwork(
request: FrameworkRequest,
options: RequestBasicOptions
): Promise<OverviewNetworkData> {
const response = await this.framework.callWithRequest<OverviewNetworkHit, TermAggregation>(
request,
'search',
buildOverviewNetworkQuery(options)
);
return {
packetbeatFlow: getOr(null, 'aggregations.unique_flow_count.doc_count', response),
packetbeatDNS: getOr(null, 'aggregations.unique_dns_count.doc_count', response),
filebeatSuricata: getOr(null, 'aggregations.unique_suricata_count.doc_count', response),
filebeatZeek: getOr(null, 'aggregations.unique_zeek_count.doc_count', response),
auditbeatSocket: getOr(null, 'aggregations.unique_socket_count.doc_count', response),
};
}
public async getOverviewHost(
request: FrameworkRequest,
options: RequestBasicOptions
): Promise<OverviewHostData> {
const response = await this.framework.callWithRequest<OverviewHostHit, TermAggregation>(
request,
'search',
buildOverviewHostQuery(options)
);
return {
auditbeatAuditd: getOr(null, 'aggregations.auditd_count.doc_count', response),
auditbeatFIM: getOr(null, 'aggregations.fim_count.doc_count', response),
auditbeatLogin: getOr(null, 'aggregations.system_module.login_count.doc_count', response),
auditbeatPackage: getOr(null, 'aggregations.system_module.package_count.doc_count', response),
auditbeatProcess: getOr(null, 'aggregations.system_module.process_count.doc_count', response),
auditbeatUser: getOr(null, 'aggregations.system_module.user_count.doc_count', response),
};
}
}

View file

@ -0,0 +1,28 @@
/*
* 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 { OverviewHostData, OverviewNetworkData } from '../../graphql/types';
import { FrameworkRequest, RequestBasicOptions } from '../framework';
import { OverviewAdapter } from './types';
export class Overview {
constructor(private readonly adapter: OverviewAdapter) {}
public async getOverviewNetwork(
req: FrameworkRequest,
options: RequestBasicOptions
): Promise<OverviewNetworkData> {
return await this.adapter.getOverviewNetwork(req, options);
}
public async getOverviewHost(
req: FrameworkRequest,
options: RequestBasicOptions
): Promise<OverviewHostData> {
return await this.adapter.getOverviewHost(req, options);
}
}

View file

@ -0,0 +1,122 @@
/*
* 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 { RequestBasicOptions } from '../framework/types';
export const mockOptionsNetwork: RequestBasicOptions = {
sourceConfiguration: {
logAlias: 'filebeat-*',
auditbeatAlias: 'auditbeat-*',
packetbeatAlias: 'packetbeat-*',
fields: {
container: 'docker.container.name',
host: 'beat.hostname',
message: ['message', '@message'],
pod: 'kubernetes.pod.name',
tiebreaker: '_doc',
timestamp: '@timestamp',
},
},
timerange: { interval: '12h', to: 1549852006071, from: 1549765606071 },
filterQuery: {},
};
export const mockRequestNetwork = {
params: {},
payload: {
operationName: 'GetOverviewNetworkQuery',
variables: {
sourceId: 'default',
timerange: { interval: '12h', from: 1549765830772, to: 1549852230772 },
filterQuery: '',
},
query:
'query GetOverviewNetworkQuery(\n $sourceId: ID!\n $timerange: TimerangeInput!\n $filterQuery: String\n ) {\n source(id: $sourceId) {\n id\n OverviewNetwork(timerange: $timerange, filterQuery: $filterQuery) {\n packetbeatFlow\n packetbeatDNS\n filebeatSuricata\n filebeatZeek\n auditbeatSocket\n }\n }\n }',
},
query: {},
};
export const mockResponseNetwork = {
took: 89,
timed_out: false,
_shards: { total: 18, successful: 18, skipped: 0, failed: 0 },
hits: { total: { value: 950867, relation: 'eq' }, max_score: null, hits: [] },
aggregations: {
unique_flow_count: { doc_count: 50243 },
unique_dns_count: { doc_count: 15000 },
unique_suricata_count: { doc_count: 2375 },
unique_zeek_count: { doc_count: 456 },
unique_socket_count: { doc_count: 13 },
},
};
export const mockResultNetwork = {
packetbeatFlow: 50243,
packetbeatDNS: 15000,
filebeatSuricata: 2375,
filebeatZeek: 456,
auditbeatSocket: 13,
};
export const mockOptionsHost: RequestBasicOptions = {
sourceConfiguration: {
logAlias: 'filebeat-*',
auditbeatAlias: 'auditbeat-*',
packetbeatAlias: 'packetbeat-*',
fields: {
container: 'docker.container.name',
host: 'beat.hostname',
message: ['message', '@message'],
pod: 'kubernetes.pod.name',
tiebreaker: '_doc',
timestamp: '@timestamp',
},
},
timerange: { interval: '12h', to: 1549852006071, from: 1549765606071 },
filterQuery: {},
};
export const mockRequestHost = {
params: {},
payload: {
operationName: 'GetOverviewHostQuery',
variables: {
sourceId: 'default',
timerange: { interval: '12h', from: 1549765830772, to: 1549852230772 },
filterQuery: '',
},
query:
'query GetOverviewHostQuery(\n $sourceId: ID!\n $timerange: TimerangeInput!\n $filterQuery: String\n ) {\n source(id: $sourceId) {\n id\n OverviewHost(timerange: $timerange, filterQuery: $filterQuery) {\n auditbeatAuditd\n auditbeatFIM\n auditbeatLogin\n auditbeatPackage\n auditbeatProcess\n auditbeatUser\n }\n }\n }',
},
query: {},
};
export const mockResponseHost = {
took: 89,
timed_out: false,
_shards: { total: 18, successful: 18, skipped: 0, failed: 0 },
hits: { total: { value: 950867, relation: 'eq' }, max_score: null, hits: [] },
aggregations: {
auditd_count: { doc_count: 73847 },
fim_count: { doc_count: 107307 },
system_module: {
doc_count: 20000000,
login_count: { doc_count: 60015 },
package_count: { doc_count: 2003 },
process_count: { doc_count: 1200 },
user_count: { doc_count: 1979 },
},
},
};
export const mockResultHost = {
auditbeatAuditd: 73847,
auditbeatFIM: 107307,
auditbeatLogin: 60015,
auditbeatPackage: 2003,
auditbeatProcess: 1200,
auditbeatUser: 1979,
};

View file

@ -0,0 +1,167 @@
/*
* 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 { createQueryFilterClauses } from '../../utils/build_query';
import { RequestBasicOptions } from '../framework';
export const buildOverviewNetworkQuery = ({
filterQuery,
timerange: { from, to },
sourceConfiguration: {
fields: { timestamp },
auditbeatAlias,
logAlias,
packetbeatAlias,
},
}: RequestBasicOptions) => {
const filter = [
...createQueryFilterClauses(filterQuery),
{
range: {
[timestamp]: {
gte: from,
lte: to,
},
},
},
];
const dslQuery = {
allowNoIndices: true,
index: [auditbeatAlias, logAlias, packetbeatAlias],
ignoreUnavailable: true,
body: {
aggregations: {
unique_flow_count: {
filter: {
term: { type: 'flow' },
},
},
unique_dns_count: {
filter: {
term: { type: 'dns' },
},
},
unique_suricata_count: {
filter: {
term: { 'service.type': 'suricata' },
},
},
unique_zeek_count: {
filter: {
term: { 'service.type': 'zeek' },
},
},
unique_socket_count: {
filter: {
term: { 'event.dataset': 'socket' },
},
},
},
query: {
bool: {
filter,
},
},
size: 0,
track_total_hits: true,
},
};
return dslQuery;
};
export const buildOverviewHostQuery = ({
filterQuery,
timerange: { from, to },
sourceConfiguration: {
fields: { timestamp },
auditbeatAlias,
logAlias,
packetbeatAlias,
},
}: RequestBasicOptions) => {
const filter = [
...createQueryFilterClauses(filterQuery),
{
range: {
[timestamp]: {
gte: from,
lte: to,
},
},
},
];
const dslQuery = {
allowNoIndices: true,
index: [auditbeatAlias],
ignoreUnavailable: true,
body: {
aggregations: {
auditd_count: {
filter: {
term: {
'event.module': 'auditd',
},
},
},
fim_count: {
filter: {
term: {
'event.module': 'file_integrity',
},
},
},
system_module: {
filter: {
term: {
'event.module': 'system',
},
},
aggs: {
login_count: {
filter: {
term: {
'event.dataset': 'login',
},
},
},
package_count: {
filter: {
term: {
'event.dataset': 'package',
},
},
},
process_count: {
filter: {
term: {
'event.dataset': 'process',
},
},
},
user_count: {
filter: {
term: {
'event.dataset': 'user',
},
},
},
},
},
},
query: {
bool: {
filter,
},
},
size: 0,
track_total_hits: true,
},
};
return dslQuery;
};

View file

@ -0,0 +1,64 @@
/*
* 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 { OverviewHostData, OverviewNetworkData } from '../../graphql/types';
import { FrameworkRequest, RequestBasicOptions } from '../framework';
import { SearchHit } from '../types';
export interface OverviewAdapter {
getOverviewNetwork(
request: FrameworkRequest,
options: RequestBasicOptions
): Promise<OverviewNetworkData>;
getOverviewHost(
request: FrameworkRequest,
options: RequestBasicOptions
): Promise<OverviewHostData>;
}
export interface OverviewNetworkHit extends SearchHit {
aggregations: {
unique_flow_count: {
doc_count: number;
};
unique_dns_count: {
doc_count: number;
};
unique_suricata_count: {
doc_count: number;
};
unique_zeek_count: {
doc_count: number;
};
unique_socket_count: {
doc_count: number;
};
};
}
export interface OverviewHostHit extends SearchHit {
aggregations: {
auditd_count: {
doc_count: number;
};
fim_count: {
doc_count: number;
};
system_module: {
login_count: {
doc_count: number;
};
package_count: {
doc_count: number;
};
process_count: {
doc_count: number;
};
user_count: {
doc_count: number;
};
};
};
}

View file

@ -13,6 +13,7 @@ import { IndexFields } from './index_fields';
import { IpOverview } from './ip_overview';
import { KpiNetwork } from './kpi_network';
import { Network } from './network';
import { Overview } from './overview';
import { SourceStatus } from './source_status';
import { SourceConfigurations, Sources } from './sources';
import { UncommonProcesses } from './uncommon_processes';
@ -27,6 +28,7 @@ export interface AppDomainLibs {
ipOverview: IpOverview;
network: Network;
kpiNetwork: KpiNetwork;
overview: Overview;
uncommonProcesses: UncommonProcesses;
}

View file

@ -17,5 +17,7 @@ export default function ({ loadTestFile }) {
loadTestFile(require.resolve('./timeline_details'));
loadTestFile(require.resolve('./uncommon_processes'));
loadTestFile(require.resolve('./kpi_network'));
loadTestFile(require.resolve('./overview_network'));
loadTestFile(require.resolve('./overview_host'));
});
}

View file

@ -0,0 +1,55 @@
/*
* 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 { overviewHostQuery } from '../../../../plugins/secops/public/containers/overview/overview_host/index.gql_query';
import { GetOverviewHostQuery } from '../../../../plugins/secops/public/graphql/types';
import { KbnTestProvider } from './types';
const overviewHostTests: KbnTestProvider = ({ getService }) => {
const esArchiver = getService('esArchiver');
const client = getService('secOpsGraphQLClient');
describe('Overview Host', () => {
describe('With auditbeat', () => {
before(() => esArchiver.load('auditbeat/overview'));
after(() => esArchiver.unload('auditbeat/overview'));
const FROM = new Date('2000-01-01T00:00:00.000Z').valueOf();
const TO = new Date('3000-01-01T00:00:00.000Z').valueOf();
const expectedResult = {
auditbeatAuditd: 2194,
auditbeatFIM: 4,
auditbeatLogin: 2810,
auditbeatPackage: 3,
auditbeatProcess: 7,
auditbeatUser: 6,
__typename: 'OverviewHostData',
};
it('Make sure that we get OverviewHost data', () => {
return client
.query<GetOverviewHostQuery.Query>({
query: overviewHostQuery,
variables: {
sourceId: 'default',
timerange: {
interval: '12h',
to: TO,
from: FROM,
},
},
})
.then(resp => {
const overviewHost = resp.data.source.OverviewHost;
expect(overviewHost).to.eql(expectedResult);
});
});
});
});
};
// tslint:disable-next-line no-default-export
export default overviewHostTests;

View file

@ -0,0 +1,125 @@
/*
* 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 { overviewNetworkQuery } from '../../../../plugins/secops/public/containers/overview/overview_network/index.gql_query';
import { GetOverviewNetworkQuery } from '../../../../plugins/secops/public/graphql/types';
import { KbnTestProvider } from './types';
const overviewNetworkTests: KbnTestProvider = ({ getService }) => {
const esArchiver = getService('esArchiver');
const client = getService('secOpsGraphQLClient');
describe('Overview Network', () => {
describe('With filebeat', () => {
before(() => esArchiver.load('filebeat/default'));
after(() => esArchiver.unload('filebeat/default'));
const FROM = new Date('2000-01-01T00:00:00.000Z').valueOf();
const TO = new Date('3000-01-01T00:00:00.000Z').valueOf();
const expectedResult = {
packetbeatFlow: 0,
packetbeatDNS: 0,
filebeatSuricata: 4547,
filebeatZeek: 0,
auditbeatSocket: 0,
__typename: 'OverviewNetworkData',
};
it('Make sure that we get OverviewNetwork data', () => {
return client
.query<GetOverviewNetworkQuery.Query>({
query: overviewNetworkQuery,
variables: {
sourceId: 'default',
timerange: {
interval: '12h',
to: TO,
from: FROM,
},
},
})
.then(resp => {
const overviewNetwork = resp.data.source.OverviewNetwork;
expect(overviewNetwork).to.eql(expectedResult);
});
});
});
describe('With packetbeat', () => {
before(() => esArchiver.load('packetbeat/overview'));
after(() => esArchiver.unload('packetbeat/overview'));
const FROM = new Date('2000-01-01T00:00:00.000Z').valueOf();
const TO = new Date('3000-01-01T00:00:00.000Z').valueOf();
const expectedResult = {
packetbeatFlow: 0,
packetbeatDNS: 0,
filebeatSuricata: 4547,
filebeatZeek: 0,
auditbeatSocket: 0,
__typename: 'OverviewNetworkData',
};
it('Make sure that we get OverviewNetwork data', () => {
return client
.query<GetOverviewNetworkQuery.Query>({
query: overviewNetworkQuery,
variables: {
sourceId: 'default',
timerange: {
interval: '12h',
to: TO,
from: FROM,
},
},
})
.then(resp => {
const overviewNetwork = resp.data.source.OverviewNetwork;
expect(overviewNetwork).to.eql(expectedResult);
});
});
});
describe('With auditbeat', () => {
before(() => esArchiver.load('auditbeat/overview'));
after(() => esArchiver.unload('auditbeat/overview'));
const FROM = new Date('2000-01-01T00:00:00.000Z').valueOf();
const TO = new Date('3000-01-01T00:00:00.000Z').valueOf();
const expectedResult = {
packetbeatFlow: 0,
packetbeatDNS: 0,
filebeatSuricata: 4547,
filebeatZeek: 0,
auditbeatSocket: 0,
__typename: 'OverviewNetworkData',
};
it('Make sure that we get OverviewNetwork data', () => {
return client
.query<GetOverviewNetworkQuery.Query>({
query: overviewNetworkQuery,
variables: {
sourceId: 'default',
timerange: {
interval: '12h',
to: TO,
from: FROM,
},
},
})
.then(resp => {
const overviewNetwork = resp.data.source.OverviewNetwork;
expect(overviewNetwork).to.eql(expectedResult);
});
});
});
});
};
// tslint:disable-next-line no-default-export
export default overviewNetworkTests;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff