[Security Solutions] Fixes telemetry to work with rule types (#120809)

## Summary

What this does:
* Fixes telemetry to work with the newer rule types
* Updates the queries to the new rule types and rule query names
* Uses constants where I can from cases and the new rule types
* Changes the index to the new index type alias
* Adds e2e backend tests we didn't have before

What this does not do:
* Doesn't add e2e backend tests for alerts added to cases
* Doesn't add e2e backend tests for ML jobs for security_solution

Those two test scenarios have to be manually tested still.

Manual testing:
To see telemetry go to advanced settings -> Usage Data (and click cluster data):
<img width="2193" alt="Screen Shot 2021-12-08 at 4 14 43 PM" src="https://user-images.githubusercontent.com/1151048/145310671-b7350892-d290-4f3d-ab8c-4e9ec86f4120.png">

Create alerts of different types and add them to cases:
<img width="1464" alt="Screen Shot 2021-12-08 at 4 48 21 PM" src="https://user-images.githubusercontent.com/1151048/145310800-2fae6373-5e84-46ec-9e44-f7a140ea9c36.png">

Activate ML_jobs and any alerts that have ML jobs associated:
<img width="754" alt="Screen Shot 2021-12-08 at 5 08 42 PM" src="https://user-images.githubusercontent.com/1151048/145310978-861f4bb7-2575-4a07-a55f-1e4fdfe288e7.png">

When clicking advanced settings -> Usage Data -> Click cluster data

Search for `security_solution` and then ensure that the data looks as expected underneath the different values such as:

`ml_jobs`
<img width="750" alt="Screen Shot 2021-12-08 at 3 08 25 PM" src="https://user-images.githubusercontent.com/1151048/145311124-c3523d4e-b31b-4bab-b14e-267155bf2b92.png">

`detection_rules` and `cases` working again:
<img width="420" alt="Screen Shot 2021-12-08 at 4 43 10 PM" src="https://user-images.githubusercontent.com/1151048/145311192-e062c435-e8c3-4919-b4e9-8a786dc588c6.png">

Note, `detection_rule_detail` will only be filled in if have prepackaged rules installed:
<img width="761" alt="Screen Shot 2021-12-08 at 5 14 50 PM" src="https://user-images.githubusercontent.com/1151048/145311446-1d78541f-1211-4389-b947-7c0939d7c946.png">

Also note that the `detection_rule_detail`'s `rule_id` is its UUID and not its `rule_id`. That's the way it's been in the codebase for a while it looks like so I have not changed that behavior.

### Checklist

- [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
Frank Hassanabad 2021-12-09 17:56:42 -07:00 committed by GitHub
parent 5e34758d43
commit 181b9e0271
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 718 additions and 13 deletions

View file

@ -45,7 +45,12 @@ import { initSavedObjects } from './saved_objects';
import { AppClientFactory } from './client';
import { createConfig, ConfigType } from './config';
import { initUiSettings } from './ui_settings';
import { APP_ID, SERVER_APP_ID, LEGACY_NOTIFICATIONS_ID } from '../common/constants';
import {
APP_ID,
SERVER_APP_ID,
LEGACY_NOTIFICATIONS_ID,
DEFAULT_ALERTS_INDEX,
} from '../common/constants';
import { registerEndpointRoutes } from './endpoint/routes/metadata';
import { registerLimitedConcurrencyRoutes } from './endpoint/routes/limited_concurrency';
import { registerResolverRoutes } from './endpoint/routes/resolver';
@ -161,7 +166,7 @@ export class Plugin implements ISecuritySolutionPlugin {
initUsageCollectors({
core,
kibanaIndex: core.savedObjects.getKibanaIndex(),
signalsIndex: config.signalsIndex,
signalsIndex: DEFAULT_ALERTS_INDEX,
ml: plugins.ml,
usageCollection: plugins.usageCollection,
});

View file

@ -5,7 +5,17 @@
* 2.0.
*/
import { SIGNALS_ID } from '@kbn/securitysolution-rules';
import {
SIGNALS_ID,
EQL_RULE_TYPE_ID,
INDICATOR_RULE_TYPE_ID,
ML_RULE_TYPE_ID,
QUERY_RULE_TYPE_ID,
THRESHOLD_RULE_TYPE_ID,
SAVED_QUERY_RULE_TYPE_ID,
} from '@kbn/securitysolution-rules';
import { ALERT_RULE_UUID } from '@kbn/rule-data-utils';
import { CASE_COMMENT_SAVED_OBJECT } from '../../../../cases/common/constants';
import { ElasticsearchClient, SavedObjectsClientContract } from '../../../../../../src/core/server';
import { isElasticRule } from './index';
@ -188,7 +198,25 @@ export const getDetectionRuleMetrics = async (
): Promise<DetectionRuleAdoption> => {
let rulesUsage: DetectionRulesTypeUsage = initialDetectionRulesUsage;
const ruleSearchOptions: RuleSearchParams = {
body: { query: { bool: { filter: { term: { 'alert.alertTypeId': SIGNALS_ID } } } } },
body: {
query: {
bool: {
filter: {
terms: {
'alert.alertTypeId': [
SIGNALS_ID,
EQL_RULE_TYPE_ID,
ML_RULE_TYPE_ID,
QUERY_RULE_TYPE_ID,
SAVED_QUERY_RULE_TYPE_ID,
INDICATOR_RULE_TYPE_ID,
THRESHOLD_RULE_TYPE_ID,
],
},
},
},
},
},
filter_path: [],
ignore_unavailable: true,
index: kibanaIndex,
@ -203,7 +231,7 @@ export const getDetectionRuleMetrics = async (
body: {
aggs: {
detectionAlerts: {
terms: { field: 'signal.rule.id.keyword' },
terms: { field: ALERT_RULE_UUID },
},
},
query: {
@ -224,11 +252,10 @@ export const getDetectionRuleMetrics = async (
})) as { body: AlertsAggregationResponse };
const cases = await savedObjectClient.find<CasesSavedObject>({
type: 'cases-comments',
fields: [],
type: CASE_COMMENT_SAVED_OBJECT,
page: 1,
perPage: MAX_RESULTS_WINDOW,
filter: 'cases-comments.attributes.type: alert',
filter: `${CASE_COMMENT_SAVED_OBJECT}.attributes.type: alert`,
});
const casesCache = cases.saved_objects.reduce((cache, { attributes: casesObject }) => {
@ -247,14 +274,13 @@ export const getDetectionRuleMetrics = async (
const alertsCache = new Map<string, number>();
alertBuckets.map((bucket) => alertsCache.set(bucket.key, bucket.doc_count));
if (ruleResults.hits?.hits?.length > 0) {
const ruleObjects = ruleResults.hits.hits.map((hit) => {
const ruleId = hit._id.split(':')[1];
const isElastic = isElasticRule(hit._source?.alert.tags);
return {
rule_name: hit._source?.alert.name,
rule_id: ruleId,
rule_id: hit._source?.alert.params.ruleId,
rule_type: hit._source?.alert.params.type,
rule_version: hit._source?.alert.params.version,
enabled: hit._source?.alert.enabled,

View file

@ -111,7 +111,7 @@ describe('Detections Usage and Metrics', () => {
created_on: '2021-03-23T17:15:59.634Z',
elastic_rule: true,
enabled: false,
rule_id: '6eecd8c2-8bfb-11eb-afbe-1b7a66309c6d',
rule_id: '5370d4cd-2bb3-4d71-abf5-1e1d0ff5a2de',
rule_name: 'Azure Diagnostic Settings Deletion',
rule_type: 'query',
rule_version: 4,
@ -248,7 +248,7 @@ describe('Detections Usage and Metrics', () => {
created_on: '2021-03-23T17:15:59.634Z',
elastic_rule: true,
enabled: false,
rule_id: '6eecd8c2-8bfb-11eb-afbe-1b7a66309c6d',
rule_id: '5370d4cd-2bb3-4d71-abf5-1e1d0ff5a2de',
rule_name: 'Azure Diagnostic Settings Deletion',
rule_type: 'query',
rule_version: 4,

View file

@ -9,7 +9,7 @@ interface RuleSearchBody {
query: {
bool: {
filter: {
term: { [key: string]: string };
terms: { [key: string]: string[] };
};
};
};

View file

@ -68,5 +68,9 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
describe('', function () {
loadTestFile(require.resolve('./alerts/index'));
});
describe('', function () {
loadTestFile(require.resolve('./telemetry/index'));
});
});
};

View file

@ -0,0 +1,3 @@
These are tests for the telemetry rules within "security_solution/server/usage"
* detection_rules

View file

@ -0,0 +1,426 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import expect from '@kbn/expect';
import { DetectionMetrics } from '../../../../../plugins/security_solution/server/usage/detections/types';
import {
EqlCreateSchema,
QueryCreateSchema,
ThreatMatchCreateSchema,
ThresholdCreateSchema,
} from '../../../../../plugins/security_solution/common/detection_engine/schemas/request';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
import {
createRule,
createSignalsIndex,
deleteAllAlerts,
deleteSignalsIndex,
getEqlRuleForSignalTesting,
getInitialDetectionMetrics,
getRuleForSignalTesting,
getSimpleMlRule,
getSimpleThreatMatch,
getStats,
getThresholdRuleForSignalTesting,
installPrePackagedRules,
waitForRuleSuccessOrStatus,
waitForSignalsToBePresent,
} from '../../../utils';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
const log = getService('log');
const retry = getService('retry');
describe('Detection rule telemetry', async () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry');
});
after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry');
});
beforeEach(async () => {
await createSignalsIndex(supertest, log);
});
afterEach(async () => {
await deleteSignalsIndex(supertest, log);
await deleteAllAlerts(supertest, log);
});
it('should have initialized empty/zero values when no rules are running', async () => {
await retry.try(async () => {
const stats = await getStats(supertest, log);
expect(stats).to.eql(getInitialDetectionMetrics());
});
});
describe('"kql" rule type', () => {
it('should show stats for active rule', async () => {
const rule: QueryCreateSchema = getRuleForSignalTesting(['telemetry']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForSignalsToBePresent(supertest, log, 4, [id]);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
query: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
enabled: 1,
alerts: 4,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
enabled: 1,
alerts: 4,
},
},
},
};
expect(stats).to.eql(expected);
});
});
it('should show stats for in-active rule', async () => {
const rule: QueryCreateSchema = getRuleForSignalTesting(['telemetry'], 'rule-1', false);
await createRule(supertest, log, rule);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
query: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
disabled: 1,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
disabled: 1,
},
},
},
};
expect(stats).to.eql(expected);
});
});
});
describe('"eql" rule type', () => {
it('should show stats for active rule', async () => {
const rule: EqlCreateSchema = getEqlRuleForSignalTesting(['telemetry']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForSignalsToBePresent(supertest, log, 4, [id]);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
eql: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
enabled: 1,
alerts: 4,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
enabled: 1,
alerts: 4,
},
},
},
};
expect(stats).to.eql(expected);
});
});
it('should show stats for in-active rule', async () => {
const rule: EqlCreateSchema = getEqlRuleForSignalTesting(['telemetry'], 'rule-1', false);
await createRule(supertest, log, rule);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
eql: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
disabled: 1,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
disabled: 1,
},
},
},
};
expect(stats).to.eql(expected);
});
});
});
describe('"threshold" rule type', () => {
it('should show stats for active rule', async () => {
const rule: ThresholdCreateSchema = {
...getThresholdRuleForSignalTesting(['telemetry']),
threshold: {
field: 'keyword',
value: 1,
},
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForSignalsToBePresent(supertest, log, 4, [id]);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
threshold: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
enabled: 1,
alerts: 4,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
enabled: 1,
alerts: 4,
},
},
},
};
expect(stats).to.eql(expected);
});
});
it('should show stats for in-active rule', async () => {
const rule: ThresholdCreateSchema = {
...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false),
threshold: {
field: 'keyword',
value: 1,
},
};
await createRule(supertest, log, rule);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
threshold: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
disabled: 1,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
disabled: 1,
},
},
},
};
expect(stats).to.eql(expected);
});
});
});
describe('"ml" rule type', () => {
// Note: We don't actually find signals with this test as we don't have a good way of signal finding with ML rules.
it('should show stats for active rule', async () => {
const rule = getSimpleMlRule('rule-1', true);
await createRule(supertest, log, rule);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
machine_learning: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
enabled: 1,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
enabled: 1,
},
},
},
};
expect(stats).to.eql(expected);
});
});
it('should show stats for in-active rule', async () => {
const rule = getSimpleMlRule();
await createRule(supertest, log, rule);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
machine_learning: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
disabled: 1,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
disabled: 1,
},
},
},
};
expect(stats).to.eql(expected);
});
});
});
describe('"indicator_match/threat_match" rule type', () => {
it('should show stats for active rule', async () => {
const rule: ThreatMatchCreateSchema = {
...getSimpleThreatMatch('rule-1', true),
index: ['telemetry'],
threat_index: ['telemetry'],
threat_mapping: [
{
entries: [
{
field: 'keyword',
value: 'keyword',
type: 'mapping',
},
],
},
],
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccessOrStatus(supertest, log, id);
await waitForSignalsToBePresent(supertest, log, 4, [id]);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
threat_match: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
enabled: 1,
alerts: 4,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
enabled: 1,
alerts: 4,
},
},
},
};
expect(stats).to.eql(expected);
});
});
it('should show stats for in-active rule', async () => {
const rule = getSimpleThreatMatch();
await createRule(supertest, log, rule);
await retry.try(async () => {
const stats = await getStats(supertest, log);
const expected: DetectionMetrics = {
...getInitialDetectionMetrics(),
detection_rules: {
...getInitialDetectionMetrics().detection_rules,
detection_rule_usage: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage,
threat_match: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query,
disabled: 1,
},
custom_total: {
...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total,
disabled: 1,
},
},
},
};
expect(stats).to.eql(expected);
});
});
});
describe('"pre-packaged" rules', async () => {
it('should show stats for totals for in-active pre-packaged rules', async () => {
await installPrePackagedRules(supertest, log);
await retry.try(async () => {
const stats = await getStats(supertest, log);
expect(stats.detection_rules.detection_rule_usage.elastic_total.enabled).above(0);
expect(stats.detection_rules.detection_rule_usage.elastic_total.disabled).above(0);
expect(stats.detection_rules.detection_rule_usage.elastic_total.enabled).above(0);
expect(stats.detection_rules.detection_rule_usage.custom_total.enabled).equal(0);
expect(stats.detection_rules.detection_rule_detail.length).above(0);
});
});
it('should show stats for the detection_rule_details for pre-packaged rules', async () => {
await installPrePackagedRules(supertest, log);
await retry.try(async () => {
const stats = await getStats(supertest, log);
// Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file:
// x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json
// We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id
const foundRule = stats.detection_rules.detection_rule_detail.find(
(rule) => rule.rule_id === '9a1a2dae-0b5f-4c3d-8305-a268d404c306'
);
if (foundRule == null) {
throw new Error('Found rule should not be null');
}
const {
created_on: createdOn,
updated_on: updatedOn,
rule_id: ruleId,
...omittedFields
} = foundRule;
expect(omittedFields).to.eql({
rule_name: 'Endpoint Security',
rule_type: 'query',
rule_version: 3,
enabled: true,
elastic_rule: true,
alert_count_daily: 0,
cases_count_total: 0,
});
});
});
});
});
};

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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrProviderContext } from '../../../common/ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default ({ loadTestFile }: FtrProviderContext): void => {
describe('Detection rule type telemetry', function () {
describe('', function () {
this.tags('ciGroup11');
loadTestFile(require.resolve('./detection_rules'));
});
});
};

