[Security Solution][API testing] Move and restructures Alerts' tests (#170350)

## Summary

- Following the initial work in this
https://github.com/elastic/kibana/pull/166755
- Addresses part of https://github.com/elastic/kibana/issues/151902 for
Alerts
- Introduced a new folder called `alerts` under
`security_solution_api_integration`
- Moved the utility files associated with alerts to the new directory
`security_solution_api_integration`. Files that were not actively used
in the previous folder were moved, while any duplicate files remained in
their original positions.
- Updated the CodeOwner file for the newly moved tests
- Old / new groups details and execution time
[document](https://docs.google.com/document/d/1CRFfDWMzw3ob03euWIvT4-IoiLXjoiPWI8mTBqP4Zks/edit)

| Action | File | New Path if moved |
|--------|------|----------|
| Delete| group1/find_rule_exception_references.ts| Already moved in
previous PR |
| Delete|security_and_spaces/group6  | - |
| Move|detection_engine_api_integration/security_and_spaces/group6
|detections_response/default_license/alerts/alerts_compatibility.ts|
| Move|detection_engine_api_integration/security_and_spaces/group1|
detections_response/default_license/alerts/aliases.ts |
| Move |detection_engine_api_integration/security_and_spaces/group1|
detections_response/default_license/alerts/create_index.ts|
|
Move|detection_engine_api_integration/security_and_spaces/group10/create_signals_migrations|
detections_response/default_license/alerts/migrations/create_alerts_migrations.ts
|
|
Move|detection_engine_api_integration/security_and_spaces/group10/delete_signals_migrations|
detections_response/default_license/alerts/migrations/delete_alerts_migrations.ts|
|
Move|detection_engine_api_integration/security_and_spaces/group10/finalize_signals_migrations|
detections_response/default_license/alerts/migrations/finalize_alerts_migrations.ts
|
|
Move|detection_engine_api_integration/security_and_spaces/group10/get_signals_migration_status|
detections_response/default_license/alerts/migrations/get_alerts_migration_status.ts|
|
Move|detection_engine_api_integration/security_and_spaces/group10/open_close_signals|
detections_response/default_license/alerts/open_close_alerts.ts|
|
Move|detection_engine_api_integration/security_and_spaces/group10/alert_tags|
detections_response/default_license/alerts/alert_tags.ts|


Note: these tests are skipped on the main branch


https://github.com/elastic/kibana/blob/main/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/open_close_signals.ts#L215



https://github.com/elastic/kibana/blob/main/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/open_close_signals.ts#L252


https://github.com/elastic/kibana/blob/main/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/finalize_signals_migrations.ts#L192


https://github.com/elastic/kibana/blob/main/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_index.ts#L42

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Wafaa Nasr 2023-11-07 13:42:05 +01:00 committed by GitHub
parent 550b3cf08d
commit 2b5f4f7a0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 576 additions and 528 deletions

View file

@ -225,7 +225,6 @@ enabled:
- x-pack/test/detection_engine_api_integration/security_and_spaces/group1/config.ts
- x-pack/test/detection_engine_api_integration/security_and_spaces/group4/config.ts
- x-pack/test/detection_engine_api_integration/security_and_spaces/group5/config.ts
- x-pack/test/detection_engine_api_integration/security_and_spaces/group6/config.ts
- x-pack/test/detection_engine_api_integration/security_and_spaces/group10/config.ts
- x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/config.ts
- x-pack/test/detection_engine_api_integration/security_and_spaces/prebuilt_rules/config.ts
@ -461,6 +460,8 @@ enabled:
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/configs/ess.config.ts
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/serverless.config.ts
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/ess.config.ts
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/configs/serverless.config.ts
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/configs/ess.config.ts

6
.github/CODEOWNERS vendored
View file

@ -1312,8 +1312,10 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics @elastic/security-detection-engine
/x-pack/test/security_solution_cypress/cypress/e2e/exceptions @elastic/security-detection-engine
/x-pack/test/security_solution_cypress/cypress/e2e/overview @elastic/security-detection-engine
x-pack/test/security_solution_api_integration/test_suites/detections_response/exceptions @elastic/security-detection-engine
x-pack/test/security_solution_api_integration/test_suites/detections_response/rule_creation @elastic/security-detection-engine
x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions @elastic/security-detection-engine
x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation @elastic/security-detection-engine
x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions @elastic/security-detection-engine
x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts @elastic/security-detection-engine
## Security Threat Intelligence - Under Security Platform
/x-pack/plugins/security_solution/public/common/components/threat_match @elastic/security-detection-engine

View file

@ -1,230 +0,0 @@
/*
* 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.
*/
/* eslint-disable @typescript-eslint/naming-convention */
import expect from '@kbn/expect';
import {
CreateExceptionListSchema,
ExceptionListTypeEnum,
} from '@kbn/securitysolution-io-ts-list-types';
import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock';
import {
DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL,
RuleReferencesSchema,
} from '@kbn/security-solution-plugin/common/api/detection_engine/rule_exceptions';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
createRule,
getSimpleRule,
createSignalsIndex,
deleteAllAlerts,
deleteAllRules,
createExceptionList,
} from '../../utils';
import { deleteAllExceptions } from '../../../lists_api_integration/utils';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const log = getService('log');
const es = getService('es');
describe('find_rule_exception_references', () => {
before(async () => {
await createSignalsIndex(supertest, log);
});
after(async () => {
await deleteAllAlerts(supertest, log, es);
await deleteAllRules(supertest, log);
});
afterEach(async () => {
await deleteAllExceptions(supertest, log);
});
it('returns empty array per list_id if no references are found', async () => {
// create exception list
const newExceptionList: CreateExceptionListSchema = {
...getCreateExceptionListMinimalSchemaMock(),
list_id: 'i_exist',
namespace_type: 'single',
type: ExceptionListTypeEnum.DETECTION,
};
const exceptionList = await createExceptionList(supertest, log, newExceptionList);
// create rule
await createRule(supertest, log, getSimpleRule('rule-1'));
const { body: references } = await supertest
.get(DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL)
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
.query({
ids: `${exceptionList.id}`,
list_ids: `${exceptionList.list_id}`,
namespace_types: `${exceptionList.namespace_type}`,
})
.expect(200);
const {
_version,
id,
created_at,
created_by,
tie_breaker_id,
updated_at,
updated_by,
...referencesWithoutServerValues
} = references.references[0].i_exist;
expect({
references: [
{
i_exist: {
...referencesWithoutServerValues,
},
},
],
}).to.eql({
references: [
{
i_exist: {
description: 'some description',
immutable: false,
list_id: 'i_exist',
name: 'some name',
namespace_type: 'single',
os_types: [],
tags: [],
type: 'detection',
version: 1,
referenced_rules: [],
},
},
],
});
});
it('returns empty array per list_id if list does not exist', async () => {
// create rule
await createRule(supertest, log, getSimpleRule('rule-1'));
const { body: references } = await supertest
.get(DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL)
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
.query({
ids: `1234`,
list_ids: `i_dont_exist`,
namespace_types: `single`,
})
.expect(200);
expect(references).to.eql({ references: [] });
});
it('returns found references', async () => {
// create exception list
const newExceptionList: CreateExceptionListSchema = {
...getCreateExceptionListMinimalSchemaMock(),
list_id: 'i_exist',
namespace_type: 'single',
type: ExceptionListTypeEnum.DETECTION,
};
const exceptionList = await createExceptionList(supertest, log, newExceptionList);
const exceptionList2 = await createExceptionList(supertest, log, {
...newExceptionList,
list_id: 'i_exist_2',
});
// create rule
await createRule(supertest, log, {
...getSimpleRule('rule-2'),
exceptions_list: [
{
id: `${exceptionList.id}`,
list_id: `${exceptionList.list_id}`,
namespace_type: `${exceptionList.namespace_type}`,
type: `${exceptionList.type}`,
},
{
id: `${exceptionList2.id}`,
list_id: `${exceptionList2.list_id}`,
namespace_type: `${exceptionList2.namespace_type}`,
type: `${exceptionList2.type}`,
},
],
});
const { body: references } = await supertest
.get(DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL)
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
.query({
ids: `${exceptionList.id},${exceptionList2.id}`,
list_ids: `${exceptionList.list_id},${exceptionList2.list_id}`,
namespace_types: `${exceptionList.namespace_type},${exceptionList2.namespace_type}`,
})
.expect(200);
const refs = references.references.flatMap((ref: RuleReferencesSchema) => Object.keys(ref));
expect(refs.sort()).to.eql(['i_exist', 'i_exist_2'].sort());
});
it('returns found references for all existing exception lists if no list id/list_id passed in', async () => {
// create exception list
const newExceptionList: CreateExceptionListSchema = {
...getCreateExceptionListMinimalSchemaMock(),
list_id: 'i_exist',
namespace_type: 'single',
type: ExceptionListTypeEnum.DETECTION,
};
const exceptionList = await createExceptionList(supertest, log, newExceptionList);
const exceptionList2 = await createExceptionList(supertest, log, {
...newExceptionList,
list_id: 'i_exist_2',
});
// create rule
await createRule(supertest, log, {
...getSimpleRule('rule-2'),
exceptions_list: [
{
id: `${exceptionList.id}`,
list_id: `${exceptionList.list_id}`,
namespace_type: `${exceptionList.namespace_type}`,
type: `${exceptionList.type}`,
},
{
id: `${exceptionList2.id}`,
list_id: `${exceptionList2.list_id}`,
namespace_type: `${exceptionList2.namespace_type}`,
type: `${exceptionList2.type}`,
},
],
});
const { body: references } = await supertest
.get(DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL)
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
.query({
namespace_types: 'single,agnostic',
})
.expect(200);
const refs = references.references.flatMap((ref: RuleReferencesSchema) => Object.keys(ref));
expect(refs.sort()).to.eql(['i_exist', 'i_exist_2', 'endpoint_list'].sort());
});
});
};

