[Cloud Security] fix rules flaky test suite (#212198)

## Summary

This PR fixes the flakiness of of rules page test suite -
https://github.com/elastic/kibana/issues/178413
Issues there were handled are:
1. Removing the set up of fleet server before every test which caused
flakiness.
![Screenshot 2025-02-24 at 9 54
40](https://github.com/user-attachments/assets/6913be9d-45aa-46fa-9923-671ed0d67f98)


2. Fixing race conditions.
3. Use retry.try function to re-execute in places where flakiness was
observed due to not waiting enough time before doing the action.

### Checklist

Reviewers should verify this PR satisfies this list as well.
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
Alex Prozorov 2025-02-26 12:05:55 +02:00 committed by GitHub
parent f5c4f203fc
commit 14e7f6007e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 554 additions and 284 deletions

View file

@ -25,6 +25,8 @@ export const RULE_NUMBER_FILTER = 'options-filter-popover-button-rule-number-mul
export const RULE_NUMBER_FILTER_SEARCH_FIELD = 'rule-number-search-input';
export const RULES_FLYOUT_SWITCH_BUTTON = 'rule-flyout-switch-button';
export const TAKE_ACTION_BUTTON = 'csp:take_action';
export const CLOSE_FLYOUT_BUTTON = 'euiFlyoutCloseButton';
export const CLOSE_TOAST_BUTTON = 'toastCloseButton';
export function RulePagePageProvider({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
@ -131,6 +133,29 @@ export function RulePagePageProvider({ getService, getPageObjects }: FtrProvider
const rulesFlyoutEnableSwitchButton = await testSubjects.find(RULES_FLYOUT_SWITCH_BUTTON);
return await rulesFlyoutEnableSwitchButton.getAttribute('aria-checked');
},
closeToasts: async () => {
const toasts = await testSubjects.findAll(CLOSE_TOAST_BUTTON);
for (const toast of toasts) {
await toast.click();
}
},
togglEnableRulesRowSwitchButton: async (index: number, filterType: 'enable' | 'disable') => {
const enableRulesRowSwitches = await testSubjects.findAll(RULES_ROWS_ENABLE_SWITCH_BUTTON);
const checked = await enableRulesRowSwitches[index].getAttribute('aria-checked');
if (filterType === 'enable' && checked) {
return;
}
if (filterType === 'disable' && !checked) {
return;
}
await enableRulesRowSwitches[index].click();
},
clickCloseFlyoutButton: async () => {
const closeFlyoutButton = await testSubjects.find(CLOSE_FLYOUT_BUTTON);
await closeFlyoutButton.click();
},
clickTakeActionButton: async () => {
const takeActionButton = await testSubjects.find(TAKE_ACTION_BUTTON);
@ -162,10 +187,17 @@ export function RulePagePageProvider({ getService, getPageObjects }: FtrProvider
},
clickIntegrationsEvaluatedButton: async () => {
const integrationsEvaluatedButton = await testSubjects.find(
'rules-counters-integrations-evaluated-button'
);
await integrationsEvaluatedButton.click();
await retry.try(async () => {
const integrationsEvaluatedButton = await testSubjects.find(
'rules-counters-integrations-evaluated-button'
);
// Check that href exists and is not empty
const href = await integrationsEvaluatedButton.getAttribute('href');
if (!href) {
throw new Error('Integration link is not ready yet - href is empty');
}
await integrationsEvaluatedButton.click();
});
},
getFailedFindingsCounter: async () => {

View file

@ -19,7 +19,9 @@ export default function ({ getPageObjects, loadTestFile }: FtrProviderContext) {
await cspSecurity.createUsers();
});
loadTestFile(require.resolve('./rules'));
loadTestFile(require.resolve('./rules/rules_counters'));
loadTestFile(require.resolve('./rules/rules_table'));
loadTestFile(require.resolve('./rules/rules_table_headers'));
loadTestFile(require.resolve('./findings_onboarding'));
loadTestFile(require.resolve('./findings'));
loadTestFile(require.resolve('./findings_grouping'));

View file

@ -1,279 +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 expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { createPackagePolicy } from '../../api_integration/apis/cloud_security_posture/helper';
import type { FtrProviderContext } from '../ftr_provider_context';
import {
RULES_BULK_ACTION_OPTION_DISABLE,
RULES_BULK_ACTION_OPTION_ENABLE,
} from '../page_objects/rule_page';
import { k8sFindingsMock } from '../mocks/latest_findings_mock';
// eslint-disable-next-line import/no-default-export
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const pageObjects = getPageObjects([
'common',
'cloudPostureDashboard',
'rule',
'header',
'findings',
]);
// FLAKY: https://github.com/elastic/kibana/issues/178413
describe.skip('Cloud Posture Rules Page', function () {
this.tags(['cloud_security_posture_rules_page']);
let rule: typeof pageObjects.rule;
let findings: typeof pageObjects.findings;
let agentPolicyId: string;
beforeEach(async () => {
rule = pageObjects.rule;
findings = pageObjects.findings;
await kibanaServer.savedObjects.cleanStandardList();
await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
const { body: agentPolicyResponse } = await supertest
.post(`/api/fleet/agent_policies`)
.set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31')
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Test policy',
namespace: 'default',
});
agentPolicyId = agentPolicyResponse.item.id;
await createPackagePolicy(
supertest,
agentPolicyId,
'kspm',
'cloudbeat/cis_k8s',
'vanilla',
'kspm'
);
await rule.waitForPluginInitialized();
await findings.index.add(k8sFindingsMock);
await rule.navigateToRulePage('cis_k8s', '1.0.1');
});
afterEach(async () => {
await kibanaServer.savedObjects.cleanStandardList();
await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
await findings.index.remove();
});
describe('Rules Page - Rules Counters', () => {
it('Shows posture score when there are findings', async () => {
const isEmptyStateVisible = await rule.rulePage.getCountersEmptyState();
expect(isEmptyStateVisible).to.be(false);
const postureScoreCounter = await rule.rulePage.getPostureScoreCounter();
expect((await postureScoreCounter.getVisibleText()).includes('33%')).to.be(true);
});
it('Clicking the posture score button leads to the dashboard', async () => {
await rule.rulePage.clickPostureScoreButton();
await pageObjects.common.waitUntilUrlIncludes('cloud_security_posture/dashboard');
});
it('Shows integrations count when there are findings', async () => {
const integrationsCounter = await rule.rulePage.getIntegrationsEvaluatedCounter();
expect((await integrationsCounter.getVisibleText()).includes('1')).to.be(true);
});
it('Clicking the integrations counter button leads to the integration page', async () => {
await rule.rulePage.clickIntegrationsEvaluatedButton();
await pageObjects.common.waitUntilUrlIncludes('add-integration/kspm');
});
it('Shows the failed findings counter when there are findings', async () => {
const failedFindingsCounter = await rule.rulePage.getFailedFindingsCounter();
expect((await failedFindingsCounter.getVisibleText()).includes('2')).to.be(true);
});
it('Clicking the failed findings button leads to the findings page', async () => {
await rule.rulePage.clickFailedFindingsButton();
await pageObjects.common.waitUntilUrlIncludes(
'cloud_security_posture/findings/configurations'
);
});
it('Shows the disabled rules count', async () => {
const disabledRulesCounter = await rule.rulePage.getDisabledRulesCounter();
expect((await disabledRulesCounter.getVisibleText()).includes('0')).to.be(true);
// disable rule 1.1.1 (k8s findings mock contains a findings from that rule)
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await disabledRulesCounter.getVisibleText()).includes('1')).to.be(true);
const postureScoreCounter = await rule.rulePage.getPostureScoreCounter();
expect((await postureScoreCounter.getVisibleText()).includes('0%')).to.be(true);
// enable rule back
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
});
it('Clicking the disabled rules button shows enables the disabled filter', async () => {
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
await pageObjects.header.waitUntilLoadingHasFinished();
await rule.rulePage.clickDisabledRulesButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 1).to.be(true);
});
it('Shows empty state when there are no findings', async () => {
// Ensure there are no findings initially
await findings.index.remove();
await rule.navigateToRulePage('cis_k8s', '1.0.1');
const isEmptyStateVisible = await rule.rulePage.getCountersEmptyState();
expect(isEmptyStateVisible).to.be(true);
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
});
});
describe('Rules Page - Bulk Action buttons', () => {
it('It should disable Enable option when there are all rules selected are already enabled ', async () => {
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(true);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(false);
});
it('It should disable both Enable and Disable options when there are no rules selected', async () => {
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(true);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(true);
});
it('It should disable Disable option when there are all rules selected are already Disabled', async () => {
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
await rule.rulePage.clickBulkActionOption(RULES_BULK_ACTION_OPTION_DISABLE);
await pageObjects.header.waitUntilLoadingHasFinished();
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(false);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(true);
});
it('Both option should not be disabled if selected rules contains both enabled and disabled rules', async () => {
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
await pageObjects.header.waitUntilLoadingHasFinished();
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(false);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(false);
});
});
describe('Rules Page - Enable Rules and Disabled Rules Filter Toggle', () => {
it('Should only display Enabled rules when Enabled Rules filter is ON', async () => {
await rule.rulePage.clickFilterButton('enabled');
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 1).to.be(true);
});
it('Should only display Disabled rules when Disabled Rules filter is ON', async () => {
await rule.rulePage.clickFilterButton('disabled');
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) > 1).to.be(true);
});
});
describe('Rules Page - CIS Section & Rule Number filters', () => {
it('Table should only show result that has the same section as in the Section filter', async () => {
await rule.rulePage.clickFilterPopover('section');
await rule.rulePage.clickFilterPopOverOption('etcd');
await rule.rulePage.clickFilterPopOverOption('Scheduler');
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) < 10).to.be(true);
});
it('Table should only show result that has the same section as in the Rule number filter', async () => {
await rule.rulePage.clickFilterPopover('ruleNumber');
await rule.rulePage.clickFilterPopOverOption('1.1.1');
await rule.rulePage.clickFilterPopOverOption('1.1.2');
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 2).to.be(true);
});
it('Table should only show result that passes both Section and Rule number filter', async () => {
await rule.rulePage.clickFilterPopover('section');
await rule.rulePage.clickFilterPopOverOption('Control-Plane-Node-Configuration-Files');
await rule.rulePage.clickFilterPopover('section');
await rule.rulePage.clickFilterPopover('ruleNumber');
await rule.rulePage.clickFilterPopOverOption('1.1.5');
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 1).to.be(true);
});
});
describe('Rules Page - Flyout', () => {
it('Users are able to Enable/Disable Rule from Switch on Rule Flyout', async () => {
await rule.rulePage.clickRulesNames(0);
await rule.rulePage.clickFlyoutEnableSwitchButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableSwitchButtonState()) === 'false').to.be(true);
});
it('Alerts section of Rules Flyout shows Disabled text when Rules are disabled', async () => {
await rule.rulePage.clickRulesNames(0);
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await rule.rulePage.doesElementExist(
'csp:findings-flyout-create-detection-rule-link'
)) === false
).to.be(true);
});
it('Users are able to Enable/Disable Rule from Take Action on Rule Flyout', async () => {
await rule.rulePage.clickRulesNames(0);
await rule.rulePage.clickTakeActionButton();
await rule.rulePage.clickTakeActionButtonOption('enable');
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableSwitchButtonState()) === 'true').to.be(true);
});
it('Alerts section of Rules Flyout shows Detection Rule Counter component when Rules are enabled', async () => {
await rule.rulePage.clickRulesNames(0);
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await rule.rulePage.doesElementExist(
'csp:findings-flyout-create-detection-rule-link'
)) === true
).to.be(true);
});
});
});
}

