[8.18] [Security Solution] Adds prebuilt rule customization integration tests (#207016) (#212314)

# Backport

This will backport the following commits from `main` to `8.18`:
- [[Security Solution] Adds prebuilt rule customization integration
tests (#207016)](https://github.com/elastic/kibana/pull/207016)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Davis
Plumlee","email":"56367316+dplumlee@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-02-24T14:35:17Z","message":"[Security
Solution] Adds prebuilt rule customization integration tests
(#207016)\n\n## Summary\n\nAdds tests in accordance
to\nhttps://github.com/elastic/kibana/pull/204888\n\nAdds integration
tests for the prebuilt rule customization features\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] 🟢 ESS
x100:\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7919\n-
[x] 🟡 Serverless
x100:\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7920\n-
[x] 🟡 Serverless
x100\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7927\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"a51e96eae2904aa3488af1037d87d83beec2cd0d","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["test","release_note:skip","v9.0.0","Team:Detections
and Resp","Team: SecuritySolution","Team:Detection Rule
Management","Feature:Prebuilt Detection
Rules","backport:version","v8.18.0","v9.1.0","v8.19.0"],"title":"[Security
Solution] Adds prebuilt rule customization integration
tests","number":207016,"url":"https://github.com/elastic/kibana/pull/207016","mergeCommit":{"message":"[Security
Solution] Adds prebuilt rule customization integration tests
(#207016)\n\n## Summary\n\nAdds tests in accordance
to\nhttps://github.com/elastic/kibana/pull/204888\n\nAdds integration
tests for the prebuilt rule customization features\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] 🟢 ESS
x100:\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7919\n-
[x] 🟡 Serverless
x100:\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7920\n-
[x] 🟡 Serverless
x100\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7927\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"a51e96eae2904aa3488af1037d87d83beec2cd0d"}},"sourceBranch":"main","suggestedTargetBranches":["8.18","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/212253","number":212253,"state":"MERGED","mergeCommit":{"sha":"c8beef4b9608465b14a097d8ab5fecb8fffbff5b","message":"[9.0]
[Security Solution] Adds prebuilt rule customization integration tests
(#207016) (#212253)\n\n# Backport\n\nThis will backport the following
commits from `main` to `9.0`:\n- [[Security Solution] Adds prebuilt rule
customization integration\ntests
(#207016)](https://github.com/elastic/kibana/pull/207016)\n\n\n\n###
Questions ?\nPlease refer to the [Backport
tool\ndocumentation](https://github.com/sorenlouv/backport)\n\n\n\nCo-authored-by:
Davis Plumlee
<56367316+dplumlee@users.noreply.github.com>"}},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/207016","number":207016,"mergeCommit":{"message":"[Security
Solution] Adds prebuilt rule customization integration tests
(#207016)\n\n## Summary\n\nAdds tests in accordance
to\nhttps://github.com/elastic/kibana/pull/204888\n\nAdds integration
tests for the prebuilt rule customization features\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] 🟢 ESS
x100:\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7919\n-
[x] 🟡 Serverless
x100:\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7920\n-
[x] 🟡 Serverless
x100\nhttps://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7927\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"a51e96eae2904aa3488af1037d87d83beec2cd0d"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Davis Plumlee 2025-02-25 04:43:26 -05:00 committed by GitHub
parent 2f193a9859
commit b1da764d7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 925 additions and 0 deletions

View file

@ -12,6 +12,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
loadTestFile(require.resolve('./is_customized_calculation'));
loadTestFile(require.resolve('./import_rules'));
loadTestFile(require.resolve('./rules_export'));
loadTestFile(require.resolve('./rule_customization'));
loadTestFile(require.resolve('./preview_prebuilt_rules_upgrade'));
loadTestFile(require.resolve('./upgrade_prebuilt_rules'));
});

View file

@ -0,0 +1,924 @@
/*
* 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 'expect';
import {
getPrebuiltRuleMock,
getPrebuiltRuleMockOfType,
} from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/mocks';
import { deleteAllRules } from '../../../../../../../common/utils/security_solution';
import { FtrProviderContext } from '../../../../../../ftr_provider_context';
import {
createPrebuiltRuleAssetSavedObjects,
createRuleAssetSavedObject,
deleteAllPrebuiltRuleAssets,
getWebHookAction,
installPrebuiltRules,
} from '../../../../utils';
export default ({ getService }: FtrProviderContext): void => {
const es = getService('es');
const supertest = getService('supertest');
const securitySolutionApi = getService('securitySolutionApi');
const log = getService('log');
const ruleAsset = createRuleAssetSavedObject({
rule_id: 'rule_1',
});
describe('@ess @serverless @skipInServerlessMKI rule customization', () => {
before(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
describe('detecting rule customizations', () => {
describe('common rule fields', () => {
beforeEach(async () => {
await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('name field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', name: 'some other name' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('description field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', description: 'some other description' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('interval field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', interval: '30m' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('from field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', from: 'now-10m' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('to field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', to: 'now-1m' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('note field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', note: '# some note markdown' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('severity field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', severity: 'medium' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('tags field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', tags: ['red fish', 'blue fish'] } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('severity_mapping field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
severity_mapping: [
{
field: 'event.severity',
operator: 'equals',
severity: 'low',
value: 'LOW',
},
],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('risk_score field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', risk_score: 72 } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('risk_score_mapping field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
risk_score_mapping: [{ field: 'event.risk_score', operator: 'equals', value: '' }],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('references field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', references: ['http://test.test'] } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('false_positives field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', false_positives: ['false positive example'] } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('threat field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
threat: [
{
framework: 'MITRE ATT&CK',
tactic: {
id: 'TA0000',
name: 'test tactic',
reference: 'https://attack.mitre.org/tactics/TA0000/',
},
},
],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('setup field', async () => {
const { body } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', setup: '# some setup markdown' } })
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('related_integrations field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
related_integrations: [{ package: 'package-a', version: '^1.2.3' }],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('required_fields field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
required_fields: [{ name: '@timestamp', type: 'date' }],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('max_signals field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
max_signals: 42,
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('investigation_fields field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', investigation_fields: { field_names: ['blob', 'boop'] } },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('rule_name_override field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', rule_name_override: 'override string' },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('timestamp_override field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', timestamp_override: 'event.ingested' },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('timeline_template fields', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', timeline_id: '123', timeline_title: 'timeline title' },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('building_block_type field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', building_block_type: 'building block string' },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
});
describe('query rule fields', () => {
beforeEach(async () => {
await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('query field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', query: 'event.action: *' },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('language field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', language: 'lucene' },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('filters field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
filters: [
{
meta: {
negate: false,
disabled: false,
type: 'phrase',
key: 'test',
params: {
query: 'value',
},
},
query: {
term: {
field: 'value',
},
},
},
],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('index field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', index: ['new-index-pattern-*'] },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('data_view_id field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: { rule_id: 'rule_1', data_view_id: 'new-data-view', index: undefined },
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('alert_suppression field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
alert_suppression: {
group_by: ['host.name'],
duration: { value: 5, unit: 'm' },
missing_fields_strategy: 'suppress',
},
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
});
describe('eql rule type fields', () => {
beforeEach(async () => {
const eqlRuleAsset = createRuleAssetSavedObject({
...getPrebuiltRuleMockOfType('eql'),
rule_id: 'rule_1',
});
await createPrebuiltRuleAssetSavedObjects(es, [eqlRuleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('event_category_override field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
event_category_override: 'host.name',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('timestamp_field field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
timestamp_field: 'event.ingested',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('tiebreaker_field field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
tiebreaker_field: 'event.ingested',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
});
describe('threat match rule type fields', () => {
beforeEach(async () => {
const threatMatchRuleAsset = createRuleAssetSavedObject({
...getPrebuiltRuleMockOfType('threat_match'),
rule_id: 'rule_1',
});
await createPrebuiltRuleAssetSavedObjects(es, [threatMatchRuleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('threat_index field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'threat_match',
threat_index: ['blue fish', 'red fish'],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('threat_mapping field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'threat_match',
threat_mapping: [
{
entries: [
{
field: 'Endpoint.capabilities',
type: 'mapping',
value: 'Target.dll.pe.description',
},
],
},
],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('threat_indicator_path field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'threat_match',
threat_indicator_path: 'C:over/there.exe',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('threat_query field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'threat_match',
threat_query: 'event.action: *',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('threat_language field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'threat_match',
threat_language: 'lucene',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('threat_filters field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'threat_match',
threat_filters: [
{
meta: {
negate: false,
disabled: false,
type: 'phrase',
key: 'test',
params: {
query: 'value',
},
},
query: {
term: {
field: 'value',
},
},
},
],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
});
describe('threshold rule type fields', () => {
beforeEach(async () => {
const thresholdRuleAsset = createRuleAssetSavedObject({
...getPrebuiltRuleMockOfType('threshold'),
rule_id: 'rule_1',
});
await createPrebuiltRuleAssetSavedObjects(es, [thresholdRuleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('threshold field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'threshold',
threshold: {
field: ['Responses.process.pid'],
value: 100,
cardinality: [{ field: 'host.id', value: 2 }],
},
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
});
describe('machine learning rule type fields', () => {
beforeEach(async () => {
const machineLearningRuleAsset = createRuleAssetSavedObject({
...getPrebuiltRuleMockOfType('machine_learning'),
rule_id: 'rule_1',
});
await createPrebuiltRuleAssetSavedObjects(es, [machineLearningRuleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('machine_learning_job_id field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'machine_learning',
machine_learning_job_id: '123',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('anomaly_threshold field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'machine_learning',
anomaly_threshold: 20,
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
});
describe('new terms rule type fields', () => {
beforeEach(async () => {
const newTermsRuleAsset = createRuleAssetSavedObject({
...getPrebuiltRuleMockOfType('new_terms'),
rule_id: 'rule_1',
});
await createPrebuiltRuleAssetSavedObjects(es, [newTermsRuleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('new_terms_fields field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'new_terms',
new_terms_fields: ['event.action'],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
it('history_window_start field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
type: 'new_terms',
history_window_start: 'now-7d',
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(true);
expect(body.rule_source.type).toEqual('external');
});
});
});
describe('is_customized calculation is not affected by', () => {
beforeEach(async () => {
await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('actions field', async () => {
// create connector/action
const createConnector = async (payload: Record<string, unknown>) =>
(
await supertest
.post('/api/actions/action')
.set('kbn-xsrf', 'true')
.send(payload)
.expect(200)
).body;
const createWebHookConnector = () => createConnector(getWebHookAction());
const webHookAction = await createWebHookConnector();
const defaultRuleAction = {
id: webHookAction.id,
action_type_id: '.webhook' as const,
group: 'default' as const,
params: {
body: '{"test":"a default action"}',
},
frequency: {
notifyWhen: 'onThrottleInterval' as const,
summary: true,
throttle: '1h' as const,
},
uuid: 'd487ec3d-05f2-44ad-8a68-11c97dc92202',
};
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
actions: [defaultRuleAction],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(false);
expect(body.rule_source.type).toEqual('external');
});
it('exceptions_list field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
exceptions_list: [
{
id: 'some_uuid',
list_id: 'list_id_single',
namespace_type: 'single',
type: 'detection',
},
],
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(false);
expect(body.rule_source.type).toEqual('external');
});
it('enabled field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
enabled: true,
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(false);
expect(body.rule_source.type).toEqual('external');
});
it('meta field', async () => {
const { body } = await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
meta: {
severity_override_field: 'field',
},
},
})
.expect(200);
expect(body.rule_source.is_customized).toEqual(false);
expect(body.rule_source.type).toEqual('external');
});
});
describe('cannot change non-customizable rule fields', () => {
beforeEach(async () => {
await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('id field', async () => {
await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
id: 'new-id',
},
})
.expect(400);
});
it('author field', async () => {
await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
author: ['new author'],
},
})
.expect(400);
});
it('license field', async () => {
await securitySolutionApi
.patchRule({
body: {
rule_id: 'rule_1',
license: 'custom-license',
},
})
.expect(400);
});
});
describe('user can revert a customized prebuilt rule to its non-customized state', () => {
beforeEach(async () => {
await createPrebuiltRuleAssetSavedObjects(es, [ruleAsset]);
await installPrebuiltRules(es, supertest);
});
afterEach(async () => {
await deleteAllRules(supertest, log);
await deleteAllPrebuiltRuleAssets(es, log);
});
it('using name field', async () => {
// Modify the prebuilt rule
const { body: customizedRuleBody } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', name: 'new name' } })
.expect(200);
expect(customizedRuleBody.rule_source.is_customized).toEqual(true);
expect(customizedRuleBody.rule_source.type).toEqual('external');
// Change the name field back to the original value
const { body: nonCustomizedRuleBody } = await securitySolutionApi
.patchRule({ body: { rule_id: 'rule_1', name: getPrebuiltRuleMock().name } })
.expect(200);
expect(nonCustomizedRuleBody.rule_source.is_customized).toEqual(false);
expect(nonCustomizedRuleBody.rule_source.type).toEqual('external');
});
});
});
};