View file

@ -14,15 +14,12 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
// action migration code. We are monitoring legacy action telemetry to clean up once we see their
// existence being near 0.
loadTestFile(require.resolve('./aliases'));
loadTestFile(require.resolve('./check_privileges'));
loadTestFile(require.resolve('./create_index'));
loadTestFile(require.resolve('./create_rules_bulk'));
loadTestFile(require.resolve('./delete_rules'));
loadTestFile(require.resolve('./delete_rules_bulk'));
loadTestFile(require.resolve('./export_rules'));
loadTestFile(require.resolve('./find_rules'));
loadTestFile(require.resolve('./find_rule_exception_references'));
loadTestFile(require.resolve('./get_rule_management_filters'));
});
};

View file

@ -26,11 +26,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
loadTestFile(require.resolve('./perform_bulk_action_dry_run'));
loadTestFile(require.resolve('./patch_rules'));
loadTestFile(require.resolve('./read_privileges'));
loadTestFile(require.resolve('./open_close_signals'));
loadTestFile(require.resolve('./get_signals_migration_status'));
loadTestFile(require.resolve('./create_signals_migrations'));
loadTestFile(require.resolve('./finalize_signals_migrations'));
loadTestFile(require.resolve('./delete_signals_migrations'));
loadTestFile(require.resolve('./timestamps'));
loadTestFile(require.resolve('./runtime'));
loadTestFile(require.resolve('./throttle'));
@ -40,6 +35,5 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
loadTestFile(require.resolve('./risk_engine/risk_score_calculation'));
loadTestFile(require.resolve('./risk_engine/risk_scoring_task_execution'));
loadTestFile(require.resolve('./risk_engine/telemetry_usage'));
loadTestFile(require.resolve('./set_alert_tags'));
});
};

View file