View file

@ -0,0 +1,169 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { createPackagePolicy } from '../../../api_integration/apis/cloud_security_posture/helper';
import type { FtrProviderContext } from '../../ftr_provider_context';
import { k8sFindingsMock } from '../../mocks/latest_findings_mock';
// eslint-disable-next-line import/no-default-export
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const pageObjects = getPageObjects([
'common',
'cloudPostureDashboard',
'rule',
'header',
'findings',
]);
const retryService = getService('retry');
describe('Cloud Posture Rules Page - Counters', function () {
this.tags(['cloud_security_posture_rules_page_counters']);
let rule: typeof pageObjects.rule;
let findings: typeof pageObjects.findings;
let agentPolicyId: string;
before(async () => {
rule = pageObjects.rule;
findings = pageObjects.findings;
await findings.index.remove();
// cleanup agent and package policies
await kibanaServer.savedObjects.clean({
types: [
'ingest-agent-policies',
'fleet-agent-policies',
'ingest-package-policies',
'fleet-package-policies',
'cloud-security-posture-settings',
],
});
await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
const { body: agentPolicyResponse } = await supertest
.post(`/api/fleet/agent_policies`)
.set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31')
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Test policy',
namespace: 'default',
});
agentPolicyId = agentPolicyResponse.item.id;
await createPackagePolicy(
supertest,
agentPolicyId,
'kspm',
'cloudbeat/cis_k8s',
'vanilla',
'kspm'
);
await rule.waitForPluginInitialized();
});
beforeEach(async () => {
await findings.index.add(k8sFindingsMock);
await rule.navigateToRulePage('cis_k8s', '1.0.1');
});
after(async () => {
await kibanaServer.savedObjects.clean({
types: [
'ingest-agent-policies',
'fleet-agent-policies',
'ingest-package-policies',
'fleet-package-policies',
'cloud-security-posture-settings',
],
});
await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
});
afterEach(async () => {
await findings.index.remove();
});
describe('Rules Page - Rules Counters', () => {
it('Shows posture score when there are findings', async () => {
const isEmptyStateVisible = await rule.rulePage.getCountersEmptyState();
expect(isEmptyStateVisible).to.be(false);
const postureScoreCounter = await rule.rulePage.getPostureScoreCounter();
expect((await postureScoreCounter.getVisibleText()).includes('33%')).to.be(true);
});
it('Clicking the posture score button leads to the dashboard', async () => {
await retryService.tryForTime(5000, async () => {
await rule.rulePage.clickPostureScoreButton();
await pageObjects.common.waitUntilUrlIncludes('cloud_security_posture/dashboard');
});
});
it('Shows integrations count when there are findings', async () => {
const integrationsCounter = await rule.rulePage.getIntegrationsEvaluatedCounter();
expect((await integrationsCounter.getVisibleText()).includes('1')).to.be(true);
});
it('Clicking the integrations counter button leads to the integration page', async () => {
await rule.rulePage.clickIntegrationsEvaluatedButton();
await pageObjects.common.waitUntilUrlIncludes('add-integration/kspm');
});
it('Shows the failed findings counter when there are findings', async () => {
const failedFindingsCounter = await rule.rulePage.getFailedFindingsCounter();
expect((await failedFindingsCounter.getVisibleText()).includes('2')).to.be(true);
});
it('Clicking the failed findings button leads to the findings page', async () => {
await rule.rulePage.clickFailedFindingsButton();
await pageObjects.common.waitUntilUrlIncludes(
'cloud_security_posture/findings/configurations'
);
});
it('Shows the disabled rules count', async () => {
const disabledRulesCounter = await rule.rulePage.getDisabledRulesCounter();
expect((await disabledRulesCounter.getVisibleText()).includes('0')).to.be(true);
// disable rule 1.1.1 (k8s findings mock contains a findings from that rule)
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await disabledRulesCounter.getVisibleText()).includes('1')).to.be(true);
const postureScoreCounter = await rule.rulePage.getPostureScoreCounter();
expect((await postureScoreCounter.getVisibleText()).includes('0%')).to.be(true);
// enable rule back
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
});
it('Clicking the disabled rules button shows enables the disabled filter', async () => {
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
await pageObjects.header.waitUntilLoadingHasFinished();
await rule.rulePage.clickDisabledRulesButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 1).to.be(true);
});
it('Shows empty state when there are no findings', async () => {
// Ensure there are no findings initially
await findings.index.remove();
await rule.navigateToRulePage('cis_k8s', '1.0.1');
const isEmptyStateVisible = await rule.rulePage.getCountersEmptyState();
expect(isEmptyStateVisible).to.be(true);
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
});
});
});
}

