[EDR Workflows] Verify flaky osquery tests (#169749)

This commit is contained in:
Tomasz Ciecierski 2023-11-01 07:09:41 +01:00 committed by GitHub
parent 531b3eccde
commit a15a9484e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 240 additions and 153 deletions

View file

@ -15,6 +15,7 @@ if [[ "$IS_TEST_EXECUTION_STEP" == "true" ]]; then
buildkite-agent artifact upload 'target/kibana-*'
buildkite-agent artifact upload 'target/kibana-security-solution/**/*.png'
buildkite-agent artifact upload 'target/kibana-osquery/**/*.png'
buildkite-agent artifact upload 'target/kibana-osquery/**/*.mp4'
buildkite-agent artifact upload 'target/kibana-fleet/**/*.png'
buildkite-agent artifact upload 'target/test-metrics/*'
buildkite-agent artifact upload 'target/test-suites-ci-plan.json'

View file

@ -11,6 +11,7 @@ import path from 'path';
import { safeLoad as loadYaml } from 'js-yaml';
import { readFileSync } from 'fs';
import { getFailedSpecVideos } from './support/filter_videos';
import type { YamlRoleDefinitions } from '../../../test_serverless/shared/lib';
import { setupUserDataLoader } from '../../../test_serverless/functional/test_suites/security/cypress/support/setup_data_loader_tasks';
const ROLES_YAML_FILE_PATH = path.join(
@ -36,8 +37,9 @@ export default defineCypressConfig({
screenshotsFolder: '../../../target/kibana-osquery/cypress/screenshots',
trashAssetsBeforeRuns: false,
video: false,
video: true,
videosFolder: '../../../target/kibana-osquery/cypress/videos',
videoCompression: 15,
viewportHeight: 900,
viewportWidth: 1440,
experimentalStudio: true,
@ -59,6 +61,7 @@ export default defineCypressConfig({
numTestsKeptInMemory: 3,
setupNodeEvents(on, config) {
setupUserDataLoader(on, config, { roleDefinitions, additionalRoleName: 'viewer' });
on('after:spec', getFailedSpecVideos);
return config;
},

View file

@ -66,8 +66,7 @@ describe('ALL - Add Integration', { tags: ['@ess', '@serverless'] }, () => {
}
);
// FLAKY: https://github.com/elastic/kibana/issues/169702
describe.skip('Add and upgrade integration', { tags: ['@ess', '@serverless'] }, () => {
describe('Add and upgrade integration', { tags: ['@ess', '@serverless'] }, () => {
const oldVersion = '0.7.4';
const [integrationName, policyName] = generateRandomStringName(2);
let policyId: string;

View file

@ -5,15 +5,19 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { cleanupRule, loadRule } from '../../tasks/api_fixtures';
import { checkActionItemsInResults, loadRuleAlerts } from '../../tasks/live_query';
const UUID_REGEX = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}';
// FLAKY: https://github.com/elastic/kibana/issues/169727
describe.skip('Alert Flyout Automated Action Results', () => {
describe('Alert Flyout Automated Action Results', () => {
let ruleId: string;
before(() => {
initializeDataViews();
});
beforeEach(() => {
loadRule(true).then((data) => {
ruleId = data.id;

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { OSQUERY_FLYOUT_BODY_EDITOR } from '../../screens/live_query';
import {
cleanupCase,
@ -29,6 +30,9 @@ describe('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, () =>
let packId: string;
let packName: string;
const packData = packFixture();
before(() => {
initializeDataViews();
});
beforeEach(() => {
loadPack(packData).then((data) => {

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { cleanupRule, loadRule } from '../../tasks/api_fixtures';
import { RESPONSE_ACTIONS_ITEM_0, RESPONSE_ACTIONS_ITEM_1 } from '../../tasks/response_actions';
import {
@ -25,7 +26,9 @@ describe(
() => {
let ruleId: string;
let ruleName: string;
before(() => {
initializeDataViews();
});
beforeEach(() => {
loadRule().then((data) => {
ruleId = data.id;

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { cleanupRule, loadRule } from '../../tasks/api_fixtures';
import {
inputQuery,
@ -14,8 +15,7 @@ import {
} from '../../tasks/live_query';
import { OSQUERY_FLYOUT_BODY_EDITOR } from '../../screens/live_query';
// FLAKY: https://github.com/elastic/kibana/issues/170157
describe.skip(
describe(
'Alert Event Details - dynamic params',
{
tags: ['@ess', '@serverless'],
@ -25,6 +25,7 @@ describe.skip(
let ruleName: string;
before(() => {
initializeDataViews();
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import {
cleanupPack,
cleanupRule,
@ -31,7 +32,9 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
let packName: string;
const packData = packFixture();
const multiQueryPackData = multiQueryPackFixture();
before(() => {
initializeDataViews();
});
beforeEach(() => {
loadPack(packData).then((data) => {
packId = data.saved_object_id;
@ -55,6 +58,7 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
it('adds response actions with osquery with proper validation and form values', () => {
cy.visit('/app/security/rules');
clickRuleName(ruleName);
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
closeDateTabIfVisible();
@ -81,20 +85,22 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_2).within(() => {
cy.contains('Query is a required field');
inputQuery('select * from uptime');
cy.contains('Query is a required field').should('not.exist');
cy.contains('Advanced').click();
typeInECSFieldInput('{downArrow}{enter}');
cy.getBySel('osqueryColumnValueSelect').type('days{downArrow}{enter}');
cy.wait(1000); // wait for the validation to trigger - cypress is way faster than users ;)
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_2)
.within(() => {
cy.contains('Query is a required field');
inputQuery('select * from uptime');
cy.contains('Query is a required field').should('not.exist');
cy.contains('Advanced').click();
typeInECSFieldInput('{downArrow}{enter}');
cy.getBySel('osqueryColumnValueSelect').type('days{downArrow}{enter}');
})
.clickOutside();
cy.getBySel('ruleEditSubmitButton').click();
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
@ -114,11 +120,13 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
cy.contains('select * from uptime1');
cy.getBySel('remove-response-action').click();
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains('Search for a pack to run');
cy.contains('Pack is a required field');
cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`);
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_0)
.within(() => {
cy.contains('Search for a pack to run');
cy.contains('Pack is a required field');
cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`);
})
.clickOutside();
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('select * from uptime');
cy.contains('Custom key/value pairs. e.g. {"application":"foo-bar","env":"production"}');
@ -126,6 +134,7 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
});
cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleSingleQuery');
cy.getBySel('ruleEditSubmitButton').click();
cy.wait('@saveRuleSingleQuery').should(({ request }) => {
const oneQuery = [
@ -141,8 +150,10 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0)
.within(() => {
@ -153,12 +164,15 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
})
.clickOutside();
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('select * from uptime');
cy.contains('Custom key/value pairs. e.g. {"application":"foo-bar","env":"production"}');
cy.contains('Days of uptime');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_1)
.within(() => {
cy.contains('select * from uptime');
cy.contains('Custom key/value pairs. e.g. {"application":"foo-bar","env":"production"}');
cy.contains('Days of uptime');
})
.clickOutside();
cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleMultiQuery');
cy.contains('Save changes').click();
cy.wait('@saveRuleMultiQuery').should(({ request }) => {
const threeQueries = [

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import {
addLiveQueryToCase,
checkActionItemsInResults,
@ -14,11 +15,11 @@ import { navigateTo } from '../../tasks/navigation';
import { loadLiveQuery, loadCase, cleanupCase } from '../../tasks/api_fixtures';
import { ServerlessRoleName } from '../../support/roles';
// FLAKY: https://github.com/elastic/kibana/issues/169747
describe.skip('Add to Cases', () => {
describe('Add to Cases', () => {
let liveQueryId: string;
let liveQueryQuery: string;
before(() => {
initializeDataViews();
loadLiveQuery({
agent_all: true,
query: "SELECT * FROM os_version where name='Ubuntu';",
@ -32,7 +33,7 @@ describe.skip('Add to Cases', () => {
describe('observability', { tags: ['@ess'] }, () => {
let caseId: string;
let caseTitle: string;
before(() => {
beforeEach(() => {
loadCase('observability').then((caseInfo) => {
caseId = caseInfo.id;
caseTitle = caseInfo.title;
@ -41,7 +42,7 @@ describe.skip('Add to Cases', () => {
navigateTo('/app/osquery');
});
after(() => {
afterEach(() => {
cleanupCase(caseId);
});
@ -64,7 +65,7 @@ describe.skip('Add to Cases', () => {
let caseId: string;
let caseTitle: string;
before(() => {
beforeEach(() => {
loadCase('securitySolution').then((caseInfo) => {
caseId = caseInfo.id;
caseTitle = caseInfo.title;
@ -73,7 +74,7 @@ describe.skip('Add to Cases', () => {
navigateTo('/app/osquery');
});
after(() => {
afterEach(() => {
cleanupCase(caseId);
});

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { navigateTo } from '../../tasks/navigation';
import {
checkActionItemsInResults,
@ -28,6 +29,7 @@ describe('ALL - Custom space', () => {
let spaceId: string;
before(() => {
initializeDataViews();
cy.wrap(
new Promise<string>((resolve) => {
if (testSpace.name !== 'default') {

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { getAdvancedButton } from '../../screens/integrations';
import { navigateTo } from '../../tasks/navigation';
import {
@ -19,6 +20,10 @@ import {
import { ServerlessRoleName } from '../../support/roles';
describe('EcsMapping', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
initializeDataViews();
});
beforeEach(() => {
cy.login(ServerlessRoleName.SOC_MANAGER);
});

View file

@ -18,8 +18,7 @@ import { LIVE_QUERY_EDITOR } from '../../screens/live_query';
import { getAdvancedButton } from '../../screens/integrations';
import { ServerlessRoleName } from '../../support/roles';
// FLAKY: https://github.com/elastic/kibana/issues/169725
describe.skip('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => {
describe('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => {
beforeEach(() => {
cy.login(ServerlessRoleName.SOC_MANAGER);
navigateTo('/app/osquery');
@ -87,6 +86,6 @@ describe.skip('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => {
inputQuery('{selectall}{backspace}{selectall}{backspace}');
// not sure if this is how it used to work when I implemented the functionality, but let's leave it like this for now
cy.get(LIVE_QUERY_EDITOR).invoke('height').should('be.gt', 200).and('be.lt', 380);
cy.get(LIVE_QUERY_EDITOR).invoke('height').should('be.gt', 200).and('be.lt', 400);
});
});

View file

@ -11,9 +11,7 @@ import { loadSavedQuery, cleanupSavedQuery } from '../../tasks/api_fixtures';
import { triggerLoadData } from '../../tasks/inventory';
import { ServerlessRoleName } from '../../support/roles';
// FLAKY: https://github.com/elastic/kibana/issues/169574
// FLAKY: https://github.com/elastic/kibana/issues/169575
describe.skip('ALL - Inventory', { tags: ['@ess'] }, () => {
describe('ALL - Inventory', { tags: ['@ess'] }, () => {
let savedQueryName: string;
let savedQueryId: string;

View file

@ -15,7 +15,7 @@ import {
findFormFieldByRowsLabelAndType,
inputQuery,
} from '../../tasks/live_query';
import { activatePack, deactivatePack, preparePack } from '../../tasks/packs';
import { changePackActiveStatus, preparePack } from '../../tasks/packs';
import {
closeModalIfVisible,
closeToastIfVisible,
@ -513,8 +513,8 @@ describe('Packs - Create and Edit', { tags: ['@ess', '@serverless'] }, () => {
it('', () => {
cy.contains('Packs').click();
deactivatePack(packName);
activatePack(packName);
changePackActiveStatus(packName);
changePackActiveStatus(packName);
});
});

View file

@ -8,17 +8,15 @@
import { find } from 'lodash';
import type { PackagePolicy } from '@kbn/fleet-plugin/common';
import { API_VERSIONS } from '../../../common/constants';
import { FLEET_AGENT_POLICIES, navigateTo } from '../../tasks/navigation';
import { FLEET_AGENT_POLICIES, navigateToWithoutWaitForReact } from '../../tasks/navigation';
import {
checkActionItemsInResults,
checkResults,
deleteAndConfirm,
findAndClickButton,
findFormFieldByRowsLabelAndType,
selectAllAgents,
submitQuery,
} from '../../tasks/live_query';
import { activatePack, cleanupAllPrebuiltPacks, deactivatePack } from '../../tasks/packs';
import { changePackActiveStatus, cleanupAllPrebuiltPacks } from '../../tasks/packs';
import {
addIntegration,
closeModalIfVisible,
@ -62,19 +60,19 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
cy.contains(integration).click();
addIntegration(AGENT_POLICY_NAME);
cy.contains('Add Elastic Agent later').click();
navigateTo('app/osquery/packs');
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', REMOVING_PACK);
findFormFieldByRowsLabelAndType('Scheduled agent policies (optional)', AGENT_POLICY_NAME);
findAndClickButton('Save pack');
navigateToWithoutWaitForReact('app/osquery/packs');
cy.getBySel('addPackButton').click();
cy.get('input[name="name"]').type(`${REMOVING_PACK}{downArrow}{enter}`);
cy.getBySel('policyIdsComboBox').type(`${AGENT_POLICY_NAME}{downArrow}{enter}`);
cy.getBySel('savePackButton').click();
closeToastIfVisible();
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.react('ScheduledQueryNameComponent', { props: { name: REMOVING_PACK } }).click();
cy.contains(REMOVING_PACK).click();
cy.contains(`${REMOVING_PACK} details`).should('exist');
findAndClickButton('Edit');
cy.react('EuiComboBoxInput', { props: { value: AGENT_POLICY_NAME } }).should('exist');
cy.get('span').contains('Edit').click();
cy.getBySel('comboBoxInput').contains(AGENT_POLICY_NAME).should('exist');
cy.visit(FLEET_AGENT_POLICIES);
cy.contains(AGENT_POLICY_NAME).click();
@ -86,12 +84,13 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
cy.contains(/^Delete integration$/).click();
closeModalIfVisible();
cy.contains(/^Deleted integration 'osquery_manager-*/);
navigateTo('app/osquery/packs');
navigateToWithoutWaitForReact('app/osquery/packs');
cy.contains(REMOVING_PACK).click();
cy.contains(`${REMOVING_PACK} details`).should('exist');
cy.wait(1000);
findAndClickButton('Edit');
cy.react('EuiComboBoxInput', { props: { value: '' } }).should('exist');
cy.get('span').contains('Edit').click();
cy.getBySel('comboBoxInput').should('have.value', '');
});
}
);
@ -100,49 +99,44 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
afterEach(() => {
cleanupAllPrebuiltPacks();
});
const PREBUILD_PACK_NAME = 'it-compliance';
describe('', () => {
beforeEach(() => {
cy.login(ServerlessRoleName.SOC_MANAGER);
navigateTo('/app/osquery/packs');
navigateToWithoutWaitForReact('/app/osquery/packs');
});
it('should load prebuilt packs', () => {
cy.contains('Load Elastic prebuilt packs').click();
cy.contains('Load Elastic prebuilt packs').should('not.exist');
cy.wait(1000);
cy.react('EuiTableRow').should('have.length.above', 5);
cy.get('tbody > tr').should('have.length.above', 5);
});
it('should be able to activate pack', () => {
activatePack(PREBUILD_PACK_NAME);
deactivatePack(PREBUILD_PACK_NAME);
changePackActiveStatus(PREBUILD_PACK_NAME);
changePackActiveStatus(PREBUILD_PACK_NAME);
});
it('should be able to add policy to it', () => {
cy.contains(PREBUILD_PACK_NAME).click();
cy.contains('Edit').click();
findFormFieldByRowsLabelAndType(
'Scheduled agent policies (optional)',
`${DEFAULT_POLICY} {downArrow}{enter}`
);
cy.contains('Update pack').click();
cy.getBySel('policyIdsComboBox').type(`${DEFAULT_POLICY} {downArrow}{enter}`);
cy.getBySel('updatePackButton').click();
cy.getBySel('confirmModalConfirmButton').click();
cy.contains(`Successfully updated "${PREBUILD_PACK_NAME}" pack`);
});
it('should be able to activate pack with agent inside', () => {
activatePack(PREBUILD_PACK_NAME);
deactivatePack(PREBUILD_PACK_NAME);
changePackActiveStatus(PREBUILD_PACK_NAME);
changePackActiveStatus(PREBUILD_PACK_NAME);
});
it('should not be able to update prebuilt pack', () => {
cy.contains(PREBUILD_PACK_NAME).click();
cy.contains('Edit').click();
cy.react('EuiFieldText', { props: { name: 'name', isDisabled: true } });
cy.react('EuiFieldText', { props: { name: 'description', isDisabled: true } });
cy.get('input[name="name"]').should('be.disabled');
cy.get('input[name="description"]').should('be.disabled');
cy.contains('Add Query').should('not.exist');
cy.react('ExpandedItemActions', { options: { timeout: 1000 } });
cy.get('.euiTableRowCell--hasActions').should('not.exist');
});
it('should be able to delete prebuilt pack and add it again', () => {
@ -156,7 +150,7 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
});
it('should be able to run live prebuilt pack', () => {
navigateTo('/app/osquery/live_queries');
navigateToWithoutWaitForReact('/app/osquery/live_queries');
cy.contains('New live query').click();
cy.contains('Run a set of queries in a pack.').click();
cy.get(LIVE_QUERY_EDITOR).should('not.exist');
@ -171,17 +165,16 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
cases: true,
timeline: false,
});
navigateTo('/app/osquery');
navigateToWithoutWaitForReact('/app/osquery');
cy.contains('osquery-monitoring');
});
});
});
// FLAKY: https://github.com/elastic/kibana/issues/169688
describe.skip('Global packs', { tags: ['@ess', '@serverless'] }, () => {
describe('Global packs', { tags: ['@ess', '@serverless'] }, () => {
beforeEach(() => {
cy.login(ServerlessRoleName.PLATFORM_ENGINEER);
navigateTo('/app/osquery/packs');
navigateToWithoutWaitForReact('/app/osquery/packs');
});
describe('add proper shard to policies packs config', () => {
@ -205,14 +198,12 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
});
it('add global packs to policies', () => {
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', globalPack);
cy.getBySel('addPackButton').click();
cy.get('input[name="name"]').type(`${globalPack}{downArrow}{enter}`);
cy.getBySel('policyIdsComboBox').should('exist');
cy.getBySel('osqueryPackTypeGlobal').click();
cy.getBySel('policyIdsComboBox').should('not.exist');
findAndClickButton('Save pack');
cy.getBySel('savePackButton').click();
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.contains(globalPack);
@ -269,8 +260,8 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
it('', () => {
const shardPack = 'shardPack' + generateRandomStringName(1)[0];
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', shardPack);
cy.getBySel('addPackButton').click();
cy.get('input[name="name"]').type(`${shardPack}{downArrow}{enter}`);
cy.contains('Partial deployment (shards)').click();
cy.getBySel('packShardsForm-0').within(() => {
@ -281,7 +272,7 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
cy.getBySel('shards-field-policy').type(`${OSQUERY_POLICY}{downArrow}{enter}`);
cy.get('#shardsPercentage1').type('{backspace}{backspace}{backspace}');
});
findAndClickButton('Save pack');
cy.getBySel('savePackButton').click();
cy.contains(`Successfully created "${shardPack}" pack`);
closeToastIfVisible();
@ -319,9 +310,9 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => {
cy.get('[data-test-subj="packShardsForm-1"]').within(() => {
cy.get(`[aria-label="Delete shards row"]`).click();
});
cy.getBySel('comboBoxInput').contains(OSQUERY_POLICY).should('not.exist');
cy.getBySel('policyIdsComboBox').click();
cy.contains(OSQUERY_POLICY).should('exist');
cy.getBySel('policyIdsComboBox').contains(OSQUERY_POLICY).should('not.exist');
cy.getBySel('policyIdsComboBox').click().type(`${OSQUERY_POLICY}{downArrow}{enter}`);
cy.getBySel('policyIdsComboBox').contains(OSQUERY_POLICY).should('exist');
});
});
});

View file

@ -105,18 +105,14 @@ describe('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => {
});
it('checks result type on prebuilt saved query', () => {
cy.react('CustomItemAction', {
props: { index: 1, item: { id: 'users_elastic' } },
}).click();
cy.get(`[aria-label="Edit users_elastic"]`).click();
cy.getBySel('resultsTypeField').within(() => {
cy.contains('Snapshot');
});
});
it('user can run prebuilt saved query and add to case', () => {
cy.react('PlayButtonComponent', {
props: { savedQuery: { id: 'users_elastic' } },
}).click();
cy.get(`[aria-label="Run users_elastic"]`).click();
selectAllAgents();
submitQuery();
@ -126,9 +122,7 @@ describe('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => {
});
it('user can not delete prebuilt saved query but can delete normal saved query', () => {
cy.react('CustomItemAction', {
props: { index: 1, item: { id: 'users_elastic' } },
}).click();
cy.get(`[aria-label="Edit users_elastic"]`).click();
cy.contains('Delete query').should('not.exist');
navigateTo(`/app/osquery/saved_queries/${savedQueryId}`);
@ -142,18 +136,14 @@ describe('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => {
findAndClickButton('Add query');
cy.contains('Attach next query');
cy.react('EuiComboBox', {
props: { placeholder: 'Search for a query to run, or write a new query below' },
})
.click()
.type('users_elastic{downArrow} {enter}');
cy.getBySel('savedQuerySelect').click().type('users_elastic{downArrow} {enter}');
inputQuery('where name=1');
cy.getBySel('resultsTypeField').click();
cy.contains('Differential (Ignore removals)').click();
cy.contains('Unique identifier of the us').should('exist');
cy.contains('User ID').should('exist');
cy.react('EuiFlyoutBody').within(() => {
cy.get(`[aria-labelledby="flyoutTitle"]`).within(() => {
cy.getBySel('ECSMappingEditorForm')
.first()
.within(() => {
@ -162,16 +152,15 @@ describe('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => {
});
cy.contains('Unique identifier of the us').should('not.exist');
cy.contains('User ID').should('not.exist');
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.get(`[aria-labelledby="flyoutTitle"]`).contains('Save').click();
cy.get(`[aria-label="Edit users_elastic"]`).click();
cy.react('CustomItemAction', {
props: { index: 0, item: { id: 'users_elastic' } },
}).click();
cy.contains('SELECT * FROM users;where name=1');
cy.contains('Unique identifier of the us.').should('not.exist');
cy.contains('User ID').should('not.exist');
cy.contains('Differential (Ignore removals)').should('exist');
cy.react('EuiFlyoutFooter').react('EuiButtonEmpty').contains('Cancel').click();
cy.get(`[aria-labelledby="flyoutTitle"]`).contains('Cancel').click();
});
});
});

View file

@ -5,10 +5,14 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { takeOsqueryActionWithParams } from '../../tasks/live_query';
import { ServerlessRoleName } from '../../support/roles';
describe.skip('ALL - Timelines', { tags: ['@ess'] }, () => {
before(() => {
initializeDataViews();
});
beforeEach(() => {
cy.login(ServerlessRoleName.SOC_MANAGER);
});

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { initializeDataViews } from '../../tasks/login';
import { checkResults, clickRuleName, submitQuery } from '../../tasks/live_query';
import { loadRule, cleanupRule } from '../../tasks/api_fixtures';
import { ServerlessRoleName } from '../../support/roles';
@ -14,6 +15,7 @@ describe('Alert Test', { tags: ['@ess'] }, () => {
let ruleId: string;
before(() => {
initializeDataViews();
loadRule().then((data) => {
ruleName = data.name;
ruleId = data.id;

View file

@ -6,6 +6,7 @@
*/
import { defineCypressConfig } from '@kbn/cypress-config';
import { getFailedSpecVideos } from './support/filter_videos';
import { setupUserDataLoader } from '../../../test_serverless/functional/test_suites/security/cypress/support/setup_data_loader_tasks';
// eslint-disable-next-line import/no-default-export
@ -21,7 +22,9 @@ export default defineCypressConfig({
responseTimeout: 60000,
screenshotsFolder: '../../../target/kibana-osquery/cypress/screenshots',
trashAssetsBeforeRuns: false,
video: false,
video: true,
videosFolder: '../../../target/kibana-osquery/cypress/videos',
videoCompression: 15,
viewportHeight: 946,
viewportWidth: 1680,
@ -40,6 +43,7 @@ export default defineCypressConfig({
numTestsKeptInMemory: 3,
setupNodeEvents: (on, config) => {
setupUserDataLoader(on, config, { additionalRoleName: 'viewer' });
on('after:spec', getFailedSpecVideos);
return config;
},

View file

@ -23,6 +23,7 @@
// ***********************************************************
// force ESM in this module
export {};
// @ts-expect-error ts(2306) module has some interesting ways of importing, see https://github.com/cypress-io/cypress/blob/0871b03c5b21711cd23056454da8f23dcaca4950/npm/grep/README.md#support-file
@ -33,7 +34,7 @@ registerCypressGrep();
import type { SecuritySolutionDescribeBlockFtrConfig } from '@kbn/security-solution-plugin/scripts/run_cypress/utils';
import { login } from '@kbn/security-solution-plugin/public/management/cypress/tasks/login';
import { ServerlessRoleName } from './roles';
import type { ServerlessRoleName } from './roles';
import 'cypress-react-selector';
import { waitUntil } from '../tasks/wait_until';
@ -92,12 +93,3 @@ Cypress.Commands.add('waitUntil', waitUntil);
// Alternatively you can use CommonJS syntax:
// require('./commands')
Cypress.on('uncaught:exception', () => false);
// Login as a SOC_MANAGER to properly initialize Security Solution App
before(() => {
cy.login(ServerlessRoleName.SOC_MANAGER);
cy.visit('/app/security/alerts');
cy.getBySel('globalLoadingIndicator').should('exist');
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('manage-alert-detection-rules').should('exist');
});

View file

@ -0,0 +1,21 @@
/*
* 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 fs from 'fs';
// makes sure we save videos just for failed specs
export const getFailedSpecVideos = (spec: Cypress.Spec, results: CypressCommandLine.RunResult) => {
if (results && results.video) {
// Do we have failures for any retry attempts?
const failures = results.tests.some((test) =>
test.attempts.some((attempt) => attempt.state === 'failed')
);
if (!failures) {
// delete the video if the spec passed and no tests retried
fs.unlinkSync(results.video);
}
}
};

View file

@ -54,7 +54,8 @@ export const integrationExistsWithinPolicyDetails = (integrationName: string) =>
};
export const interceptAgentPolicyId = (cb: (policyId: string) => void) => {
cy.intercept('POST', '**/api/fleet/agent_policies**', (req) => {
// create policy has agent_policies?SOMEPARAMS=true , this ? helps to distinguish it from the delete agent_policies/delete route
cy.intercept('POST', '**/api/fleet/agent_policies?**', (req) => {
req.continue((res) => {
cb(res.body.item.id);

View file

@ -9,7 +9,15 @@ export const triggerLoadData = () => {
cy.getBySel('infraWaffleTimeControlsAutoRefreshButton').should('exist');
cy.wait(1000);
cy.getBySel('infraWaffleTimeControlsAutoRefreshButton').click();
cy.getBySel('nodeContainer').last().should('exist');
// @ts-expect-error update types for multiple true
cy.getBySel('nodeContainer', { multiple: true })
.not(':contains("dev-fleet-server")')
.first()
.should('exist');
cy.getBySel('infraWaffleTimeControlsStopRefreshingButton').click();
cy.getBySel('nodeContainer').last().click();
// @ts-expect-error update types for multiple true
cy.getBySel('nodeContainer', { multiple: true })
.not(':contains("dev-fleet-server")')
.first()
.click();
};

View file

@ -80,9 +80,9 @@ export const findFormFieldByRowsLabelAndType = (label: string, text: string) =>
};
export const deleteAndConfirm = (type: string) => {
cy.react('EuiButton').contains(`Delete ${type}`).click();
cy.get('span').contains(`Delete ${type}`).click();
cy.contains(`Are you sure you want to delete this ${type}?`);
cy.react('EuiButton').contains('Confirm').click();
cy.get('span').contains('Confirm').click();
cy.get('[data-test-subj="globalToastList"]')
.first()
.contains('Successfully deleted')

View file

@ -0,0 +1,17 @@
/*
* 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 { ServerlessRoleName } from '../support/roles';
// Login as a SOC_MANAGER to properly initialize Security Solution App
export const initializeDataViews = () => {
cy.login(ServerlessRoleName.SOC_MANAGER);
cy.visit('/app/security/alerts');
cy.getBySel('globalLoadingIndicator').should('exist');
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('manage-alert-detection-rules').should('exist');
};

View file

@ -24,6 +24,19 @@ export const navigateTo = (page: string, opts?: Partial<Cypress.VisitOptions>) =
waitForReact();
};
// We're moving away from using react-cypress-selector, I'll be adjusting this on file by file approach
export const navigateToWithoutWaitForReact = (
page: string,
opts?: Partial<Cypress.VisitOptions>
) => {
cy.visit(page, opts);
cy.contains('Loading Elastic').should('exist');
cy.contains('Loading Elastic').should('not.exist');
// There's a security warning toast that seemingly makes ui elements in the bottom right unavailable, so we close it
closeToastIfVisible();
};
export const waitForReact = () => {
cy.waitForReact(
10000,

View file

@ -20,26 +20,16 @@ export const preparePack = (packName: string) => {
createdPack.click();
};
export const deactivatePack = (packName: string) => {
cy.react('ActiveStateSwitchComponent', {
props: { item: { name: packName } },
}).click();
export const changePackActiveStatus = (packName: string) => {
const regex = new RegExp(`Successfully (activated|deactivated) "${packName}" pack`);
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.get(`[aria-label="${packName}"]`).click();
closeModalIfVisible();
cy.contains(`Successfully deactivated "${packName}" pack`).should('not.exist');
cy.contains(`Successfully deactivated "${packName}" pack`).should('exist');
closeToastIfVisible();
};
export const activatePack = (packName: string) => {
cy.react('ActiveStateSwitchComponent', {
props: { item: { name: packName } },
}).click();
closeModalIfVisible();
cy.contains(`Successfully activated "${packName}" pack`).should('not.exist');
cy.contains(`Successfully activated "${packName}" pack`).should('exist');
cy.contains(regex).should('not.exist');
cy.contains(regex).should('exist');
closeToastIfVisible();
cy.contains(regex).should('not.exist');
};
export const cleanupAllPrebuiltPacks = () => {

View file

@ -6,7 +6,7 @@
*/
export const waitUntil = (fn: () => Cypress.Chainable) => {
const timeout = 90000;
const timeout = 120000;
const interval = 5000;
let attempts = timeout / interval;

View file

@ -96,6 +96,7 @@ const ActiveStateSwitchComponent: React.FC<ActiveStateSwitchProps> = ({ item })
checked={!!item.enabled}
disabled={!permissions.writePacks || isLoading}
showLabel={false}
aria-label={item.name}
label=""
onChange={handleToggleActiveClick}
/>

View file

@ -25,6 +25,7 @@ const AddPackButtonComponent: React.FC<AddPackButtonComponentProps> = ({ fill =
{...newQueryLinkProps}
iconType="plusInCircle"
isDisabled={!permissions.writePacks}
data-test-subj={'addPackButton'}
>
<FormattedMessage id="xpack.osquery.packList.addPackButtonLabel" defaultMessage="Add pack" />
</EuiButton>

View file

@ -315,6 +315,7 @@ const PackFormComponent: React.FC<PackFormProps> = ({
size="m"
iconType="save"
onClick={handleSaveClick}
data-test-subj={`${editMode ? 'update' : 'save'}PackButton`}
>
{editMode ? (
<FormattedMessage

View file

@ -5,23 +5,33 @@
* 2.0.
*/
import { ToolingLog } from '@kbn/tooling-log';
import execa from 'execa';
import { ToolingLog } from '@kbn/tooling-log';
import { KbnClient } from '@kbn/test';
import { waitForHostToEnroll } from '@kbn/security-solution-plugin/scripts/endpoint/common/fleet_services';
import { getLatestVersion } from './artifact_manager';
import { Manager } from './resource_manager';
import { generateRandomString } from './utils';
export class AgentManager extends Manager {
private log: ToolingLog;
private policyEnrollmentKey: string;
private fleetServerPort: string;
private agentContainerId?: string;
private kbnClient: KbnClient;
constructor(policyEnrollmentKey: string, fleetServerPort: string, log: ToolingLog) {
constructor(
policyEnrollmentKey: string,
fleetServerPort: string,
log: ToolingLog,
kbnClient: KbnClient
) {
super();
this.log = log;
this.fleetServerPort = fleetServerPort;
this.policyEnrollmentKey = policyEnrollmentKey;
this.kbnClient = kbnClient;
}
public async setup() {
@ -29,6 +39,7 @@ export class AgentManager extends Manager {
const artifact = `docker.elastic.co/beats/elastic-agent:${await getLatestVersion()}`;
this.log.info(artifact);
const containerName = generateRandomString(12);
const dockerArgs = [
'run',
@ -37,6 +48,10 @@ export class AgentManager extends Manager {
'--detach',
'--add-host',
'host.docker.internal:host-gateway',
'--name',
containerName,
'--hostname',
containerName,
'--env',
'FLEET_ENROLL=1',
'--env',
@ -50,6 +65,7 @@ export class AgentManager extends Manager {
];
this.agentContainerId = (await execa('docker', dockerArgs)).stdout;
await waitForHostToEnroll(this.kbnClient, containerName);
}
public cleanup() {

View file

@ -48,12 +48,10 @@ async function setupFleetAgent({ getService }: FtrProviderContext) {
const policyEnrollmentKey = await createAgentPolicy(kbnClient, log, 'Default policy');
const policyEnrollmentKeyTwo = await createAgentPolicy(kbnClient, log, 'Osquery policy');
await new AgentManager(policyEnrollmentKey, config.get('servers.fleetserver.port'), log).setup();
await new AgentManager(
policyEnrollmentKeyTwo,
config.get('servers.fleetserver.port'),
log
).setup();
const port = config.get('servers.fleetserver.port');
await new AgentManager(policyEnrollmentKey, port, log, kbnClient).setup();
await new AgentManager(policyEnrollmentKeyTwo, port, log, kbnClient).setup();
}
export async function startOsqueryCypress(context: FtrProviderContext) {

View file

@ -137,3 +137,7 @@ export const getLatestAvailableAgentVersion = async (kbnClient: KbnClient): Prom
return version;
};
export const generateRandomString = (length: number) => {
return [...Array(length)].map(() => Math.random().toString(36)[2]).join('');
};