@ -1,15 +0,0 @@
/*
* 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 engine signals/alerts compatibility', function () {
loadTestFile(require.resolve('./alerts_compatibility'));
});
};

View file

@ -1,15 +0,0 @@
/*
* 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 engine api security and spaces enabled - Group 6', function () {
loadTestFile(require.resolve('./alerts'));
});
};

View file

@ -25,7 +25,6 @@ export * from './delete_all_rule_execution_info';
export * from './delete_all_alerts';
export * from './delete_all_timelines';
export * from './delete_exception_list';
export * from './delete_migrations';
export * from './delete_rule';
export * from './downgrade_immutable_rule';
export * from './finalize_signals_migration';
@ -35,14 +34,12 @@ export * from './get_complex_rule_output';
export * from './get_detection_metrics_from_body';
export * from './get_eql_rule_for_signal_testing';
export * from './get_event_log_execute_complete_by_id';
export * from './get_index_name_from_load';
export * from './get_legacy_action_notification_so';
export * from './get_open_signals';
export * from './get_preview_alerts';
export * from './get_query_all_signals';
export * from './get_query_signal_ids';
export * from './get_query_signals_ids';
export * from './get_query_signals_rule_id';
export * from './get_query_signal_ids';
export * from './get_rule';
export * from './get_rules_as_ndjson';
export * from './get_rule_for_signal_testing';
@ -53,7 +50,6 @@ export * from './get_rule_with_legacy_investigation_fields';
export * from './get_saved_query_rule_for_signal_testing';
export * from './get_security_telemetry_stats';
export * from './get_signal_status';
export * from './get_signal_status_empty_response';
export * from './get_signals_by_id';
export * from './get_signals_by_ids';
export * from './get_signals_by_rule_ids';
@ -93,7 +89,6 @@ export * from './update_rule';
export * from './wait_for';
export * from './wait_for_alert_to_complete';
export * from './wait_for_event_log_execute_complete';
export * from './wait_for_index_to_populate';
export * from './wait_for_rule_status';
export * from './wait_for_signals_to_be_present';
export * from './prebuilt_rules/create_prebuilt_rule_saved_objects';

View file

@ -36,6 +36,11 @@
"actions:runner:serverless": "npm run run-tests:dr:default actions serverless serverlessEnv",
"actions:qa:serverless": "npm run run-tests:dr:default actions serverless qaEnv",
"actions:server:ess": "npm run initialize-server:dr:default actions ess",
"actions:runner:ess": "npm run run-tests:dr:default actions ess essEnv"
"actions:runner:ess": "npm run run-tests:dr:default actions ess essEnv",
"alerts:server:serverless": "npm run initialize-server:dr:default alerts serverless",
"alerts:runner:serverless": "npm run run-tests:dr:default alerts serverless serverlessEnv",
"alerts:qa:serverless": "npm run run-tests:dr:default alerts serverless qaEnv",
"alerts:server:ess": "npm run initialize-server:dr:default alerts ess",
"alerts:runner:ess": "npm run run-tests:dr:default alerts ess essEnv"
}
}

View file

@ -22,32 +22,31 @@ import {
} from '@kbn/security-solution-plugin/common/api/detection_engine';
import {
createRule,
createSignalsIndex,
createAlertsIndex,
deleteAllRules,
deleteAllAlerts,
finalizeSignalsMigration,
getEqlRuleForSignalTesting,
getRuleForSignalTesting,
getSavedQueryRuleForSignalTesting,
getSignalsByIds,
getThreatMatchRuleForSignalTesting,
getThresholdRuleForSignalTesting,
startSignalsMigration,
finalizeAlertsMigration,
getEqlRuleForAlertTesting,
getRuleForAlertTesting,
getSavedQueryRuleForAlertTesting,
getAlertsByIds,
getThreatMatchRuleForAlertTesting,
getThresholdRuleForAlertTesting,
startAlertsMigration,
waitFor,
waitForRuleSuccess,
waitForSignalsToBePresent,
} from '../../../utils';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
import { removeRandomValuedProperties } from '../../rule_execution_logic/utils';
waitForAlertsToBePresent,
removeRandomValuedProperties,
} from '../../utils';
import { FtrProviderContext } from '../../../../ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
const log = getService('log');
const supertest = getService('supertest');
const es = getService('es');
describe('Alerts Compatibility', function () {
describe('@ess Alerts Compatibility', function () {
describe('CTI', () => {
const expectedDomain = 'elastic.local';
const expectedProvider = 'provider1';
@ -63,7 +62,7 @@ export default ({ getService }: FtrProviderContext) => {
await esArchiver.load(
'x-pack/test/functional/es_archives/security_solution/legacy_cti_signals'
);
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -124,14 +123,14 @@ export default ({ getService }: FtrProviderContext) => {
expect(indices.length).to.eql(1);
expect(indices[0].is_outdated).to.eql(true);
const [migration] = await startSignalsMigration({
const [migration] = await startAlertsMigration({
indices: [indices[0].index],
supertest,
log,
});
await waitFor(
async () => {
const [{ completed }] = await finalizeSignalsMigration({
const [{ completed }] = await finalizeAlertsMigration({
migrationIds: [migration.migration_id],
supertest,
log,
@ -183,26 +182,26 @@ export default ({ getService }: FtrProviderContext) => {
});
it('should generate a signal-on-legacy-signal with legacy index pattern', async () => {
const rule: ThreatMatchRuleCreateProps = getThreatMatchRuleForSignalTesting([
const rule: ThreatMatchRuleCreateProps = getThreatMatchRuleForAlertTesting([
'.siem-signals-*',
]);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
});
it('should generate a signal-on-legacy-signal with AAD index pattern', async () => {
const rule: ThreatMatchRuleCreateProps = getThreatMatchRuleForSignalTesting([
const rule: ThreatMatchRuleCreateProps = getThreatMatchRuleForAlertTesting([
`.alerts-security.alerts-default`,
]);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
@ -212,7 +211,7 @@ export default ({ getService }: FtrProviderContext) => {
describe('Query', () => {
beforeEach(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alerts/7.16.0');
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -224,11 +223,11 @@ export default ({ getService }: FtrProviderContext) => {
});
it('should generate a signal-on-legacy-signal with legacy index pattern', async () => {
const rule: QueryRuleCreateProps = getRuleForSignalTesting([`.siem-signals-*`]);
const rule: QueryRuleCreateProps = getRuleForAlertTesting([`.siem-signals-*`]);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
@ -384,13 +383,13 @@ export default ({ getService }: FtrProviderContext) => {
});
it('should generate a signal-on-legacy-signal with AAD index pattern', async () => {
const rule: QueryRuleCreateProps = getRuleForSignalTesting([
const rule: QueryRuleCreateProps = getRuleForAlertTesting([
`.alerts-security.alerts-default`,
]);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
@ -549,7 +548,7 @@ export default ({ getService }: FtrProviderContext) => {
describe('Saved Query', () => {
beforeEach(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alerts/7.16.0');
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -562,13 +561,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should generate a signal-on-legacy-signal with legacy index pattern', async () => {
const rule: SavedQueryRuleCreateProps = {
...getSavedQueryRuleForSignalTesting([`.siem-signals-*`]),
...getSavedQueryRuleForAlertTesting([`.siem-signals-*`]),
query: 'agent.name: "security-linux-1.example.dev"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
@ -576,13 +575,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should generate a signal-on-legacy-signal with AAD index pattern', async () => {
const rule: SavedQueryRuleCreateProps = {
...getSavedQueryRuleForSignalTesting([`.alerts-security.alerts-default`]),
...getSavedQueryRuleForAlertTesting([`.alerts-security.alerts-default`]),
query: 'agent.name: "security-linux-1.example.dev"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
@ -592,7 +591,7 @@ export default ({ getService }: FtrProviderContext) => {
describe('EQL', () => {
beforeEach(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alerts/7.16.0');
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -605,13 +604,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should generate a signal-on-legacy-signal with legacy index pattern', async () => {
const rule: EqlRuleCreateProps = {
...getEqlRuleForSignalTesting(['.siem-signals-*']),
...getEqlRuleForAlertTesting(['.siem-signals-*']),
query: 'any where agent.name == "security-linux-1.example.dev"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
@ -619,13 +618,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should generate a signal-on-legacy-signal with AAD index pattern', async () => {
const rule: EqlRuleCreateProps = {
...getEqlRuleForSignalTesting([`.alerts-security.alerts-default`]),
...getEqlRuleForAlertTesting([`.alerts-security.alerts-default`]),
query: 'any where agent.name == "security-linux-1.example.dev"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
@ -635,7 +634,7 @@ export default ({ getService }: FtrProviderContext) => {
describe('Threshold', () => {
beforeEach(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alerts/7.16.0');
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -647,7 +646,7 @@ export default ({ getService }: FtrProviderContext) => {
});
it('should generate a signal-on-legacy-signal with legacy index pattern', async () => {
const baseRule: ThresholdRuleCreateProps = getThresholdRuleForSignalTesting([
const baseRule: ThresholdRuleCreateProps = getThresholdRuleForAlertTesting([
'.siem-signals-*',
]);
const rule: ThresholdRuleCreateProps = {
@ -660,15 +659,15 @@ export default ({ getService }: FtrProviderContext) => {
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);
});
it('should generate a signal-on-legacy-signal with AAD index pattern', async () => {
const baseRule: ThresholdRuleCreateProps = getThresholdRuleForSignalTesting([
const baseRule: ThresholdRuleCreateProps = getThresholdRuleForAlertTesting([
`.alerts-security.alerts-default`,
]);
const rule: ThresholdRuleCreateProps = {
@ -681,8 +680,8 @@ export default ({ getService }: FtrProviderContext) => {
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getAlertsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).greaterThan(0);
const hit = signalsOpen.hits.hits[0];
expect(hit._source?.kibana).to.eql(undefined);

View file

@ -7,19 +7,18 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
createRule,
createSignalsIndex,
createAlertsIndex,
deleteAllRules,
deleteAllAlerts,
getRuleForSignalTesting,
getSignalsById,
getRuleForAlertTesting,
getAlertsById,
waitForRuleSuccess,
waitForSignalsToBePresent,
waitForAlertsToBePresent,
} from '../../utils';
import { FtrProviderContext } from '../../../../ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
@ -30,7 +29,7 @@ export default ({ getService }: FtrProviderContext) => {
name: string;
}
describe('Tests involving aliases of source indexes and the signals index', () => {
describe('@ess Tests involving aliases of source indexes and the alerts index', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alias');
});
@ -40,7 +39,7 @@ export default ({ getService }: FtrProviderContext) => {
});
beforeEach(async () => {
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -49,25 +48,25 @@ export default ({ getService }: FtrProviderContext) => {
});
it('should keep the original alias value such as "host_alias" from a source index when the value is indexed', async () => {
const rule = getRuleForSignalTesting(['host_alias']);
const rule = getRuleForAlertTesting(['host_alias']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 4, [id]);
const signalsOpen = await getSignalsById(supertest, log, id);
const hits = signalsOpen.hits.hits
.map((signal) => (signal._source?.host_alias as HostAlias).name)
await waitForAlertsToBePresent(supertest, log, 4, [id]);
const alertsOpen = await getAlertsById(supertest, log, id);
const hits = alertsOpen.hits.hits
.map((alert) => (alert._source?.host_alias as HostAlias).name)
.sort();
expect(hits).to.eql(['host name 1', 'host name 2', 'host name 3', 'host name 4']);
});
it('should copy alias data from a source index into the signals index in the same position when the target is ECS compatible', async () => {
const rule = getRuleForSignalTesting(['host_alias']);
it('should copy alias data from a source index into the alerts index in the same position when the target is ECS compatible', async () => {
const rule = getRuleForAlertTesting(['host_alias']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 4, [id]);
const signalsOpen = await getSignalsById(supertest, log, id);
const hits = signalsOpen.hits.hits
.map((signal) => (signal._source?.host as HostAlias).name)
await waitForAlertsToBePresent(supertest, log, 4, [id]);
const alertsOpen = await getAlertsById(supertest, log, id);
const hits = alertsOpen.hits.hits
.map((alert) => (alert._source?.host as HostAlias).name)
.sort();
expect(hits).to.eql(['host name 1', 'host name 2', 'host name 3', 'host name 4']);
});

View file

@ -7,12 +7,16 @@
import { FtrConfigProviderContext } from '@kbn/test';
// eslint-disable-next-line import/no-default-export
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const functionalConfig = await readConfigFile(require.resolve('../config.base.ts'));
const functionalConfig = await readConfigFile(
require.resolve('../../../../../config/ess/config.base.trial')
);
return {
...functionalConfig.getAll(),
testFiles: [require.resolve('.')],
testFiles: [require.resolve('..')],
junit: {
reportName: 'Detection Engine API Integration Tests - ESS - Alerts',
},
};
}

View file

@ -0,0 +1,15 @@
/*
* 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 { createTestConfig } from '../../../../../config/serverless/config.base';
export default createTestConfig({
testFiles: [require.resolve('..')],
junit: {
reportName: 'Detection Engine API Integration Tests - Serverless - Alerts',
},
});

View file

@ -13,17 +13,17 @@ import {
import { SIGNALS_FIELD_ALIASES_VERSION } from '@kbn/security-solution-plugin/server/lib/detection_engine/routes/index/get_signals_template';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import { deleteAllAlerts } from '../../utils';
// eslint-disable-next-line import/no-default-export
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
const es = getService('es');
const log = getService('log');
describe('create_index', () => {
describe('@ess create_index', () => {
afterEach(async () => {
await deleteAllAlerts(supertest, log, es);
});
@ -39,7 +39,7 @@ export default ({ getService }: FtrProviderContext) => {
});
// This fails and should be investigated or removed if it no longer applies
it.skip('should report that signals index does not exist', async () => {
it.skip('should report that alerts index does not exist', async () => {
const { body } = await supertest.get(DETECTION_ENGINE_INDEX_URL).send().expect(404);
expect(body).to.eql({ message: 'index for this space does not exist', status_code: 404 });
});
@ -54,7 +54,7 @@ export default ({ getService }: FtrProviderContext) => {
});
});
describe('with an outdated signals index', () => {
describe('with an outdated alerts index', () => {
beforeEach(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/endpoint/resolver/signals');
});
@ -63,7 +63,7 @@ export default ({ getService }: FtrProviderContext) => {
await esArchiver.unload('x-pack/test/functional/es_archives/endpoint/resolver/signals');
});
it('should report that signals index is outdated', async () => {
it('should report that alerts index is outdated', async () => {
const { body } = await supertest.get(DETECTION_ENGINE_INDEX_URL).send().expect(200);
expect(body).to.eql({
index_mapping_outdated: true,

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 '../../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('Alerts API', function () {
loadTestFile(require.resolve('./aliases'));
loadTestFile(require.resolve('./create_index'));
loadTestFile(require.resolve('./alerts_compatibility'));
loadTestFile(require.resolve('./migrations'));
loadTestFile(require.resolve('./open_close_alerts'));
loadTestFile(require.resolve('./set_alert_tags'));
});
}

View file

@ -15,15 +15,19 @@ import {
import { ROLES } from '@kbn/security-solution-plugin/common/test';
import { SIGNALS_TEMPLATE_VERSION } from '@kbn/security-solution-plugin/server/lib/detection_engine/routes/index/get_signals_template';
import { Signal } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/types';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
createSignalsIndex,
createAlertsIndex,
deleteMigrations,
deleteAllAlerts,
getIndexNameFromLoad,
waitForIndexToPopulate,
} from '../../utils';
import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution';
} from '../../../utils';
import {
createUserAndRole,
deleteUserAndRole,
} from '../../../../../../common/services/security_solution';
import { FtrProviderContext } from '../../../../../ftr_provider_context';
interface CreateResponse {
index: string;
@ -35,7 +39,6 @@ function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext): void => {
const es = getService('es');
const esArchiver = getService('esArchiver');
@ -58,7 +61,7 @@ export default ({ getService }: FtrProviderContext): void => {
outdatedSignalsIndexName = getIndexNameFromLoad(
await esArchiver.load('x-pack/test/functional/es_archives/signals/outdated_signals_index')
);
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {

View file

@ -13,9 +13,8 @@ import {
DETECTION_ENGINE_SIGNALS_MIGRATION_URL,
} from '@kbn/security-solution-plugin/common/constants';
import { ROLES } from '@kbn/security-solution-plugin/common/test';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import { createSignalsIndex, deleteAllAlerts, getIndexNameFromLoad, waitFor } from '../../utils';
import { createUserAndRole } from '../../../common/services/security_solution';
import { createAlertsIndex, deleteAllAlerts, getIndexNameFromLoad, waitFor } from '../../../utils';
import { createUserAndRole } from '../../../../../../common/services/security_solution';
interface CreateResponse {
index: string;
@ -27,8 +26,8 @@ interface FinalizeResponse extends CreateResponse {
completed?: boolean;
error?: unknown;
}
import { FtrProviderContext } from '../../../../../ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext): void => {
const es = getService('es');
const esArchiver = getService('esArchiver');
@ -36,17 +35,17 @@ export default ({ getService }: FtrProviderContext): void => {
const supertestWithoutAuth = getService('supertestWithoutAuth');
const log = getService('log');
describe('deleting signals migrations', () => {
let outdatedSignalsIndexName: string;
describe('@ess Deleting alerts migrations', () => {
let outdatedAlertsIndexName: string;
let createdMigration: CreateResponse;
let finalizedMigration: FinalizeResponse;
beforeEach(async () => {
outdatedSignalsIndexName = getIndexNameFromLoad(
outdatedAlertsIndexName = getIndexNameFromLoad(
await esArchiver.load('x-pack/test/functional/es_archives/signals/outdated_signals_index')
);
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
({
body: {
@ -55,7 +54,7 @@ export default ({ getService }: FtrProviderContext): void => {
} = await supertest
.post(DETECTION_ENGINE_SIGNALS_MIGRATION_URL)
.set('kbn-xsrf', 'true')
.send({ index: [outdatedSignalsIndexName] })
.send({ index: [outdatedAlertsIndexName] })
.expect(200));
await waitFor(
@ -91,7 +90,7 @@ export default ({ getService }: FtrProviderContext): void => {
const deletedMigration = body.migrations[0];
expect(deletedMigration.id).to.eql(createdMigration.migration_id);
expect(deletedMigration.sourceIndex).to.eql(outdatedSignalsIndexName);
expect(deletedMigration.sourceIndex).to.eql(outdatedAlertsIndexName);
});
it('marks the original index for deletion by applying our cleanup policy', async () => {

View file

@ -13,15 +13,17 @@ import {
DETECTION_ENGINE_SIGNALS_MIGRATION_URL,
} from '@kbn/security-solution-plugin/common/constants';
import { ROLES } from '@kbn/security-solution-plugin/common/test';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
createSignalsIndex,
createAlertsIndex,
deleteMigrations,
deleteAllAlerts,
getIndexNameFromLoad,
waitFor,
} from '../../utils';
import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution';
} from '../../../utils';
import {
createUserAndRole,
deleteUserAndRole,
} from '../../../../../../common/services/security_solution';
interface StatusResponse {
index: string;
@ -39,8 +41,8 @@ interface FinalizeResponse {
completed?: boolean;
error?: unknown;
}
import { FtrProviderContext } from '../../../../../ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext): void => {
const esArchiver = getService('esArchiver');
const kbnClient = getService('kibanaServer');
@ -49,7 +51,7 @@ export default ({ getService }: FtrProviderContext): void => {
const log = getService('log');
const es = getService('es');
const getSignalsMigrationStatus = async (query: any) => {
const getAlertsMigrationStatus = async (query: any) => {
const { body } = await supertest
.get(DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL)
.query(query)
@ -62,28 +64,28 @@ export default ({ getService }: FtrProviderContext): void => {
return filteredIndices;
};
describe('Finalizing signals migrations', () => {
let legacySignalsIndexName: string;
let outdatedSignalsIndexName: string;
describe('@ess Finalizing Alerts migrations', () => {
let legacyAlertsIndexName: string;
let outdatedAlertsIndexName: string;
let createdMigrations: CreateResponse[];
let createdMigration: CreateResponse;
beforeEach(async () => {
createdMigrations = [];
legacySignalsIndexName = getIndexNameFromLoad(
legacyAlertsIndexName = getIndexNameFromLoad(
await esArchiver.load('x-pack/test/functional/es_archives/signals/legacy_signals_index')
);
outdatedSignalsIndexName = getIndexNameFromLoad(
outdatedAlertsIndexName = getIndexNameFromLoad(
await esArchiver.load('x-pack/test/functional/es_archives/signals/outdated_signals_index')
);
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
({
body: { indices: createdMigrations },
} = await supertest
.post(DETECTION_ENGINE_SIGNALS_MIGRATION_URL)
.set('kbn-xsrf', 'true')
.send({ index: [legacySignalsIndexName] })
.send({ index: [legacyAlertsIndexName] })
.expect(200));
[createdMigration] = createdMigrations;
@ -91,7 +93,7 @@ export default ({ getService }: FtrProviderContext): void => {
afterEach(async () => {
// Finalize the migration after each test so that the .siem-signals alias gets added to the migrated index -
// this allows deleteSignalsIndex to find and delete the migrated index
// this allows deleteAlertsIndex to find and delete the migrated index
await supertest
.post(DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL)
.set('kbn-xsrf', 'true')
@ -107,7 +109,7 @@ export default ({ getService }: FtrProviderContext): void => {
});
it('replaces the original index alias with the migrated one', async () => {
const statusResponses: StatusResponse[] = await getSignalsMigrationStatus({
const statusResponses: StatusResponse[] = await getAlertsMigrationStatus({
from: '2020-10-10',
});
const indicesBefore = statusResponses.map((index) => index.index);
@ -160,7 +162,7 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await supertest
.post(DETECTION_ENGINE_SIGNALS_MIGRATION_URL)
.set('kbn-xsrf', 'true')
.send({ index: [outdatedSignalsIndexName] })
.send({ index: [outdatedAlertsIndexName] })
.expect(200);
createdMigrations = [...createdMigrations, ...body.indices];
@ -181,7 +183,7 @@ export default ({ getService }: FtrProviderContext): void => {
log
);
const indices = await getSignalsMigrationStatus({ from: '2020-10-10' });
const indices = await getAlertsMigrationStatus({ from: '2020-10-10' });
expect(indices.map((s: any) => s.index)).to.eql([
...createdMigrations.map((c) => c.migration_index),
]);

View file

@ -9,11 +9,14 @@ import expect from '@kbn/expect';
import { DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL } from '@kbn/security-solution-plugin/common/constants';
import { ROLES } from '@kbn/security-solution-plugin/common/test';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import { createSignalsIndex, deleteAllAlerts, getIndexNameFromLoad } from '../../utils';
import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution';
import { createAlertsIndex, deleteAllAlerts, getIndexNameFromLoad } from '../../../utils';
import {
createUserAndRole,
deleteUserAndRole,
} from '../../../../../../common/services/security_solution';
import { FtrProviderContext } from '../../../../../ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext): void => {
const esArchiver = getService('esArchiver');
const supertest = getService('supertest');
@ -21,7 +24,7 @@ export default ({ getService }: FtrProviderContext): void => {
const log = getService('log');
const es = getService('es');
const getSignalsMigrationStatus = async (query: any) => {
const getAlertsMigrationStatus = async (query: any) => {
const { body } = await supertest
.get(DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL)
.query(query)
@ -34,13 +37,13 @@ export default ({ getService }: FtrProviderContext): void => {
return filteredIndices;
};
describe('Signals migration status', () => {
let legacySignalsIndexName: string;
describe('Alerts migration status', () => {
let legacyAlertsIndexName: string;
beforeEach(async () => {
legacySignalsIndexName = getIndexNameFromLoad(
legacyAlertsIndexName = getIndexNameFromLoad(
await esArchiver.load('x-pack/test/functional/es_archives/signals/legacy_signals_index')
);
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -48,26 +51,26 @@ export default ({ getService }: FtrProviderContext): void => {
await deleteAllAlerts(supertest, log, es);
});
it('returns no indexes if no signals exist in the specified range', async () => {
const indices = await getSignalsMigrationStatus({ from: '2020-10-20' });
it('returns no indexes if no alerts exist in the specified range', async () => {
const indices = await getAlertsMigrationStatus({ from: '2020-10-20' });
expect(indices).to.eql([]);
});
it('includes an index if its signals are within the specified range', async () => {
const indices = await getSignalsMigrationStatus({ from: '2020-10-10' });
it('includes an index if its alerts are within the specified range', async () => {
const indices = await getAlertsMigrationStatus({ from: '2020-10-10' });
expect(indices).length(1);
expect(indices[0].index).to.eql(legacySignalsIndexName);
expect(indices[0].index).to.eql(legacyAlertsIndexName);
});
it("returns the mappings version and a breakdown of signals' version", async () => {
it("returns the mappings version and a breakdown of alerts' version", async () => {
const outdatedIndexName = getIndexNameFromLoad(
await esArchiver.load('x-pack/test/functional/es_archives/signals/outdated_signals_index')
);
const indices = await getSignalsMigrationStatus({ from: '2020-10-10' });
const indices = await getAlertsMigrationStatus({ from: '2020-10-10' });
expect(indices).to.eql([
{
index: legacySignalsIndexName,
index: legacyAlertsIndexName,
is_outdated: true,
migrations: [],
signal_versions: [

View file

@ -0,0 +1,16 @@
/*
* 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 '../../../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('Actions API', function () {
loadTestFile(require.resolve('./create_alerts_migrations'));
loadTestFile(require.resolve('./delete_alerts_migrations'));
loadTestFile(require.resolve('./finalize_alerts_migrations'));
loadTestFile(require.resolve('./finalize_alerts_migrations'));
});
}

View file

@ -15,38 +15,46 @@ import {
} from '@kbn/security-solution-plugin/common/constants';
import { ROLES } from '@kbn/security-solution-plugin/common/test';
import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
createSignalsIndex,
createAlertsIndex,
deleteAllAlerts,
setSignalStatus,
setAlertStatus,
getAlertUpdateByQueryEmptyResponse,
getQuerySignalIds,
getQueryAlertIds,
deleteAllRules,
createRule,
waitForSignalsToBePresent,
getSignalsByIds,
waitForAlertsToBePresent,
getAlertsByIds,
waitForRuleSuccess,
getRuleForSignalTesting,
getRuleForAlertTesting,
} from '../../utils';
import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution';
import {
createUserAndRole,
deleteUserAndRole,
} from '../../../../../common/services/security_solution';
import { FtrProviderContext } from '../../../../ftr_provider_context';
import { EsArchivePathBuilder } from '../../../../es_archive_path_builder';
// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
const supertestWithoutAuth = getService('supertestWithoutAuth');
const log = getService('log');
const es = getService('es');
// TODO: add a new service
const config = getService('config');
const isServerless = config.get('serverless');
const dataPathBuilder = new EsArchivePathBuilder(isServerless);
const path = dataPathBuilder.getPath('auditbeat/hosts');
describe('open_close_signals', () => {
describe('@ess @serverless open_close_alerts', () => {
describe('validation checks', () => {
describe('update by ids', () => {
it('should not give errors when querying and the signals index does not exist yet', async () => {
it('should not give errors when querying and the alerts index does not exist yet', async () => {
const { body } = await supertest
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.send(setSignalStatus({ signalIds: ['123'], status: 'open' }))
.send(setAlertStatus({ alertIds: ['123'], status: 'open' }))
.expect(200);
// remove any server generated items that are nondeterministic
@ -55,12 +63,12 @@ export default ({ getService }: FtrProviderContext) => {
expect(body).to.eql(getAlertUpdateByQueryEmptyResponse());
});
it('should not give errors when querying and the signals index does exist and is empty', async () => {
await createSignalsIndex(supertest, log);
it('should not give errors when querying and the alerts index does exist and is empty', async () => {
await createAlertsIndex(supertest, log);
const { body } = await supertest
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.send(setSignalStatus({ signalIds: ['123'], status: 'open' }))
.send(setAlertStatus({ alertIds: ['123'], status: 'open' }))
.expect(200);
// remove any server generated items that are nondeterministic
@ -73,11 +81,11 @@ export default ({ getService }: FtrProviderContext) => {
});
describe('update by query', () => {
it('should not give errors when querying and the signals index does not exist yet', async () => {
it('should not give errors when querying and the alerts index does not exist yet', async () => {
const { body } = await supertest
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.send(setSignalStatus({ query: { match_all: {} }, status: 'open' }))
.send(setAlertStatus({ query: { match_all: {} }, status: 'open' }))
.expect(200);
// remove any server generated items that are indeterministic
@ -86,12 +94,12 @@ export default ({ getService }: FtrProviderContext) => {
expect(body).to.eql(getAlertUpdateByQueryEmptyResponse());
});
it('should not give errors when querying and the signals index does exist and is empty', async () => {
await createSignalsIndex(supertest, log);
it('should not give errors when querying and the alerts index does exist and is empty', async () => {
await createAlertsIndex(supertest, log);
const { body } = await supertest
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.send(setSignalStatus({ query: { match_all: {} }, status: 'open' }))
.send(setAlertStatus({ query: { match_all: {} }, status: 'open' }))
.expect(200);
// remove any server generated items that are indeterministic
@ -105,16 +113,16 @@ export default ({ getService }: FtrProviderContext) => {
describe('tests with auditbeat data', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts');
await esArchiver.load(path);
});
after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts');
await esArchiver.unload(path);
});
beforeEach(async () => {
await deleteAllRules(supertest, log);
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -122,163 +130,160 @@ export default ({ getService }: FtrProviderContext) => {
await deleteAllRules(supertest, log);
});
it('should be able to execute and get 10 signals', async () => {
it('should be able to execute and get 10 alerts', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
expect(signalsOpen.hits.hits.length).equal(10);
await waitForAlertsToBePresent(supertest, log, 10, [id]);
const alertsOpen = await getAlertsByIds(supertest, log, [id]);
expect(alertsOpen.hits.hits.length).equal(10);
});
it('should be have set the signals in an open state initially', async () => {
it('should be have set the alerts in an open state initially', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const everySignalOpen = signalsOpen.hits.hits.every(
await waitForAlertsToBePresent(supertest, log, 10, [id]);
const alertsOpen = await getAlertsByIds(supertest, log, [id]);
const everyAlertOpen = alertsOpen.hits.hits.every(
(hit) => hit._source?.[ALERT_WORKFLOW_STATUS] === 'open'
);
expect(everySignalOpen).to.eql(true);
expect(everyAlertOpen).to.eql(true);
});
it('should be able to get a count of 10 closed signals when closing 10', async () => {
it('should be able to get a count of 10 closed alerts when closing 10', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const signalIds = signalsOpen.hits.hits.map((signal) => signal._id);
await waitForAlertsToBePresent(supertest, log, 10, [id]);
const alertsOpen = await getAlertsByIds(supertest, log, [id]);
const alertIds = alertsOpen.hits.hits.map((alert) => alert._id);
// set all of the signals to the state of closed. There is no reason to use a waitUntil here
// set all of the alerts to the state of closed. There is no reason to use a waitUntil here
// as this route intentionally has a waitFor within it and should only return when the query has
// the data.
await supertest
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.send(setSignalStatus({ signalIds, status: 'closed' }))
.send(setAlertStatus({ alertIds, status: 'closed' }))
.expect(200);
const { body: signalsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
const { body: alertsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(signalIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
expect(signalsClosed.hits.hits.length).to.equal(10);
expect(alertsClosed.hits.hits.length).to.equal(10);
});
// Test is failing after changing refresh to false
it.skip('should be able close signals immediately and they all should be closed', async () => {
it('should be able close alerts immediately and they all should be closed', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const signalIds = signalsOpen.hits.hits.map((signal) => signal._id);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const alertsOpen = await getAlertsByIds(supertest, log, [id]);
const alertIds = alertsOpen.hits.hits.map((alert) => alert._id);
// set all of the signals to the state of closed. There is no reason to use a waitUntil here
// set all of the alerts to the state of closed. There is no reason to use a waitUntil here
// as this route intentionally has a waitFor within it and should only return when the query has
// the data.
await supertest
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.send(setSignalStatus({ signalIds, status: 'closed' }))
.send(setAlertStatus({ alertIds, status: 'closed' }))
.expect(200);
const { body: signalsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
const { body: alertsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(signalIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
const everySignalClosed = signalsClosed.hits.hits.every(
const everyAlertClosed = alertsClosed.hits.hits.every(
(hit) => hit._source?.['kibana.alert.workflow_status'] === 'closed'
);
expect(everySignalClosed).to.eql(true);
expect(everyAlertClosed).to.eql(true);
});
// This fails and should be investigated or removed if it no longer applies
it.skip('should be able to close signals with t1 analyst user', async () => {
const rule = getRuleForSignalTesting(['auditbeat-*']);
it.skip('should be able to close alerts with t1 analyst user', async () => {
const rule = getRuleForAlertTesting(['auditbeat-*']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
await createUserAndRole(getService, ROLES.t1_analyst);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const signalIds = signalsOpen.hits.hits.map((signal) => signal._id);
const alertsOpen = await getAlertsByIds(supertest, log, [id]);
const alertIds = alertsOpen.hits.hits.map((alert) => alert._id);
// Try to set all of the signals to the state of closed.
// Try to set all of the alerts to the state of closed.
// This should not be possible with the given user.
await supertestWithoutAuth
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.auth(ROLES.t1_analyst, 'changeme')
.send(setSignalStatus({ signalIds, status: 'closed' }))
.send(setAlertStatus({ alertIds, status: 'closed' }))
.expect(200);
// query for the signals with the superuser
// to allow a check that the signals were NOT closed with t1 analyst
const { body: signalsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
// query for the alerts with the superuser
// to allow a check that the alerts were NOT closed with t1 analyst
const { body: alertsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(signalIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
const everySignalClosed = signalsClosed.hits.hits.every(
const everyAlertClosed = alertsClosed.hits.hits.every(
(hit) => hit._source?.['kibana.alert.workflow_status'] === 'closed'
);
expect(everySignalClosed).to.eql(true);
expect(everyAlertClosed).to.eql(true);
await deleteUserAndRole(getService, ROLES.t1_analyst);
});
// This fails and should be investigated or removed if it no longer applies
it.skip('should be able to close signals with soc_manager user', async () => {
const rule = getRuleForSignalTesting(['auditbeat-*']);
it.skip('should be able to close alerts with soc_manager user', async () => {
const rule = getRuleForAlertTesting(['auditbeat-*']);
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 1, [id]);
await waitForAlertsToBePresent(supertest, log, 1, [id]);
const userAndRole = ROLES.soc_manager;
await createUserAndRole(getService, userAndRole);
const signalsOpen = await getSignalsByIds(supertest, log, [id]);
const signalIds = signalsOpen.hits.hits.map((signal) => signal._id);
const alertsOpen = await getAlertsByIds(supertest, log, [id]);
const alertIds = alertsOpen.hits.hits.map((alert) => alert._id);
// Try to set all of the signals to the state of closed.
// Try to set all of the alerts to the state of closed.
// This should not be possible with the given user.
await supertestWithoutAuth
.post(DETECTION_ENGINE_SIGNALS_STATUS_URL)
.set('kbn-xsrf', 'true')
.auth(userAndRole, 'changeme') // each user has the same password
.send(setSignalStatus({ signalIds, status: 'closed' }))
.send(setAlertStatus({ alertIds, status: 'closed' }))
.expect(200);
const { body: signalsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
const { body: alertsClosed }: { body: estypes.SearchResponse<DetectionAlert> } =
await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(signalIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
const everySignalClosed = signalsClosed.hits.hits.every(
const everyAlertClosed = alertsClosed.hits.hits.every(
(hit) => hit._source?.['kibana.alert.workflow_status'] === 'closed'
);
expect(everySignalClosed).to.eql(true);
expect(everyAlertClosed).to.eql(true);
await deleteUserAndRole(getService, userAndRole);
});

View file

@ -13,28 +13,34 @@ import {
DETECTION_ENGINE_ALERT_TAGS_URL,
} from '@kbn/security-solution-plugin/common/constants';
import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
createSignalsIndex,
createAlertsIndex,
deleteAllAlerts,
getQuerySignalIds,
getQueryAlertIds,
deleteAllRules,
createRule,
waitForSignalsToBePresent,
getSignalsByIds,
waitForAlertsToBePresent,
getAlertsByIds,
waitForRuleSuccess,
getRuleForSignalTesting,
getRuleForAlertTesting,
setAlertTags,
} from '../../utils';
import { setAlertTags } from '../../utils/set_alert_tags';
import { FtrProviderContext } from '../../../../ftr_provider_context';
import { EsArchivePathBuilder } from '../../../../es_archive_path_builder';
// 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 es = getService('es');
// TODO: add a new service
const config = getService('config');
const isServerless = config.get('serverless');
const dataPathBuilder = new EsArchivePathBuilder(isServerless);
const path = dataPathBuilder.getPath('auditbeat/hosts');
describe('set_alert_tags', () => {
describe('@ess @serverless set_alert_tags', () => {
describe('validation checks', () => {
it('should give errors when no alert ids are provided', async () => {
const { body } = await supertest
@ -65,19 +71,18 @@ export default ({ getService }: FtrProviderContext) => {
});
});
// Test is failing after changing refresh to false
describe.skip('tests with auditbeat data', () => {
describe('tests with auditbeat data', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts');
await esArchiver.load(path);
});
after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts');
await esArchiver.unload(path);
});
beforeEach(async () => {
await deleteAllRules(supertest, log);
await createSignalsIndex(supertest, log);
await createAlertsIndex(supertest, log);
});
afterEach(async () => {
@ -86,13 +91,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should be able to add tags to multiple alerts', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const alerts = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 10, [id]);
const alerts = await getAlertsByIds(supertest, log, [id]);
const alertIds = alerts.hits.hits.map((alert) => alert._id);
await supertest
@ -110,7 +115,7 @@ export default ({ getService }: FtrProviderContext) => {
const { body }: { body: estypes.SearchResponse<DetectionAlert> } = await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(alertIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
body.hits.hits.map((alert) => {
@ -120,13 +125,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should be able to add tags to alerts that have tags already and not duplicate them', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const alerts = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 10, [id]);
const alerts = await getAlertsByIds(supertest, log, [id]);
const alertIds = alerts.hits.hits.map((alert) => alert._id);
await supertest
@ -156,7 +161,7 @@ export default ({ getService }: FtrProviderContext) => {
const { body }: { body: estypes.SearchResponse<DetectionAlert> } = await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(alertIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
body.hits.hits.map((alert) => {
@ -166,13 +171,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should be able to remove tags', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const alerts = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 10, [id]);
const alerts = await getAlertsByIds(supertest, log, [id]);
const alertIds = alerts.hits.hits.map((alert) => alert._id);
await supertest
@ -202,7 +207,7 @@ export default ({ getService }: FtrProviderContext) => {
const { body }: { body: estypes.SearchResponse<DetectionAlert> } = await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(alertIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
body.hits.hits.map((alert) => {
@ -212,13 +217,13 @@ export default ({ getService }: FtrProviderContext) => {
it('should be able to remove tags that do not exist without breaking', async () => {
const rule = {
...getRuleForSignalTesting(['auditbeat-*']),
...getRuleForAlertTesting(['auditbeat-*']),
query: 'process.executable: "/usr/bin/sudo"',
};
const { id } = await createRule(supertest, log, rule);
await waitForRuleSuccess({ supertest, log, id });
await waitForSignalsToBePresent(supertest, log, 10, [id]);
const alerts = await getSignalsByIds(supertest, log, [id]);
await waitForAlertsToBePresent(supertest, log, 10, [id]);
const alerts = await getAlertsByIds(supertest, log, [id]);
const alertIds = alerts.hits.hits.map((alert) => alert._id);
await supertest
@ -236,7 +241,7 @@ export default ({ getService }: FtrProviderContext) => {
const { body }: { body: estypes.SearchResponse<DetectionAlert> } = await supertest
.post(DETECTION_ENGINE_QUERY_SIGNALS_URL)
.set('kbn-xsrf', 'true')
.send(getQuerySignalIds(alertIds))
.send(getQueryAlertIds(alertIds))
.expect(200);
body.hits.hits.map((alert) => {

View file

@ -0,0 +1,16 @@
/*
* 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 type { SignalIds as AlertIds } from '@kbn/security-solution-plugin/common/api/detection_engine';
export const getQueryAlertIds = (alertIds: AlertIds) => ({
query: {
terms: {
_id: alertIds,
},
},
});

View file

@ -5,7 +5,6 @@
* 2.0.
*/
// TODO rename signal to alert
export * from './create_alerts_index';
export * from './delete_all_alerts';
export * from './wait_for_alert_to_complete';
@ -15,3 +14,9 @@ export * from './get_open_alerts';
export * from './get_alerts_by_ids';
export * from './get_query_alerts_ids';
export * from './get_alerts_by_id';
export * from './remove_random_valued_properties';
export * from './set_alert_status';
export * from './get_alert_status_empty_response';
export * from './get_query_alert_ids';
export * from './set_alert_tags';
export * from './migrations';