View file

@ -0,0 +1,210 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { createPackagePolicy } from '../../../api_integration/apis/cloud_security_posture/helper';
import type { FtrProviderContext } from '../../ftr_provider_context';
import { k8sFindingsMock } from '../../mocks/latest_findings_mock';
import {
RULES_BULK_ACTION_OPTION_DISABLE,
RULES_BULK_ACTION_OPTION_ENABLE,
} from '../../page_objects/rule_page';
// eslint-disable-next-line import/no-default-export
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const pageObjects = getPageObjects([
'common',
'cloudPostureDashboard',
'rule',
'header',
'findings',
]);
const retryService = getService('retry');
describe('Cloud Posture Rules Page - Table', function () {
this.tags(['cloud_security_posture_rules_page_table']);
let rule: typeof pageObjects.rule;
let findings: typeof pageObjects.findings;
let agentPolicyId: string;
before(async () => {
rule = pageObjects.rule;
findings = pageObjects.findings;
await findings.index.remove();
await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
const { body: agentPolicyResponse } = await supertest
.post(`/api/fleet/agent_policies`)
.set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31')
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Test policy',
namespace: 'default',
});
agentPolicyId = agentPolicyResponse.item.id;
await createPackagePolicy(
supertest,
agentPolicyId,
'kspm',
'cloudbeat/cis_k8s',
'vanilla',
'kspm'
);
await rule.waitForPluginInitialized();
});
beforeEach(async () => {
// cleanup agent and package policies
await kibanaServer.savedObjects.clean({
types: [
'ingest-agent-policies',
'fleet-agent-policies',
'ingest-package-policies',
'fleet-package-policies',
'cloud-security-posture-settings',
],
});
await findings.index.add(k8sFindingsMock);
await rule.navigateToRulePage('cis_k8s', '1.0.1');
});
after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
});
afterEach(async () => {
await kibanaServer.savedObjects.clean({
types: [
'ingest-agent-policies',
'fleet-agent-policies',
'ingest-package-policies',
'fleet-package-policies',
'cloud-security-posture-settings',
],
});
await findings.index.remove();
});
describe('Rules Page - Bulk Action buttons', () => {
it('It should disable Enable option when there are all rules selected are already enabled ', async () => {
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(true);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(false);
});
it('It should disable both Enable and Disable options when there are no rules selected', async () => {
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(true);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(true);
});
it('It should disable Disable option when there are all rules selected are already Disabled', async () => {
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
await rule.rulePage.clickBulkActionOption(RULES_BULK_ACTION_OPTION_DISABLE);
await pageObjects.header.waitUntilLoadingHasFinished();
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(false);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(true);
});
it('Both option should not be disabled if selected rules contains both enabled and disabled rules', async () => {
await rule.rulePage.clickEnableRulesRowSwitchButton(0);
await pageObjects.header.waitUntilLoadingHasFinished();
await rule.rulePage.clickSelectAllRules();
await rule.rulePage.toggleBulkActionButton();
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_ENABLE)) ===
'true'
).to.be(false);
expect(
(await rule.rulePage.isBulkActionOptionDisabled(RULES_BULK_ACTION_OPTION_DISABLE)) ===
'true'
).to.be(false);
});
});
describe('Rules Page - Flyout', () => {
it('Users are able to Enable/Disable Rule from Switch on Rule Flyout', async () => {
// Ensure that the first rule is enabled
await rule.rulePage.togglEnableRulesRowSwitchButton(0, 'enable');
await rule.rulePage.closeToasts();
await rule.rulePage.clickRulesNames(0);
await rule.rulePage.clickFlyoutEnableSwitchButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableSwitchButtonState()) === 'false').to.be(true);
await rule.rulePage.clickCloseFlyoutButton();
});
it('Alerts section of Rules Flyout shows Disabled text when Rules are disabled', async () => {
await rule.rulePage.togglEnableRulesRowSwitchButton(0, 'disable');
await rule.rulePage.closeToasts();
await rule.rulePage.clickRulesNames(0);
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await rule.rulePage.doesElementExist(
'csp:findings-flyout-create-detection-rule-link'
)) === false
).to.be(true);
await rule.rulePage.clickCloseFlyoutButton();
});
it('Users are able to Enable/Disable Rule from Take Action on Rule Flyout', async () => {
await rule.rulePage.togglEnableRulesRowSwitchButton(0, 'disable');
await rule.rulePage.closeToasts();
await rule.rulePage.clickRulesNames(0);
await retryService.try(async () => {
await rule.rulePage.clickTakeActionButton();
await rule.rulePage.clickTakeActionButtonOption('enable');
});
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableSwitchButtonState()) === 'true').to.be(true);
await rule.rulePage.clickCloseFlyoutButton();
});
it('Alerts section of Rules Flyout shows Detection Rule Counter component when Rules are enabled', async () => {
await rule.rulePage.clickRulesNames(0);
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await rule.rulePage.doesElementExist(
'csp:findings-flyout-create-detection-rule-link'
)) === true
).to.be(true);
});
});
});
}

