diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json index 357b8cde8ad104..6c9b4e2cba49c6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json @@ -26,8 +26,7 @@ "siem": ["all"], "actions": ["read"], "builtInAlerts": ["all"], - "dev_tools": ["all"], - "savedObjectsManagement": ["all"] + "dev_tools": ["all"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/README.md b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/README.md index f0060fb006e325..1344c5bbb0891c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/README.md +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/README.md @@ -2,7 +2,6 @@ This user can CRUD rules and signals. The main difference here is the user has ```json "builtInAlerts": ["all"], -"savedObjectsManagement": ["all"] ``` privileges whereas the T1 and T2 have "read" privileges which prevents them from creating rules diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json index f5482643fb2683..119fe5421c86c5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json @@ -30,8 +30,7 @@ "ml": ["read"], "siem": ["all"], "actions": ["read"], - "builtInAlerts": ["all"], - "savedObjectsManagement": ["all"] + "builtInAlerts": ["all"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json index 75001292242c3e..17dbd90d179253 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json @@ -30,8 +30,7 @@ "ml": ["all"], "siem": ["all"], "actions": ["all"], - "builtInAlerts": ["all"], - "savedObjectsManagement": ["all"] + "builtInAlerts": ["all"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json index de2aa18386188b..289aeca24d45eb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json @@ -24,8 +24,7 @@ "ml": ["read"], "siem": ["read"], "actions": ["read"], - "builtInAlerts": ["read"], - "savedObjectsManagement": ["read"] + "builtInAlerts": ["read"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json index da69643f3c2d3e..0db8359c577640 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json @@ -28,8 +28,7 @@ "ml": ["read"], "siem": ["all"], "actions": ["read"], - "builtInAlerts": ["all"], - "savedObjectsManagement": ["all"] + "builtInAlerts": ["all"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json index a6cb64ef83ba73..6962701ae5be35 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json @@ -28,8 +28,7 @@ "ml": ["read"], "siem": ["all"], "actions": ["all"], - "builtInAlerts": ["all"], - "savedObjectsManagement": ["all"] + "builtInAlerts": ["all"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json index 10b0ffc9d98907..07827069dbc739 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json @@ -21,10 +21,9 @@ { "feature": { "ml": ["read"], - "siem": ["all"], + "siem": ["read"], "actions": ["read"], - "builtInAlerts": ["read"], - "savedObjectsManagement": ["read"] + "builtInAlerts": ["read"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json index 58a069e03985ce..f554c916c6684d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json @@ -23,10 +23,9 @@ { "feature": { "ml": ["read"], - "siem": ["all"], + "siem": ["read"], "actions": ["read"], - "builtInAlerts": ["read"], - "savedObjectsManagement": ["read"] + "builtInAlerts": ["read"] }, "spaces": ["*"] } diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 6e03d81a7d3561..164ccfd7389194 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -219,6 +219,8 @@ export class Plugin implements IPlugin; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts index 1ae6aa80b219f4..e8beef3e58a431 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts @@ -14,7 +14,10 @@ import { deleteAllExceptions } from '../../../lists_api_integration/utils'; import { RulesSchema } from '../../../../plugins/security_solution/common/detection_engine/schemas/response'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { CreateExceptionListItemSchema } from '../../../../plugins/lists/common'; -import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; +import { + EXCEPTION_LIST_ITEM_URL, + EXCEPTION_LIST_URL, +} from '../../../../plugins/lists/common/constants'; import { DETECTION_ENGINE_RULES_URL } from '../../../../plugins/security_solution/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; @@ -37,10 +40,13 @@ import { findImmutableRuleById, getPrePackagedRulesStatus, } from '../../utils'; +import { ROLES } from '../../../../plugins/security_solution/common/test'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const esArchiver = getService('esArchiver'); const es = getService('es'); @@ -58,129 +64,19 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.unload('auditbeat/hosts'); }); - it('should create a single rule with a rule_id and add an exception list to the rule', async () => { - const { - body: { id, list_id, namespace_type, type }, - } = await supertest - .post(EXCEPTION_LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateExceptionListMinimalSchemaMock()) - .expect(200); - - const ruleWithException: CreateRulesSchema = { - ...getSimpleRule(), - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }; - - const rule = await createRule(supertest, ruleWithException); - const expected: Partial = { - ...getSimpleRuleOutput(), - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }; - const bodyToCompare = removeServerGeneratedProperties(rule); - expect(bodyToCompare).to.eql(expected); - }); - - it('should create a single rule with an exception list and validate it ran successfully', async () => { - const { - body: { id, list_id, namespace_type, type }, - } = await supertest - .post(EXCEPTION_LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateExceptionListMinimalSchemaMock()) - .expect(200); - - const ruleWithException: CreateRulesSchema = { - ...getSimpleRule(), - enabled: true, - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }; - - const rule = await createRule(supertest, ruleWithException); - await waitForRuleSuccessOrStatus(supertest, rule.id); - const bodyToCompare = removeServerGeneratedProperties(rule); + describe('elastic admin', () => { + it('should create a single rule with a rule_id and add an exception list to the rule', async () => { + const { + body: { id, list_id, namespace_type, type }, + } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); - const expected: Partial = { - ...getSimpleRuleOutput(), - enabled: true, - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }; - expect(bodyToCompare).to.eql(expected); - }); - - it('should allow removing an exception list from an immutable rule through patch', async () => { - await installPrePackagedRules(supertest); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to use - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one exceptions_list - - // remove the exceptions list as a user is allowed to remove it from an immutable rule - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', exceptions_list: [] }) - .expect(200); - - const immutableRuleSecondTime = await getRule( - supertest, - '9a1a2dae-0b5f-4c3d-8305-a268d404c306' - ); - expect(immutableRuleSecondTime.exceptions_list.length).to.eql(0); - }); - - it('should allow adding a second exception list to an immutable rule through patch', async () => { - await installPrePackagedRules(supertest); - - const { id, list_id, namespace_type, type } = await createExceptionList( - supertest, - getCreateExceptionListMinimalSchemaMock() - ); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to use - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one - - // add a second exceptions list as a user is allowed to add a second list to an immutable rule - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ - rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + const ruleWithException: CreateRulesSchema = { + ...getSimpleRule(), exceptions_list: [ - ...immutableRule.exceptions_list, { id, list_id, @@ -188,64 +84,11 @@ export default ({ getService }: FtrProviderContext) => { type, }, ], - }) - .expect(200); - - const immutableRuleSecondTime = await getRule( - supertest, - '9a1a2dae-0b5f-4c3d-8305-a268d404c306' - ); - - expect(immutableRuleSecondTime.exceptions_list.length).to.eql(2); - }); - - it('should override any updates to pre-packaged rules if the user removes the exception list through the API but the new version of a rule has an exception list again', async () => { - await installPrePackagedRules(supertest); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to use - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one - - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', exceptions_list: [] }) - .expect(200); - - await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - await installPrePackagedRules(supertest); - const immutableRuleSecondTime = await getRule( - supertest, - '9a1a2dae-0b5f-4c3d-8305-a268d404c306' - ); - - // We should have a length of 1 and it should be the same as our original before we tried to remove it using patch - expect(immutableRuleSecondTime.exceptions_list.length).to.eql(1); - expect(immutableRuleSecondTime.exceptions_list).to.eql(immutableRule.exceptions_list); - }); + }; - it('should merge back an exceptions_list if it was removed from the immutable rule through PATCH', async () => { - await installPrePackagedRules(supertest); - - const { id, list_id, namespace_type, type } = await createExceptionList( - supertest, - getCreateExceptionListMinimalSchemaMock() - ); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one - - // remove the exception list and only have a single list that is not an endpoint_list - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ - rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + const rule = await createRule(supertest, ruleWithException); + const expected: Partial = { + ...getSimpleRuleOutput(), exceptions_list: [ { id, @@ -254,70 +97,24 @@ export default ({ getService }: FtrProviderContext) => { type, }, ], - }) - .expect(200); - - await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - await installPrePackagedRules(supertest); - const immutableRuleSecondTime = await getRule( - supertest, - '9a1a2dae-0b5f-4c3d-8305-a268d404c306' - ); - - expect(immutableRuleSecondTime.exceptions_list).to.eql([ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ]); - }); - - it('should NOT add an extra exceptions_list that already exists on a rule during an upgrade', async () => { - await installPrePackagedRules(supertest); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one - - await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - await installPrePackagedRules(supertest); - - const immutableRuleSecondTime = await getRule( - supertest, - '9a1a2dae-0b5f-4c3d-8305-a268d404c306' - ); + }; + const bodyToCompare = removeServerGeneratedProperties(rule); + expect(bodyToCompare).to.eql(expected); + }); - // The installed rule should have both the original immutable exceptions list back and the - // new list the user added. - expect(immutableRuleSecondTime.exceptions_list).to.eql([...immutableRule.exceptions_list]); - }); + it('should create a single rule with an exception list and validate it ran successfully', async () => { + const { + body: { id, list_id, namespace_type, type }, + } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); - it('should NOT allow updates to pre-packaged rules to overwrite existing exception based rules when the user adds an additional exception list', async () => { - await installPrePackagedRules(supertest); - - const { id, list_id, namespace_type, type } = await createExceptionList( - supertest, - getCreateExceptionListMinimalSchemaMock() - ); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - - // add a second exceptions list as a user is allowed to add a second list to an immutable rule - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ - rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + const ruleWithException: CreateRulesSchema = { + ...getSimpleRule(), + enabled: true, exceptions_list: [ - ...immutableRule.exceptions_list, { id, list_id, @@ -325,99 +122,16 @@ export default ({ getService }: FtrProviderContext) => { type, }, ], - }) - .expect(200); - - await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - await installPrePackagedRules(supertest); - const immutableRuleSecondTime = await getRule( - supertest, - '9a1a2dae-0b5f-4c3d-8305-a268d404c306' - ); - - // It should be the same as what the user added originally - expect(immutableRuleSecondTime.exceptions_list).to.eql([ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ]); - }); + }; - it('should not remove any exceptions added to a pre-packaged/immutable rule during an update if that rule has no existing exception lists', async () => { - await installPrePackagedRules(supertest); - - // Create a new exception list - const { id, list_id, namespace_type, type } = await createExceptionList( - supertest, - getCreateExceptionListMinimalSchemaMock() - ); - - // Rule id of "eb079c62-4481-4d6e-9643-3ca499df7aaa" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/external_alerts.json - // since this rule does not have existing exceptions_list that we are going to use for tests - const immutableRule = await getRule(supertest, 'eb079c62-4481-4d6e-9643-3ca499df7aaa'); - expect(immutableRule.exceptions_list.length).eql(0); // make sure we have no exceptions_list - - // add a second exceptions list as a user is allowed to add a second list to an immutable rule - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ - rule_id: 'eb079c62-4481-4d6e-9643-3ca499df7aaa', - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await downgradeImmutableRule(es, 'eb079c62-4481-4d6e-9643-3ca499df7aaa'); - await installPrePackagedRules(supertest); - const immutableRuleSecondTime = await getRule( - supertest, - 'eb079c62-4481-4d6e-9643-3ca499df7aaa' - ); - - expect(immutableRuleSecondTime.exceptions_list).to.eql([ - { - id, - list_id, - namespace_type, - type, - }, - ]); - }); + const rule = await createRule(supertest, ruleWithException); + await waitForRuleSuccessOrStatus(supertest, rule.id); + const bodyToCompare = removeServerGeneratedProperties(rule); - it('should not change the immutable tags when adding a second exception list to an immutable rule through patch', async () => { - await installPrePackagedRules(supertest); - - const { id, list_id, namespace_type, type } = await createExceptionList( - supertest, - getCreateExceptionListMinimalSchemaMock() - ); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to use - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one - - // add a second exceptions list as a user is allowed to add a second list to an immutable rule - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ - rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + const expected: Partial = { + ...getSimpleRuleOutput(), + enabled: true, exceptions_list: [ - ...immutableRule.exceptions_list, { id, list_id, @@ -425,52 +139,381 @@ export default ({ getService }: FtrProviderContext) => { type, }, ], - }) - .expect(200); + }; + expect(bodyToCompare).to.eql(expected); + }); + + it('should allow removing an exception list from an immutable rule through patch', async () => { + await installPrePackagedRules(supertest); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to use + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one exceptions_list + + // remove the exceptions list as a user is allowed to remove it from an immutable rule + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', exceptions_list: [] }) + .expect(200); + + const immutableRuleSecondTime = await getRule( + supertest, + '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + expect(immutableRuleSecondTime.exceptions_list.length).to.eql(0); + }); + + it('should allow adding a second exception list to an immutable rule through patch', async () => { + await installPrePackagedRules(supertest); + + const { id, list_id, namespace_type, type } = await createExceptionList( + supertest, + getCreateExceptionListMinimalSchemaMock() + ); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to use + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one + + // add a second exceptions list as a user is allowed to add a second list to an immutable rule + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + const immutableRuleSecondTime = await getRule( + supertest, + '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + + expect(immutableRuleSecondTime.exceptions_list.length).to.eql(2); + }); + + it('should override any updates to pre-packaged rules if the user removes the exception list through the API but the new version of a rule has an exception list again', async () => { + await installPrePackagedRules(supertest); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to use + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one + + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', exceptions_list: [] }) + .expect(200); + + await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + await installPrePackagedRules(supertest); + const immutableRuleSecondTime = await getRule( + supertest, + '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + + // We should have a length of 1 and it should be the same as our original before we tried to remove it using patch + expect(immutableRuleSecondTime.exceptions_list.length).to.eql(1); + expect(immutableRuleSecondTime.exceptions_list).to.eql(immutableRule.exceptions_list); + }); - const body = await findImmutableRuleById(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(body.data.length).to.eql(1); // should have only one length to the data set, otherwise we have duplicates or the tags were removed and that is incredibly bad. + it('should merge back an exceptions_list if it was removed from the immutable rule through PATCH', async () => { + await installPrePackagedRules(supertest); - const bodyToCompare = removeServerGeneratedProperties(body.data[0]); - expect(bodyToCompare.rule_id).to.eql(immutableRule.rule_id); // Rule id should not change with a a patch - expect(bodyToCompare.immutable).to.eql(immutableRule.immutable); // Immutable should always stay the same which is true and never flip to false. - expect(bodyToCompare.version).to.eql(immutableRule.version); // The version should never update on a patch + const { id, list_id, namespace_type, type } = await createExceptionList( + supertest, + getCreateExceptionListMinimalSchemaMock() + ); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one + + // remove the exception list and only have a single list that is not an endpoint_list + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + exceptions_list: [ + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + await installPrePackagedRules(supertest); + const immutableRuleSecondTime = await getRule( + supertest, + '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + + expect(immutableRuleSecondTime.exceptions_list).to.eql([ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ]); + }); + + it('should NOT add an extra exceptions_list that already exists on a rule during an upgrade', async () => { + await installPrePackagedRules(supertest); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one + + await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + await installPrePackagedRules(supertest); + + const immutableRuleSecondTime = await getRule( + supertest, + '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + + // The installed rule should have both the original immutable exceptions list back and the + // new list the user added. + expect(immutableRuleSecondTime.exceptions_list).to.eql([ + ...immutableRule.exceptions_list, + ]); + }); + + it('should NOT allow updates to pre-packaged rules to overwrite existing exception based rules when the user adds an additional exception list', async () => { + await installPrePackagedRules(supertest); + + const { id, list_id, namespace_type, type } = await createExceptionList( + supertest, + getCreateExceptionListMinimalSchemaMock() + ); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to ensure does not stomp on our existing rule + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + + // add a second exceptions list as a user is allowed to add a second list to an immutable rule + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await downgradeImmutableRule(es, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + await installPrePackagedRules(supertest); + const immutableRuleSecondTime = await getRule( + supertest, + '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + + // It should be the same as what the user added originally + expect(immutableRuleSecondTime.exceptions_list).to.eql([ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ]); + }); + + it('should not remove any exceptions added to a pre-packaged/immutable rule during an update if that rule has no existing exception lists', async () => { + await installPrePackagedRules(supertest); + + // Create a new exception list + const { id, list_id, namespace_type, type } = await createExceptionList( + supertest, + getCreateExceptionListMinimalSchemaMock() + ); + + // Rule id of "eb079c62-4481-4d6e-9643-3ca499df7aaa" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/external_alerts.json + // since this rule does not have existing exceptions_list that we are going to use for tests + const immutableRule = await getRule(supertest, 'eb079c62-4481-4d6e-9643-3ca499df7aaa'); + expect(immutableRule.exceptions_list.length).eql(0); // make sure we have no exceptions_list + + // add a second exceptions list as a user is allowed to add a second list to an immutable rule + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ + rule_id: 'eb079c62-4481-4d6e-9643-3ca499df7aaa', + exceptions_list: [ + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await downgradeImmutableRule(es, 'eb079c62-4481-4d6e-9643-3ca499df7aaa'); + await installPrePackagedRules(supertest); + const immutableRuleSecondTime = await getRule( + supertest, + 'eb079c62-4481-4d6e-9643-3ca499df7aaa' + ); + + expect(immutableRuleSecondTime.exceptions_list).to.eql([ + { + id, + list_id, + namespace_type, + type, + }, + ]); + }); + + it('should not change the immutable tags when adding a second exception list to an immutable rule through patch', async () => { + await installPrePackagedRules(supertest); + + const { id, list_id, namespace_type, type } = await createExceptionList( + supertest, + getCreateExceptionListMinimalSchemaMock() + ); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to use + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one + + // add a second exceptions list as a user is allowed to add a second list to an immutable rule + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + const body = await findImmutableRuleById( + supertest, + '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + expect(body.data.length).to.eql(1); // should have only one length to the data set, otherwise we have duplicates or the tags were removed and that is incredibly bad. + + const bodyToCompare = removeServerGeneratedProperties(body.data[0]); + expect(bodyToCompare.rule_id).to.eql(immutableRule.rule_id); // Rule id should not change with a a patch + expect(bodyToCompare.immutable).to.eql(immutableRule.immutable); // Immutable should always stay the same which is true and never flip to false. + expect(bodyToCompare.version).to.eql(immutableRule.version); // The version should never update on a patch + }); + + it('should not change count of prepacked rules when adding a second exception list to an immutable rule through patch. If this fails, suspect the immutable tags are not staying on the rule correctly.', async () => { + await installPrePackagedRules(supertest); + + const { id, list_id, namespace_type, type } = await createExceptionList( + supertest, + getCreateExceptionListMinimalSchemaMock() + ); + + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + // This rule has an existing exceptions_list that we are going to use + const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one + + // add a second exceptions list as a user is allowed to add a second list to an immutable rule + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send({ + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + const status = await getPrePackagedRulesStatus(supertest); + expect(status.rules_not_installed).to.eql(0); + }); }); - it('should not change count of prepacked rules when adding a second exception list to an immutable rule through patch. If this fails, suspect the immutable tags are not staying on the rule correctly.', async () => { - await installPrePackagedRules(supertest); - - const { id, list_id, namespace_type, type } = await createExceptionList( - supertest, - getCreateExceptionListMinimalSchemaMock() - ); - - // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: - // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json - // This rule has an existing exceptions_list that we are going to use - const immutableRule = await getRule(supertest, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); - expect(immutableRule.exceptions_list.length).greaterThan(0); // make sure we have at least one - - // add a second exceptions list as a user is allowed to add a second list to an immutable rule - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send({ - rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', - exceptions_list: [ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); + describe('t1_analyst', () => { + const role = ROLES.t1_analyst; + + beforeEach(async () => { + await createUserAndRole(getService, role); + }); - const status = await getPrePackagedRulesStatus(supertest); - expect(status.rules_not_installed).to.eql(0); + afterEach(async () => { + await deleteUserAndRole(getService, role); + }); + + it('should NOT be able to create an exception list', async () => { + await supertestWithoutAuth + .post(EXCEPTION_LIST_ITEM_URL) + .auth(role, 'changeme') + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(403); + }); + + it('should NOT be able to create an exception list item', async () => { + await supertestWithoutAuth + .post(EXCEPTION_LIST_ITEM_URL) + .auth(role, 'changeme') + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(403); + }); }); describe('tests with auditbeat data', () => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts index 30d734b0e0262e..a735eba6693fed 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts @@ -30,10 +30,13 @@ import { getRuleForSignalTesting, getRuleForSignalTestingWithTimestampOverride, } from '../../utils'; +import { ROLES } from '../../../../plugins/security_solution/common/test'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const esArchiver = getService('esArchiver'); describe('create_rules', () => { @@ -65,186 +68,209 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.unload('auditbeat/hosts'); }); - it('should create a single rule with a rule_id', async () => { - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(getSimpleRule()) - .expect(200); - - const bodyToCompare = removeServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getSimpleRuleOutput()); - }); - - /* - This test is to ensure no future regressions introduced by the following scenario - a call to updateApiKey was invalidating the api key used by the - rule while the rule was executing, or even before it executed, - on the first rule run. - this pr https://github.com/elastic/kibana/pull/68184 - fixed this by finding the true source of a bug that required the manual - api key update, and removed the call to that function. - - When the api key is updated before / while the rule is executing, the alert - executor no longer has access to a service to update the rule status - saved object in Elasticsearch. Because of this, we cannot set the rule into - a 'failure' state, so the user ends up seeing 'going to run' as that is the - last status set for the rule before it erupts in an error that cannot be - recorded inside of the executor. - - This adds an e2e test for the backend to catch that in case - this pops up again elsewhere. - */ - it('should create a single rule with a rule_id and validate it ran successfully', async () => { - const simpleRule = getRuleForSignalTesting(['auditbeat-*']); - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(simpleRule) - .expect(200); - - await waitForRuleSuccessOrStatus(supertest, body.id); - - const { body: statusBody } = await supertest - .post(DETECTION_ENGINE_RULES_STATUS_URL) - .set('kbn-xsrf', 'true') - .send({ ids: [body.id] }) - .expect(200); + describe('elastic admin', () => { + it('should create a single rule with a rule_id', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(200); - expect(statusBody[body.id].current_status.status).to.eql('succeeded'); - }); + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getSimpleRuleOutput()); + }); - it('should create a single rule with a rule_id and an index pattern that does not match anything available and fail the rule', async () => { - const simpleRule = getRuleForSignalTesting(['does-not-exist-*']); - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(simpleRule) - .expect(200); + /* + This test is to ensure no future regressions introduced by the following scenario + a call to updateApiKey was invalidating the api key used by the + rule while the rule was executing, or even before it executed, + on the first rule run. + this pr https://github.com/elastic/kibana/pull/68184 + fixed this by finding the true source of a bug that required the manual + api key update, and removed the call to that function. + + When the api key is updated before / while the rule is executing, the alert + executor no longer has access to a service to update the rule status + saved object in Elasticsearch. Because of this, we cannot set the rule into + a 'failure' state, so the user ends up seeing 'going to run' as that is the + last status set for the rule before it erupts in an error that cannot be + recorded inside of the executor. + + This adds an e2e test for the backend to catch that in case + this pops up again elsewhere. + */ + it('should create a single rule with a rule_id and validate it ran successfully', async () => { + const simpleRule = getRuleForSignalTesting(['auditbeat-*']); + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(simpleRule) + .expect(200); + + await waitForRuleSuccessOrStatus(supertest, body.id); + + const { body: statusBody } = await supertest + .post(DETECTION_ENGINE_RULES_STATUS_URL) + .set('kbn-xsrf', 'true') + .send({ ids: [body.id] }) + .expect(200); + + expect(statusBody[body.id].current_status.status).to.eql('succeeded'); + }); - await waitForRuleSuccessOrStatus(supertest, body.id, 'failed'); + it('should create a single rule with a rule_id and an index pattern that does not match anything available and fail the rule', async () => { + const simpleRule = getRuleForSignalTesting(['does-not-exist-*']); + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(simpleRule) + .expect(200); + + await waitForRuleSuccessOrStatus(supertest, body.id, 'failed'); + + const { body: statusBody } = await supertest + .post(DETECTION_ENGINE_RULES_STATUS_URL) + .set('kbn-xsrf', 'true') + .send({ ids: [body.id] }) + .expect(200); + + expect(statusBody[body.id].current_status.status).to.eql('failed'); + expect(statusBody[body.id].current_status.last_failure_message).to.eql( + 'The following index patterns did not match any indices: ["does-not-exist-*"]' + ); + }); - const { body: statusBody } = await supertest - .post(DETECTION_ENGINE_RULES_STATUS_URL) - .set('kbn-xsrf', 'true') - .send({ ids: [body.id] }) - .expect(200); + it('should create a single rule with a rule_id and an index pattern that does not match anything and an index pattern that does and the rule should be successful', async () => { + const simpleRule = getRuleForSignalTesting(['does-not-exist-*', 'auditbeat-*']); + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(simpleRule) + .expect(200); - expect(statusBody[body.id].current_status.status).to.eql('failed'); - expect(statusBody[body.id].current_status.last_failure_message).to.eql( - 'The following index patterns did not match any indices: ["does-not-exist-*"]' - ); - }); + await waitForRuleSuccessOrStatus(supertest, body.id, 'succeeded'); - it('should create a single rule with a rule_id and an index pattern that does not match anything and an index pattern that does and the rule should be successful', async () => { - const simpleRule = getRuleForSignalTesting(['does-not-exist-*', 'auditbeat-*']); - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(simpleRule) - .expect(200); + const { body: statusBody } = await supertest + .post(DETECTION_ENGINE_RULES_STATUS_URL) + .set('kbn-xsrf', 'true') + .send({ ids: [body.id] }) + .expect(200); - await waitForRuleSuccessOrStatus(supertest, body.id, 'succeeded'); - - const { body: statusBody } = await supertest - .post(DETECTION_ENGINE_RULES_STATUS_URL) - .set('kbn-xsrf', 'true') - .send({ ids: [body.id] }) - .expect(200); + expect(statusBody[body.id].current_status.status).to.eql('succeeded'); + }); - expect(statusBody[body.id].current_status.status).to.eql('succeeded'); - }); + it('should create a single rule without an input index', async () => { + const rule: CreateRulesSchema = { + name: 'Simple Rule Query', + description: 'Simple Rule Query', + enabled: true, + risk_score: 1, + rule_id: 'rule-1', + severity: 'high', + type: 'query', + query: 'user.name: root or user.name: admin', + }; + const expected = { + actions: [], + author: [], + created_by: 'elastic', + description: 'Simple Rule Query', + enabled: true, + false_positives: [], + from: 'now-6m', + immutable: false, + interval: '5m', + rule_id: 'rule-1', + language: 'kuery', + output_index: '.siem-signals-default', + max_signals: 100, + risk_score: 1, + risk_score_mapping: [], + name: 'Simple Rule Query', + query: 'user.name: root or user.name: admin', + references: [], + severity: 'high', + severity_mapping: [], + updated_by: 'elastic', + tags: [], + to: 'now', + type: 'query', + threat: [], + throttle: 'no_actions', + exceptions_list: [], + version: 1, + }; + + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(rule) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(expected); + }); - it('should create a single rule without an input index', async () => { - const rule: CreateRulesSchema = { - name: 'Simple Rule Query', - description: 'Simple Rule Query', - enabled: true, - risk_score: 1, - rule_id: 'rule-1', - severity: 'high', - type: 'query', - query: 'user.name: root or user.name: admin', - }; - const expected = { - actions: [], - author: [], - created_by: 'elastic', - description: 'Simple Rule Query', - enabled: true, - false_positives: [], - from: 'now-6m', - immutable: false, - interval: '5m', - rule_id: 'rule-1', - language: 'kuery', - output_index: '.siem-signals-default', - max_signals: 100, - risk_score: 1, - risk_score_mapping: [], - name: 'Simple Rule Query', - query: 'user.name: root or user.name: admin', - references: [], - severity: 'high', - severity_mapping: [], - updated_by: 'elastic', - tags: [], - to: 'now', - type: 'query', - threat: [], - throttle: 'no_actions', - exceptions_list: [], - version: 1, - }; + it('should create a single rule without a rule_id', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRuleWithoutRuleId()) + .expect(200); - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(rule) - .expect(200); + const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); + expect(bodyToCompare).to.eql(getSimpleRuleOutputWithoutRuleId()); + }); - const bodyToCompare = removeServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(expected); - }); + it('should create a single Machine Learning rule', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleMlRule()) + .expect(200); - it('should create a single rule without a rule_id', async () => { - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(getSimpleRuleWithoutRuleId()) - .expect(200); + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getSimpleMlRuleOutput()); + }); - const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); - expect(bodyToCompare).to.eql(getSimpleRuleOutputWithoutRuleId()); + it('should cause a 409 conflict if we attempt to create the same rule_id twice', async () => { + await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(200); + + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(409); + + expect(body).to.eql({ + message: 'rule_id: "rule-1" already exists', + status_code: 409, + }); + }); }); - it('should create a single Machine Learning rule', async () => { - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(getSimpleMlRule()) - .expect(200); + describe('t1_analyst', () => { + const role = ROLES.t1_analyst; - const bodyToCompare = removeServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getSimpleMlRuleOutput()); - }); - - it('should cause a 409 conflict if we attempt to create the same rule_id twice', async () => { - await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(getSimpleRule()) - .expect(200); + beforeEach(async () => { + await createUserAndRole(getService, role); + }); - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(getSimpleRule()) - .expect(409); + afterEach(async () => { + await deleteUserAndRole(getService, role); + }); - expect(body).to.eql({ - message: 'rule_id: "rule-1" already exists', - status_code: 409, + it('should NOT be able to create a rule', async () => { + await supertestWithoutAuth + .post(DETECTION_ENGINE_RULES_URL) + .auth(role, 'changeme') + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(403); }); }); });