View file

@ -0,0 +1,44 @@
/*
* 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 type { ToolingLog } from '@kbn/tooling-log';
import type SuperTest from 'supertest';
import { DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL } from '@kbn/security-solution-plugin/common/constants';
interface FinalizeMigrationResponse {
id: string;
completed?: boolean;
error?: unknown;
}
export const finalizeAlertsMigration = async ({
migrationIds,
supertest,
log,
}: {
supertest: SuperTest.SuperTest<SuperTest.Test>;
log: ToolingLog;
migrationIds: string[];
}): Promise<FinalizeMigrationResponse[]> => {
const response = await supertest
.post(DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL)
.set('kbn-xsrf', 'true')
.send({ migration_ids: migrationIds });
const {
body: { migrations },
}: { body: { migrations: FinalizeMigrationResponse[] } } = response;
if (response.status !== 200) {
log.error(
`Did not get an expected 200 "ok" when finalizing alerts migration (finalizeAlertsMigration). CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify(
response.body
)}, status: ${JSON.stringify(response.status)}`
);
}
return migrations;
};

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export * from './finalize_alerts_migration';
export * from './start_alerts_migration';
export * from './delete_migrations';

View file

@ -0,0 +1,44 @@
/*
* 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 type { ToolingLog } from '@kbn/tooling-log';
import type SuperTest from 'supertest';
import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '@kbn/security-solution-plugin/common/constants';
interface CreateMigrationResponse {
index: string;
migration_index: string;
migration_id: string;
}
export const startAlertsMigration = async ({
indices,
supertest,
log,
}: {
supertest: SuperTest.SuperTest<SuperTest.Test>;
log: ToolingLog;
indices: string[];
}): Promise<CreateMigrationResponse[]> => {
const response = await supertest
.post(DETECTION_ENGINE_SIGNALS_MIGRATION_URL)
.set('kbn-xsrf', 'true')
.send({ index: indices });
const {
body: { indices: created },
}: { body: { indices: CreateMigrationResponse[] } } = response;
if (response.status !== 200) {
log.error(
`Did not get an expected 200 "ok" when starting a alerts migration (startAlertsMigration). CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify(
response.body
)}, status: ${JSON.stringify(response.status)}`
);
}
return created;
};

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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine';
import { ALERT_LAST_DETECTED, ALERT_START } from '@kbn/rule-data-utils';
export const removeRandomValuedProperties = (alert: DetectionAlert | undefined) => {
if (!alert) {
return undefined;
}
const {
'kibana.version': version,
'kibana.alert.rule.execution.uuid': execUuid,
'kibana.alert.rule.uuid': uuid,
'@timestamp': timestamp,
'kibana.alert.rule.created_at': createdAt,
'kibana.alert.rule.updated_at': updatedAt,
'kibana.alert.uuid': alertUuid,
[ALERT_START]: alertStart,
[ALERT_LAST_DETECTED]: lastDetected,
...restOfAlert
} = alert;
return restOfAlert;
};

View file

@ -0,0 +1,25 @@
/*
* 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 type {
Status,
SignalIds as AlertIds,
} from '@kbn/security-solution-plugin/common/api/detection_engine';
export const setAlertStatus = ({
alertIds,
query,
status,
}: {
alertIds?: AlertIds;
query?: object;
status: Status;
}) => ({
signal_ids: alertIds,
query,
status,
});

View file

@ -8,11 +8,14 @@ export * from './rules';
export * from './exception_list_and_item';
export * from './alerts';
export * from './actions';
export * from './get_rule_so_by_id';
export * from './create_rule_saved_object';
export * from './get_rule_with_legacy_investigation_fields';
export * from './rules/get_rule_so_by_id';
export * from './rules/create_rule_saved_object';
export * from './rules/get_rule_with_legacy_investigation_fields';
export * from './get_index_name_from_load';
export * from './count_down_test';
export * from './count_down_es';
export * from './update_username';
export * from './refresh_index';
export * from './wait_for';
export * from './wait_for_index_to_populate';

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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { SavedQueryRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine';
import { getRuleForAlertTesting } from './get_rule_for_alert_testing';
/**
* This is a typical alert testing rule that is easy for most basic testing of output of Saved Query alerts.
* It starts out in an enabled true state. The 'from' is set very far back to test the basics of alert
* creation for SavedQuery and testing by getting all the alerts at once.
* @param ruleId The optional ruleId which is threshold-rule by default.
* @param enabled Enables the rule on creation or not. Defaulted to true.
*/
export const getSavedQueryRuleForAlertTesting = (
index: string[],
ruleId = 'saved-query-rule',
enabled = true
): SavedQueryRuleCreateProps => ({
...getRuleForAlertTesting(index, ruleId, enabled),
type: 'saved_query',
saved_id: 'abcd',
});