View file

@ -0,0 +1,136 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { createPackagePolicy } from '../../../api_integration/apis/cloud_security_posture/helper';
import type { FtrProviderContext } from '../../ftr_provider_context';
import { k8sFindingsMock } from '../../mocks/latest_findings_mock';
// eslint-disable-next-line import/no-default-export
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const pageObjects = getPageObjects([
'common',
'cloudPostureDashboard',
'rule',
'header',
'findings',
]);
describe('Cloud Posture Rules Page - Table Headers', function () {
this.tags(['cloud_security_posture_rules_page_table_headers']);
let rule: typeof pageObjects.rule;
let findings: typeof pageObjects.findings;
let agentPolicyId: string;
before(async () => {
rule = pageObjects.rule;
findings = pageObjects.findings;
await findings.index.remove();
// cleanup agent and package policies
await kibanaServer.savedObjects.clean({
types: [
'ingest-agent-policies',
'fleet-agent-policies',
'ingest-package-policies',
'fleet-package-policies',
'cloud-security-posture-settings',
],
});
await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
const { body: agentPolicyResponse } = await supertest
.post(`/api/fleet/agent_policies`)
.set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31')
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Test policy',
namespace: 'default',
});
agentPolicyId = agentPolicyResponse.item.id;
await createPackagePolicy(
supertest,
agentPolicyId,
'kspm',
'cloudbeat/cis_k8s',
'vanilla',
'kspm'
);
await rule.waitForPluginInitialized();
});
beforeEach(async () => {
await findings.index.add(k8sFindingsMock);
await rule.navigateToRulePage('cis_k8s', '1.0.1');
});
after(async () => {
await kibanaServer.savedObjects.clean({
types: [
'ingest-agent-policies',
'fleet-agent-policies',
'ingest-package-policies',
'fleet-package-policies',
'cloud-security-posture-settings',
],
});
await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
});
afterEach(async () => {
await findings.index.remove();
});
describe('Rules Page - Enable Rules and Disabled Rules Filter Toggle', () => {
it('Should only display Enabled rules when Enabled Rules filter is ON', async () => {
await rule.rulePage.clickFilterButton('enabled');
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 25).to.be(true);
});
it('Should only display Disabled rules when Disabled Rules filter is ON', async () => {
await rule.rulePage.clickFilterButton('disabled');
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 0).to.be(true);
});
});
describe('Rules Page - CIS Section & Rule Number filters', () => {
it('Table should only show result that has the same section as in the Section filter', async () => {
await rule.rulePage.closeToasts();
await rule.rulePage.clickFilterPopover('section');
await rule.rulePage.clickFilterPopOverOption('etcd');
await rule.rulePage.clickFilterPopOverOption('Scheduler');
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) < 10).to.be(true);
});
it('Table should only show result that has the same section as in the Rule number filter', async () => {
await rule.rulePage.closeToasts();
await rule.rulePage.clickFilterPopover('ruleNumber');
await rule.rulePage.clickFilterPopOverOption('1.1.1');
await rule.rulePage.clickFilterPopOverOption('1.1.2');
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 2).to.be(true);
});
it('Table should only show result that passes both Section and Rule number filter', async () => {
await rule.rulePage.closeToasts();
await rule.rulePage.clickFilterPopover('section');
await rule.rulePage.clickFilterPopOverOption('Control-Plane-Node-Configuration-Files');
await rule.rulePage.clickFilterPopover('section');
await rule.rulePage.clickFilterPopover('ruleNumber');
await rule.rulePage.clickFilterPopOverOption('1.1.5');
expect((await rule.rulePage.getEnableRulesRowSwitchButton()) === 1).to.be(true);
});
});
});
}