View file

@ -34,6 +34,7 @@ import {
EqlCreateSchema,
ThresholdCreateSchema,
PreviewRulesSchema,
ThreatMatchCreateSchema,
} from '../../plugins/security_solution/common/detection_engine/schemas/request';
import { signalsMigrationType } from '../../plugins/security_solution/server/lib/detection_engine/migrations/saved_objects';
import {
@ -53,6 +54,7 @@ import {
UPDATE_OR_CREATE_LEGACY_ACTIONS,
} from '../../plugins/security_solution/common/constants';
import { RACAlert } from '../../plugins/security_solution/server/lib/detection_engine/rule_types/types';
import { DetectionMetrics } from '../../plugins/security_solution/server/usage/detections/types';
/**
* This will remove server generated properties such as date times, etc...
@ -1827,3 +1829,151 @@ export const getOpenSignals = async (
await refreshIndex(es, '.alerts-security.alerts-default*');
return getSignalsByIds(supertest, log, [rule.id]);
};
/**
* Cluster stats URL. Replace this with any from kibana core if there is ever a constant there for this.
*/
export const getStatsUrl = (): string => '/api/telemetry/v2/clusters/_stats';
/**
* Initial detection metrics initialized.
*/
export const getInitialDetectionMetrics = (): DetectionMetrics => ({
ml_jobs: {
ml_job_usage: {
custom: {
enabled: 0,
disabled: 0,
},
elastic: {
enabled: 0,
disabled: 0,
},
},
ml_job_metrics: [],
},
detection_rules: {
detection_rule_detail: [],
detection_rule_usage: {
query: {
enabled: 0,
disabled: 0,
alerts: 0,
cases: 0,
},
threshold: {
enabled: 0,
disabled: 0,
alerts: 0,
cases: 0,
},
eql: {
enabled: 0,
disabled: 0,
alerts: 0,
cases: 0,
},
machine_learning: {
enabled: 0,
disabled: 0,
alerts: 0,
cases: 0,
},
threat_match: {
enabled: 0,
disabled: 0,
alerts: 0,
cases: 0,
},
elastic_total: {
enabled: 0,
disabled: 0,
alerts: 0,
cases: 0,
},
custom_total: {
enabled: 0,
disabled: 0,
alerts: 0,
cases: 0,
},
},
},
});
/**
* Given a body this will return the detection metrics from it.
* @param body The Stats body
* @returns Detection metrics
*/
export const getDetectionMetricsFromBody = (
body: Array<{
stats: {
stack_stats: {
kibana: { plugins: { security_solution: { detectionMetrics: DetectionMetrics } } };
};
};
}>
): DetectionMetrics => {
return body[0].stats.stack_stats.kibana.plugins.security_solution.detectionMetrics;
};
/**
* Gets the stats from the stats endpoint
* @param supertest The supertest agent.
* @returns The detection metrics
*/
export const getStats = async (
supertest: SuperTest.SuperTest<SuperTest.Test>,
log: ToolingLog
): Promise<DetectionMetrics> => {
const response = await supertest
.post(getStatsUrl())
.set('kbn-xsrf', 'true')
.send({ unencrypted: true });
if (response.status !== 200) {
log.error(
`Did not get an expected 200 "ok" when getting the stats for detections. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify(
response.body
)}, status: ${JSON.stringify(response.status)}`
);
}
return getDetectionMetricsFromBody(response.body);
};
/**
* This is a typical simple indicator match/threat match for testing that is easy for most basic testing
* @param ruleId
* @param enabled Enables the rule on creation or not. Defaulted to false.
*/
export const getSimpleThreatMatch = (
ruleId = 'rule-1',
enabled = false
): ThreatMatchCreateSchema => ({
description: 'Detecting root and admin users',
name: 'Query with a rule id',
severity: 'high',
enabled,
index: ['auditbeat-*'],
type: 'threat_match',
risk_score: 55,
language: 'kuery',
rule_id: ruleId,
from: '1900-01-01T00:00:00.000Z',
query: '*:*',
threat_query: '*:*',
threat_index: ['auditbeat-*'],
threat_mapping: [
// We match host.name against host.name
{
entries: [
{
field: 'host.name',
value: 'host.name',
type: 'mapping',
},
],
},
],
threat_filters: [],
});

View file

@ -9,3 +9,5 @@ or
```
x-pack/test/api_integration/apis/security_solution
```
* Folder `telemetry` is for the tests underneath `detection_engine_api_integration/security_and_spaces/tests/telemetry`.

View file

@ -0,0 +1,51 @@
{
"type": "doc",
"value": {
"id": "1",
"index": "telemetry",
"source": {
"@timestamp": "2020-10-28T05:00:53.000Z",
"keyword": "word one"
},
"type": "_doc"
}
}
{
"type": "doc",
"value": {
"id": "2",
"index": "telemetry",
"source": {
"@timestamp": "2020-10-28T05:01:53.000Z",
"keyword": "word two"
},
"type": "_doc"
}
}
{
"type": "doc",
"value": {
"id": "3",
"index": "telemetry",
"source": {
"@timestamp": "2020-10-28T05:02:53.000Z",
"keyword": "word three"
},
"type": "_doc"
}
}
{
"type": "doc",
"value": {
"id": "4",
"index": "telemetry",
"source": {
"@timestamp": "2020-10-28T05:03:53.000Z",
"keyword": "word four"
},
"type": "_doc"
}
}

View file

@ -0,0 +1,20 @@
{
"type": "index",
"value": {
"index": "telemetry",
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
},
"keyword": { "type": "keyword" }
}
},
"settings": {
"index": {
"number_of_replicas": "1",
"number_of_shards": "1"
}
}
}
}