View file

@ -0,0 +1,41 @@
/*
* 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 type { ThreatMatchRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine';
import { getRuleForAlertTesting } from './get_rule_for_alert_testing';
/**
* This is a typical alert testing rule that is easy for most basic testing of output of Threat Match alerts.
* It starts out in an enabled true state. The 'from' is set very far back to test the basics of alert
* creation for Threat Match and testing by getting all the alerts at once.
* @param ruleId The optional ruleId which is threshold-rule by default.
* @param enabled Enables the rule on creation or not. Defaulted to true.
*/
export const getThreatMatchRuleForAlertTesting = (
index: string[],
ruleId = 'threat-match-rule',
enabled = true
): ThreatMatchRuleCreateProps => ({
...getRuleForAlertTesting(index, ruleId, enabled),
type: 'threat_match',
language: 'kuery',
query: '*:*',
threat_query: '*:*',
threat_mapping: [
// We match host.name against host.name
{
entries: [
{
field: 'host.name',
value: 'host.name',
type: 'mapping',
},
],
},
],
threat_index: index, // match against same index for simplicity
});

View file

@ -32,5 +32,10 @@ export * from './get_rule_with_web_hook_action';
export * from './get_simple_rule_output_with_web_hook_action';
export * from './rule_to_update_schema';
export * from './update_rule';
export * from './get_threat_match_rule_for_alert_testing';
export * from './get_saved_query_rule_for_alert_testing';
export * from './get_rule_so_by_id';
export * from './create_rule_saved_object';
export * from './get_rule_with_legacy_investigation_fields';
export * from './prebuilt_rules';

View file

@ -7,7 +7,7 @@
import type { ToolingLog } from '@kbn/tooling-log';
import type { Client } from '@elastic/elasticsearch';
import { waitFor } from './wait_for';
import { waitFor } from '../../../../detection_engine_api_integration/utils/wait_for';
/**
* Waits for the given index to contain documents

View file

@ -29,6 +29,7 @@
"@kbn/securitysolution-list-constants",
"@kbn/core-saved-objects-server",
"@kbn/core",
"@kbn/alerting-plugin"
"@kbn/alerting-plugin",
"@kbn/securitysolution-ecs"
]
}

View file

@ -106,7 +106,6 @@
"@kbn/journeys",
"@kbn/stdio-dev-helpers",
"@kbn/alerting-api-integration-helpers",
"@kbn/securitysolution-ecs",
"@kbn/cloud-security-posture-plugin",
"@kbn/cloud-integration-saml-provider-plugin",
"@kbn/security-api-integration-helpers",