[8.10] Fix osquery cypress tests (#163988) (#164248)

# Backport

This will backport the following commits from `main` to `8.10`:
- [Fix osquery cypress tests
(#163988)](https://github.com/elastic/kibana/pull/163988)

<!--- Backport version: 8.9.7 -->

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

<!--BACKPORT [{"author":{"name":"Patryk
Kopyciński","email":"contact@patrykkopycinski.com"},"sourceCommit":{"committedDate":"2023-08-16T22:11:05Z","message":"Fix
osquery cypress tests (#163988)\n\n## Summary\r\n\r\nAdjust tests to
https://github.com/elastic/kibana/pull/161614\r\nSplit tests into
smaller files to better utilize parallelization and\r\nincrease the
stability of
tests","sha":"fd33ed55fd9bc81d006ca41c85b7bd4117741e80","branchLabelMapping":{"^v8.10.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport:prev-minor","v8.10.0","v8.11.0"],"number":163988,"url":"https://github.com/elastic/kibana/pull/163988","mergeCommit":{"message":"Fix
osquery cypress tests (#163988)\n\n## Summary\r\n\r\nAdjust tests to
https://github.com/elastic/kibana/pull/161614\r\nSplit tests into
smaller files to better utilize parallelization and\r\nincrease the
stability of
tests","sha":"fd33ed55fd9bc81d006ca41c85b7bd4117741e80"}},"sourceBranch":"main","suggestedTargetBranches":["8.11"],"targetPullRequestStates":[{"branch":"main","label":"v8.10.0","labelRegex":"^v8.10.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/163988","number":163988,"mergeCommit":{"message":"Fix
osquery cypress tests (#163988)\n\n## Summary\r\n\r\nAdjust tests to
https://github.com/elastic/kibana/pull/161614\r\nSplit tests into
smaller files to better utilize parallelization and\r\nincrease the
stability of
tests","sha":"fd33ed55fd9bc81d006ca41c85b7bd4117741e80"}},{"branch":"8.11","label":"v8.11.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Patryk Kopyciński <contact@patrykkopycinski.com>
This commit is contained in:
Kibana Machine 2023-08-18 15:10:11 -04:00 committed by GitHub
parent 2b5b603171
commit f8121b897d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 1628 additions and 1662 deletions

View file

@ -12,3 +12,13 @@ steps:
limit: 1
artifact_paths:
- "target/kibana-osquery/**/*"
- command: .buildkite/scripts/steps/functional/osquery_cypress_burn.sh
label: 'Osquery Cypress Tests, burning changed specs'
agents:
queue: n2-4-spot
depends_on: build
timeout_in_minutes: 50
soft_fail: true
artifact_paths:
- "target/kibana-osquery/**/*"

View file

@ -80,6 +80,7 @@ const uploadPipeline = (pipelineContent: string | object) => {
getPipeline('.buildkite/pipelines/pull_request/security_solution_explore.yml')
);
pipeline.push(getPipeline('.buildkite/pipelines/pull_request/defend_workflows.yml'));
pipeline.push(getPipeline('.buildkite/pipelines/pull_request/osquery_cypress.yml'));
}
if (
@ -200,7 +201,8 @@ const uploadPipeline = (pipelineContent: string | object) => {
pipeline.push(getPipeline('.buildkite/pipelines/pull_request/post_build.yml'));
uploadPipeline(pipeline.join('\n'));
// remove duplicated steps
uploadPipeline([...new Set(pipeline)].join('\n'));
} catch (ex) {
console.error('PR pipeline generation error', ex.message);
process.exit(1);

View file

@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
source .buildkite/scripts/common/util.sh
source .buildkite/scripts/steps/functional/common_cypress.sh
.buildkite/scripts/bootstrap.sh
node scripts/build_kibana_platform_plugins.js
export JOB=kibana-osquery-cypress
buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" 'false'
echo "--- Osquery Cypress tests, burning changed specs (Chrome)"
yarn --cwd x-pack/plugins/osquery cypress:changed-specs-only

View file

@ -36,6 +36,6 @@ export default defineCypressConfig({
baseUrl: 'http://localhost:5601',
experimentalRunAllSpecs: true,
experimentalMemoryManagement: true,
numTestsKeptInMemory: 10,
numTestsKeptInMemory: 3,
},
});

View file

@ -1,721 +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 {
cleanupCase,
cleanupPack,
cleanupRule,
loadCase,
loadPack,
loadRule,
multiQueryPackFixture,
packFixture,
} from '../../tasks/api_fixtures';
import {
RESPONSE_ACTIONS_ITEM_0,
RESPONSE_ACTIONS_ITEM_1,
RESPONSE_ACTIONS_ITEM_2,
OSQUERY_RESPONSE_ACTION_ADD_BUTTON,
} from '../../tasks/response_actions';
import { ROLE, login } from '../../tasks/login';
import {
addToCase,
checkActionItemsInResults,
findAndClickButton,
findFormFieldByRowsLabelAndType,
inputQuery,
loadRuleAlerts,
submitQuery,
takeOsqueryActionWithParams,
toggleRuleOffAndOn,
typeInECSFieldInput,
viewRecentCaseAndCheckResults,
} from '../../tasks/live_query';
import { preparePack } from '../../tasks/packs';
import {
closeDateTabIfVisible,
closeModalIfVisible,
closeToastIfVisible,
generateRandomStringName,
interceptCaseId,
} from '../../tasks/integrations';
import { navigateTo } from '../../tasks/navigation';
import { RESULTS_TABLE, RESULTS_TABLE_BUTTON } from '../../screens/live_query';
import { OSQUERY_POLICY } from '../../screens/fleet';
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}';
describe('Alert Event Details', () => {
beforeEach(() => {
login(ROLE.soc_manager);
});
describe('Packs and rules creation', () => {
let ruleId: string;
let ruleName: string;
let packId: string;
let packName: string;
const packData = packFixture();
before(() => {
loadPack(packData).then((data) => {
packId = data.saved_object_id;
packName = data.name;
});
loadRule().then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupPack(packId);
cleanupRule(ruleId);
});
it('should prepare packs and alert rules', () => {
navigateTo('/app/osquery/live_queries');
preparePack(packName);
findAndClickButton('Edit');
cy.contains(`Edit ${packName}`);
findFormFieldByRowsLabelAndType(
'Scheduled agent policies (optional)',
`${OSQUERY_POLICY}{downArrow}{enter}`
);
findAndClickButton('Update pack');
closeModalIfVisible();
cy.contains(`Successfully updated "${packName}" pack`);
closeToastIfVisible();
toggleRuleOffAndOn(ruleName);
});
});
describe.skip('Response actions', () => {
let multiQueryPackId: string;
let multiQueryPackName: string;
let ruleId: string;
let ruleName: string;
let packId: string;
let packName: string;
const packData = packFixture();
const multiQueryPackData = multiQueryPackFixture();
beforeEach(() => {
loadPack(packData).then((data) => {
packId = data.saved_object_id;
packName = data.name;
});
loadPack(multiQueryPackData).then((data) => {
multiQueryPackId = data.saved_object_id;
multiQueryPackName = data.name;
});
loadRule().then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
afterEach(() => {
cleanupPack(packId);
cleanupPack(multiQueryPackId);
cleanupRule(ruleId);
});
it('adds response actions with osquery with proper validation and form values', () => {
cy.visit('/app/security/rules');
cy.contains(ruleName).click();
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
closeDateTabIfVisible();
cy.getBySel('edit-rule-actions-tab').click();
cy.contains('Response actions are run on each rule execution.');
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains('Query is a required field');
inputQuery('select * from uptime1');
});
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('Run a set of queries in a pack').click();
});
cy.contains('Save changes').click();
cy.getBySel('response-actions-error')
.within(() => {
cy.contains('Pack is a required field');
})
.should('exist');
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('Pack is a required field');
cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`);
});
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('Advanced').click();
typeInECSFieldInput('message{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('ruleEditSubmitButton').click();
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains('select * from uptime1');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_2).within(() => {
cy.contains('select * from uptime');
cy.contains('Log message optimized for viewing in a log viewer');
cy.contains('Days of uptime');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains(packName);
cy.getBySel('comboBoxInput').type('{backspace}{enter}');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
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_1).within(() => {
cy.contains('select * from uptime');
cy.contains('Log message optimized for viewing in a log viewer');
cy.contains('Days of uptime');
});
cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleSingleQuery');
cy.getBySel('ruleEditSubmitButton').click();
cy.wait('@saveRuleSingleQuery').should(({ request }) => {
const oneQuery = [
{
interval: 3600,
query: 'select * from uptime;',
id: Object.keys(packData.queries)[0],
},
];
expect(request.body.response_actions[0].params.queries).to.deep.equal(oneQuery);
});
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains(packName);
cy.getBySel('comboBoxInput').type(`${multiQueryPackName}{downArrow}{enter}`);
checkActionItemsInResults({
cases: false,
lens: false,
discover: false,
timeline: false,
});
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('select * from uptime');
cy.contains('Log message optimized for viewing in a log viewer');
cy.contains('Days of uptime');
});
cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleMultiQuery');
cy.contains('Save changes').click();
cy.wait('@saveRuleMultiQuery').should(({ request }) => {
const threeQueries = [
{
interval: 3600,
query: 'SELECT * FROM memory_info;',
platform: 'linux',
id: Object.keys(multiQueryPackData.queries)[0],
},
{
interval: 3600,
query: 'SELECT * FROM system_info;',
id: Object.keys(multiQueryPackData.queries)[1],
},
{
interval: 10,
query: 'select opera_extensions.* from users join opera_extensions using (uid);',
id: Object.keys(multiQueryPackData.queries)[2],
},
];
expect(request.body.response_actions[0].params.queries).to.deep.equal(threeQueries);
});
});
});
describe('investigation guide', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule().then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('should be able to add investigation guides to response actions', () => {
const investigationGuideNote =
'You have queries in the investigation guide. Add them as response actions?';
cy.visit('/app/security/rules');
cy.contains(ruleName).click();
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
cy.contains(investigationGuideNote);
cy.getBySel('osqueryAddInvestigationGuideQueries').click();
cy.contains(investigationGuideNote).should('not.exist');
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains("SELECT * FROM os_version where name='{{host.os.name}}';");
cy.contains('host.os.platform');
cy.contains('platform');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('select * from users');
});
cy.contains('Save changes').click();
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
});
});
describe('timeline', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule().then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('should be able to run live query and add to timeline (-depending on the previous test)', () => {
const TIMELINE_NAME = 'Untitled timeline';
loadRuleAlerts(ruleName);
cy.getBySel('timeline-context-menu-button').first().click();
cy.contains('Run Osquery');
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('osquery-action-item').click();
cy.contains('1 agent selected.');
inputQuery('select * from uptime;');
submitQuery();
cy.contains('Results');
cy.contains('Add to timeline investigation');
cy.contains('Save for later').click();
cy.contains('Save query');
cy.get('[data-test-subj="osquery-save-query-flyout"]').within(() => {
cy.get('.euiButtonEmpty').contains('Cancel').click();
});
cy.getBySel('add-to-timeline').first().click();
cy.getBySel('globalToastList').contains('Added');
closeToastIfVisible();
cy.getBySel(RESULTS_TABLE).within(() => {
cy.getBySel(RESULTS_TABLE_BUTTON).should('not.exist');
});
cy.contains('Cancel').click();
cy.getBySel('flyoutBottomBar').within(() => {
cy.contains(TIMELINE_NAME).click();
});
cy.getBySel('draggableWrapperKeyboardHandler').contains('action_id: "');
// timeline unsaved changes modal
cy.visit('/app/osquery');
closeModalIfVisible();
});
});
describe('substitute params', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule().then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('should substitute parameters in investigation guide', () => {
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click();
cy.contains('Get processes').click();
cy.getBySel('flyout-body-osquery').within(() => {
cy.contains("SELECT * FROM os_version where name='Ubuntu';");
cy.contains('host.os.platform');
cy.contains('platform');
});
});
});
describe.skip('Case creation', () => {
let ruleId: string;
let ruleName: string;
let packId: string;
let packName: string;
let caseId: string;
const packData = packFixture();
before(() => {
loadPack(packData).then((data) => {
packId = data.saved_object_id;
packName = data.name;
});
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
interceptCaseId((id) => {
caseId = id;
});
});
after(() => {
cleanupPack(packId);
cleanupRule(ruleId);
cleanupCase(caseId);
});
it('runs osquery against alert and creates a new case', () => {
const [caseName, caseDescription] = generateRandomStringName(2);
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click({ force: true });
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('osquery-action-item').click();
cy.contains('Run a set of queries in a pack').wait(500).click();
cy.getBySel('select-live-pack').within(() => {
cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`);
});
submitQuery();
cy.get('[aria-label="Add to Case"]').first().click();
cy.getBySel('cases-table-add-case-filter-bar').click();
cy.getBySel('create-case-flyout').should('be.visible');
cy.getBySel('caseTitle').within(() => {
cy.getBySel('input').type(caseName);
});
cy.getBySel('caseDescription').within(() => {
cy.getBySel('euiMarkdownEditorTextArea').type(caseDescription);
});
cy.getBySel('create-case-submit').click();
cy.contains(`An alert was added to "${caseName}"`);
});
});
describe('Case', () => {
let ruleId: string;
let ruleName: string;
let caseId: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
loadCase('securitySolution').then((data) => {
caseId = data.id;
});
});
after(() => {
cleanupRule(ruleId);
cleanupCase(caseId);
});
it('sees osquery results from last action and add to a case', () => {
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click();
cy.getBySel('responseActionsViewTab').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
cy.contains('select * from users;');
cy.contains("SELECT * FROM os_version where name='Ubuntu';");
cy.getBySel('osquery-results-comment').each(($comment) => {
cy.wrap($comment).within(() => {
// On initial load result table might not render due to displayed error
if ($comment.find('div .euiDataGridRow').length <= 0) {
// If tabs are present try clicking between status and results to get rid of the error message
if ($comment.find('div .euiTabs').length > 0) {
cy.getBySel('osquery-status-tab').click();
cy.getBySel('osquery-results-tab').click();
cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0);
}
} else {
// Result tab was rendered successfully
cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0);
}
// }
});
});
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
addToCase(caseId);
viewRecentCaseAndCheckResults();
});
});
describe('Discover', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('can visit discover from response action results', () => {
const discoverRegex = new RegExp(`action_id: ${UUID_REGEX}`);
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click();
cy.getBySel('responseActionsViewTab').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
cy.contains('View in Discover')
.should('exist')
.should('have.attr', 'href')
.then(($href) => {
// @ts-expect-error-next-line href string - check types
cy.visit($href);
cy.getBySel('breadcrumbs').contains('Discover').should('exist');
cy.getBySel('discoverDocTable', { timeout: 60000 }).within(() => {
cy.contains(`action_data.query`);
});
cy.contains(discoverRegex);
});
});
});
describe('Lens', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('can visit lens from response action results', () => {
const lensRegex = new RegExp(`Action ${UUID_REGEX} results`);
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click();
cy.getBySel('responseActionsViewTab').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
cy.getBySel('osquery-results-comment')
.first()
.within(() => {
let lensUrl = '';
cy.window().then((win) => {
cy.stub(win, 'open')
.as('windowOpen')
.callsFake((url) => {
lensUrl = url;
});
});
cy.get(`[aria-label="View in Lens"]`).click();
cy.window()
.its('open')
.then(() => {
cy.visit(lensUrl);
});
});
cy.getBySel('lnsWorkspace').should('exist');
cy.getBySel('breadcrumbs').contains(lensRegex);
});
});
describe('Timeline', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('can add to timeline from response action results', () => {
const timelineRegex = new RegExp(`Added ${UUID_REGEX} to timeline`);
const filterRegex = new RegExp(`action_id: "${UUID_REGEX}"`);
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click();
cy.getBySel('responseActionsViewTab').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
cy.getBySel('osquery-results-comment')
.first()
.within(() => {
cy.get('.euiTableRow')
.first()
.within(() => {
cy.getBySel('add-to-timeline').click();
});
});
cy.contains(timelineRegex);
cy.getBySel('flyoutBottomBar').contains('Untitled timeline').click();
cy.contains(filterRegex);
});
});
describe('Params', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('should substitute parameters in live query and increase number of ran queries', () => {
let initialNotificationCount: number;
let updatedNotificationCount: number;
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click();
cy.getBySel('response-actions-notification')
.should('not.have.text', '0')
.then((element) => {
initialNotificationCount = parseInt(element.text(), 10);
});
takeOsqueryActionWithParams();
cy.getBySel('osquery-empty-button').click();
cy.getBySel('response-actions-notification')
.should('not.have.text', '0')
.then((element) => {
updatedNotificationCount = parseInt(element.text(), 10);
expect(initialNotificationCount).to.be.equal(updatedNotificationCount - 1);
})
.then(() => {
cy.getBySel('responseActionsViewTab').click();
cy.getBySel('responseActionsViewWrapper').within(() => {
cy.contains('tags');
cy.getBySel('osquery-results-comment').should('have.length', updatedNotificationCount);
});
});
});
});
describe('Multiple agents', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('should be able to run take action query against all enrolled agents', () => {
loadRuleAlerts(ruleName);
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('osquery-action-item').click();
cy.getBySel('agentSelection').within(() => {
cy.getBySel('comboBoxClearButton').click();
cy.getBySel('comboBoxInput').type('All{downArrow}{enter}{esc}');
cy.contains('All agents');
});
inputQuery("SELECT * FROM os_version where name='{{host.os.name}}';", {
parseSpecialCharSequences: false,
});
cy.wait(1000);
submitQuery();
cy.getBySel('flyout-body-osquery').within(() => {
// at least 2 agents should have responded, sometimes it takes a while for the agents to respond
cy.get('[data-grid-row-index]', { timeout: 6000000 }).should('have.length.at.least', 2);
});
});
});
describe('Params in timeline', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});
after(() => {
cleanupRule(ruleId);
});
it('should substitute params in osquery ran from timelines alerts', () => {
loadRuleAlerts(ruleName);
cy.getBySel('send-alert-to-timeline-button').first().click();
cy.getBySel('query-events-table').within(() => {
cy.getBySel('expand-event').first().click();
});
takeOsqueryActionWithParams();
});
});
});

View file

@ -0,0 +1,141 @@
/*
* 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 {
cleanupCase,
cleanupPack,
cleanupRule,
loadCase,
loadPack,
loadRule,
packFixture,
} from '../../tasks/api_fixtures';
import { ROLE, login } from '../../tasks/login';
import {
addToCase,
checkActionItemsInResults,
loadRuleAlerts,
submitQuery,
viewRecentCaseAndCheckResults,
} from '../../tasks/live_query';
import { generateRandomStringName, interceptCaseId } from '../../tasks/integrations';
describe('Alert Event Details - Cases', () => {
let ruleId: string;
let ruleName: string;
let packId: string;
let packName: string;
const packData = packFixture();
before(() => {
loadPack(packData).then((data) => {
packId = data.saved_object_id;
packName = data.name;
});
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
loadRuleAlerts(data.name);
});
});
beforeEach(() => {
login(ROLE.soc_manager);
cy.visit('/app/security/rules');
cy.contains(ruleName).click();
});
after(() => {
cleanupPack(packId);
cleanupRule(ruleId);
});
describe('Case creation', () => {
let caseId: string;
before(() => {
interceptCaseId((id) => {
caseId = id;
});
});
after(() => {
cleanupCase(caseId);
});
it('runs osquery against alert and creates a new case', () => {
const [caseName, caseDescription] = generateRandomStringName(2);
cy.getBySel('expand-event').first().click({ force: true });
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('osquery-action-item').click();
cy.contains('Run a set of queries in a pack').wait(500).click();
cy.getBySel('select-live-pack').within(() => {
cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`);
});
submitQuery();
cy.get('[aria-label="Add to Case"]').first().click();
cy.getBySel('cases-table-add-case-filter-bar').click();
cy.getBySel('create-case-flyout').should('be.visible');
cy.getBySel('caseTitle').within(() => {
cy.getBySel('input').type(caseName);
});
cy.getBySel('caseDescription').within(() => {
cy.getBySel('euiMarkdownEditorTextArea').type(caseDescription);
});
cy.getBySel('create-case-submit').click();
cy.contains(`An alert was added to "${caseName}"`);
});
});
describe('Case', () => {
let caseId: string;
before(() => {
loadCase('securitySolution').then((data) => {
caseId = data.id;
});
});
after(() => {
cleanupCase(caseId);
});
it('sees osquery results from last action and add to a case', () => {
cy.getBySel('expand-event').first().click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
cy.contains('select * from users;');
cy.contains("SELECT * FROM os_version where name='Ubuntu';");
cy.getBySel('osquery-results-comment').each(($comment) => {
cy.wrap($comment).within(() => {
// On initial load result table might not render due to displayed error
if ($comment.find('div .euiDataGridRow').length <= 0) {
// If tabs are present try clicking between status and results to get rid of the error message
if ($comment.find('div .euiTabs').length > 0) {
cy.getBySel('osquery-status-tab').click();
cy.getBySel('osquery-results-tab').click();
cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0);
}
} else {
// Result tab was rendered successfully
cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0);
}
// }
});
});
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
addToCase(caseId);
viewRecentCaseAndCheckResults();
});
});
});

View file

@ -0,0 +1,188 @@
/*
* 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 { cleanupRule, loadRule } from '../../tasks/api_fixtures';
import { RESPONSE_ACTIONS_ITEM_0, RESPONSE_ACTIONS_ITEM_1 } from '../../tasks/response_actions';
import { ROLE, login } from '../../tasks/login';
import {
checkActionItemsInResults,
inputQuery,
loadRuleAlerts,
submitQuery,
} from '../../tasks/live_query';
import { closeModalIfVisible, closeToastIfVisible } from '../../tasks/integrations';
import { RESULTS_TABLE, RESULTS_TABLE_BUTTON } from '../../screens/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}';
describe('Alert Event Details', { browser: 'electron' }, () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule().then((data) => {
ruleId = data.id;
ruleName = data.name;
loadRuleAlerts(data.name);
});
});
after(() => {
cleanupRule(ruleId);
});
beforeEach(() => {
login(ROLE.soc_manager);
cy.visit('/app/security/rules');
cy.contains(ruleName).click();
});
it('should be able to add investigation guides to response actions', () => {
const investigationGuideNote =
'You have queries in the investigation guide. Add them as response actions?';
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
cy.contains(investigationGuideNote);
cy.getBySel('osqueryAddInvestigationGuideQueries').click();
cy.contains(investigationGuideNote).should('not.exist');
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains("SELECT * FROM os_version where name='{{host.os.name}}';");
cy.contains('host.os.platform');
cy.contains('platform');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('select * from users');
});
cy.contains('Save changes').click();
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
});
it('should be able to run live query and add to timeline', () => {
const TIMELINE_NAME = 'Untitled timeline';
cy.getBySel('timeline-context-menu-button').first().click();
cy.contains('Run Osquery');
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('osquery-action-item').click();
cy.contains('1 agent selected.');
inputQuery('select * from uptime;');
submitQuery();
cy.contains('Results');
cy.contains('Add to timeline investigation');
cy.contains('Save for later').click();
cy.contains('Save query');
cy.get('[data-test-subj="osquery-save-query-flyout"]').within(() => {
cy.get('.euiButtonEmpty').contains('Cancel').click();
});
cy.getBySel('add-to-timeline').first().click();
cy.getBySel('globalToastList').contains('Added');
closeToastIfVisible();
cy.getBySel(RESULTS_TABLE).within(() => {
cy.getBySel(RESULTS_TABLE_BUTTON).should('not.exist');
});
cy.contains('Cancel').click();
cy.getBySel('flyoutBottomBar').within(() => {
cy.contains(TIMELINE_NAME).click();
});
cy.getBySel('draggableWrapperKeyboardHandler').contains('action_id: "');
// timeline unsaved changes modal
cy.visit('/app/osquery');
closeModalIfVisible();
});
it('can visit discover from response action results', () => {
const discoverRegex = new RegExp(`action_id: ${UUID_REGEX}`);
cy.getBySel('expand-event').first().click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
cy.contains('View in Discover')
.should('exist')
.should('have.attr', 'href')
.then(($href) => {
// @ts-expect-error-next-line href string - check types
cy.visit($href);
cy.getBySel('breadcrumbs').contains('Discover').should('exist');
cy.getBySel('discoverDocTable', { timeout: 60000 }).within(() => {
cy.contains(`action_data.query`);
});
cy.contains(discoverRegex);
});
});
it('can visit lens from response action results', () => {
const lensRegex = new RegExp(`Action ${UUID_REGEX} results`);
cy.getBySel('expand-event').first().click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
cy.getBySel('osquery-results-comment')
.first()
.within(() => {
let lensUrl = '';
cy.window().then((win) => {
cy.stub(win, 'open')
.as('windowOpen')
.callsFake((url) => {
lensUrl = url;
});
});
cy.get(`[aria-label="View in Lens"]`).click();
cy.window()
.its('open')
.then(() => {
cy.visit(lensUrl);
});
});
cy.getBySel('lnsWorkspace').should('exist');
cy.getBySel('breadcrumbs').contains(lensRegex);
});
it('can add to timeline from response action results', () => {
const timelineRegex = new RegExp(`Added ${UUID_REGEX} to timeline`);
const filterRegex = new RegExp(`action_id: "${UUID_REGEX}"`);
cy.getBySel('expand-event').first().click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click();
cy.getBySel('responseActionsViewWrapper').should('exist');
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: true,
});
cy.getBySel('osquery-results-comment')
.first()
.within(() => {
cy.get('.euiTableRow')
.first()
.within(() => {
cy.getBySel('add-to-timeline').click();
});
});
cy.contains(timelineRegex);
cy.getBySel('securitySolutionDocumentDetailsFlyoutHeaderCollapseDetailButton').click();
cy.getBySel('flyoutBottomBar').contains('Untitled timeline').click();
cy.contains(filterRegex);
});
});

View file

@ -0,0 +1,106 @@
/*
* 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 { cleanupRule, loadRule } from '../../tasks/api_fixtures';
import { ROLE, login } from '../../tasks/login';
import {
inputQuery,
loadRuleAlerts,
submitQuery,
takeOsqueryActionWithParams,
} from '../../tasks/live_query';
describe('Alert Event Details - dynamic params', () => {
let ruleId: string;
let ruleName: string;
before(() => {
loadRule(true).then((data) => {
ruleId = data.id;
ruleName = data.name;
loadRuleAlerts(data.name);
});
});
after(() => {
cleanupRule(ruleId);
});
beforeEach(() => {
login(ROLE.soc_manager);
cy.visit('/app/security/rules');
cy.contains(ruleName).click();
});
it('should substitute parameters in investigation guide', () => {
cy.getBySel('expand-event').first().click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutInvestigationGuideButton').click();
cy.contains('Get processes').click();
cy.getBySel('flyout-body-osquery').within(() => {
cy.contains("SELECT * FROM os_version where name='Ubuntu';");
cy.contains('host.os.platform');
cy.contains('platform');
});
});
// response-actions-notification doesn't exist in expandable flyout
it.skip('should substitute parameters in live query and increase number of ran queries', () => {
let initialNotificationCount: number;
let updatedNotificationCount: number;
cy.getBySel('expand-event').first().click();
cy.getBySel('response-actions-notification')
.should('not.have.text', '0')
.then((element) => {
initialNotificationCount = parseInt(element.text(), 10);
});
takeOsqueryActionWithParams();
cy.getBySel('osquery-empty-button').click();
cy.getBySel('response-actions-notification')
.should('not.have.text', '0')
.then((element) => {
updatedNotificationCount = parseInt(element.text(), 10);
expect(initialNotificationCount).to.be.equal(updatedNotificationCount - 1);
})
.then(() => {
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click();
cy.getBySel('responseActionsViewWrapper').within(() => {
cy.contains('tags');
cy.getBySel('osquery-results-comment').should('have.length', updatedNotificationCount);
});
});
it('should be able to run take action query against all enrolled agents', () => {
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('osquery-action-item').click();
cy.getBySel('agentSelection').within(() => {
cy.getBySel('comboBoxClearButton').click();
cy.getBySel('comboBoxInput').type('All{downArrow}{enter}{esc}');
cy.contains('All agents');
});
inputQuery("SELECT * FROM os_version where name='{{host.os.name}}';", {
parseSpecialCharSequences: false,
});
cy.wait(1000);
submitQuery();
cy.getBySel('flyout-body-osquery').within(() => {
// at least 2 agents should have responded, sometimes it takes a while for the agents to respond
cy.get('[data-grid-row-index]', { timeout: 6000000 }).should('have.length.at.least', 2);
});
});
it('should substitute params in osquery ran from timelines alerts', () => {
loadRuleAlerts(ruleName);
cy.getBySel('send-alert-to-timeline-button').first().click();
cy.getBySel('query-events-table').within(() => {
cy.getBySel('expand-event').first().click();
});
takeOsqueryActionWithParams();
});
});
});

View file

@ -0,0 +1,188 @@
/*
* 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 {
cleanupPack,
cleanupRule,
loadPack,
loadRule,
multiQueryPackFixture,
packFixture,
} from '../../tasks/api_fixtures';
import {
RESPONSE_ACTIONS_ITEM_0,
RESPONSE_ACTIONS_ITEM_1,
RESPONSE_ACTIONS_ITEM_2,
OSQUERY_RESPONSE_ACTION_ADD_BUTTON,
} from '../../tasks/response_actions';
import { ROLE, login } from '../../tasks/login';
import { checkActionItemsInResults, inputQuery, typeInECSFieldInput } from '../../tasks/live_query';
import { closeDateTabIfVisible, closeToastIfVisible } from '../../tasks/integrations';
describe('Alert Event Details - Response Actions Form', { browser: 'electron' }, () => {
let multiQueryPackId: string;
let multiQueryPackName: string;
let ruleId: string;
let ruleName: string;
let packId: string;
let packName: string;
const packData = packFixture();
const multiQueryPackData = multiQueryPackFixture();
beforeEach(() => {
loadPack(packData).then((data) => {
packId = data.saved_object_id;
packName = data.name;
});
loadPack(multiQueryPackData).then((data) => {
multiQueryPackId = data.saved_object_id;
multiQueryPackName = data.name;
});
loadRule().then((data) => {
ruleId = data.id;
ruleName = data.name;
});
login(ROLE.soc_manager);
});
afterEach(() => {
cleanupPack(packId);
cleanupPack(multiQueryPackId);
cleanupRule(ruleId);
});
it('adds response actions with osquery with proper validation and form values', () => {
cy.visit('/app/security/rules');
cy.contains(ruleName).click();
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
closeDateTabIfVisible();
cy.getBySel('edit-rule-actions-tab').click();
cy.contains('Response actions are run on each rule execution.');
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains('Query is a required field');
inputQuery('select * from uptime1');
});
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('Run a set of queries in a pack').click();
});
cy.contains('Save changes').click();
cy.getBySel('response-actions-error')
.within(() => {
cy.contains('Pack is a required field');
})
.should('exist');
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('Pack is a required field');
cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`);
});
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('Advanced').click();
typeInECSFieldInput('message{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('ruleEditSubmitButton').click();
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains('select * from uptime1');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_2).within(() => {
cy.contains('select * from uptime');
cy.contains('Log message optimized for viewing in a log viewer');
cy.contains('Days of uptime');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains(packName);
cy.getBySel('comboBoxInput').type('{backspace}{enter}');
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
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_1).within(() => {
cy.contains('select * from uptime');
cy.contains('Log message optimized for viewing in a log viewer');
cy.contains('Days of uptime');
});
cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleSingleQuery');
cy.getBySel('ruleEditSubmitButton').click();
cy.wait('@saveRuleSingleQuery').should(({ request }) => {
const oneQuery = [
{
interval: 3600,
query: 'select * from uptime;',
id: Object.keys(packData.queries)[0],
},
];
expect(request.body.response_actions[0].params.queries).to.deep.equal(oneQuery);
});
cy.contains(`${ruleName} was saved`).should('exist');
closeToastIfVisible();
cy.getBySel('editRuleSettingsLink').click();
cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.getBySel('edit-rule-actions-tab').click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
cy.contains(packName);
cy.getBySel('comboBoxInput').type(`${multiQueryPackName}{downArrow}{enter}`);
checkActionItemsInResults({
cases: false,
lens: false,
discover: false,
timeline: false,
});
});
cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => {
cy.contains('select * from uptime');
cy.contains('Log message optimized for viewing in a log viewer');
cy.contains('Days of uptime');
});
cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleMultiQuery');
cy.contains('Save changes').click();
cy.wait('@saveRuleMultiQuery').should(({ request }) => {
const threeQueries = [
{
interval: 3600,
query: 'SELECT * FROM memory_info;',
platform: 'linux',
id: Object.keys(multiQueryPackData.queries)[0],
},
{
interval: 3600,
query: 'SELECT * FROM system_info;',
id: Object.keys(multiQueryPackData.queries)[1],
},
{
interval: 10,
query: 'select opera_extensions.* from users join opera_extensions using (uid);',
id: Object.keys(multiQueryPackData.queries)[2],
},
];
expect(request.body.response_actions[0].params.queries).to.deep.equal(threeQueries);
});
});
});

View file

@ -1,934 +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 { recurse } from 'cypress-recurse';
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 {
checkActionItemsInResults,
checkResults,
deleteAndConfirm,
findAndClickButton,
findFormFieldByRowsLabelAndType,
inputQuery,
selectAllAgents,
submitQuery,
} from '../../tasks/live_query';
import { ROLE, login } from '../../tasks/login';
import {
activatePack,
cleanupAllPrebuiltPacks,
deactivatePack,
preparePack,
} from '../../tasks/packs';
import {
addIntegration,
closeModalIfVisible,
closeToastIfVisible,
generateRandomStringName,
interceptPackId,
interceptAgentPolicyId,
} from '../../tasks/integrations';
import { DEFAULT_POLICY, OSQUERY_POLICY } from '../../screens/fleet';
import {
getIdFormField,
getSavedQueriesDropdown,
LIVE_QUERY_EDITOR,
} from '../../screens/live_query';
import {
loadSavedQuery,
cleanupSavedQuery,
cleanupPack,
loadPack,
cleanupAgentPolicy,
} from '../../tasks/api_fixtures';
import { request } from '../../tasks/common';
describe('ALL - Packs', () => {
let savedQueryId: string;
let savedQueryName: string;
let nomappingSavedQueryId: string;
let nomappingSavedQueryName: string;
let oneMappingSavedQueryId: string;
let oneMappingSavedQueryName: string;
let multipleMappingsSavedQueryId: string;
let multipleMappingsSavedQueryName: string;
const integration = 'Osquery Manager';
const PACK_NAME = 'Pack-name' + generateRandomStringName(1)[0];
describe('Create and edit a pack', () => {
before(() => {
loadSavedQuery().then((data) => {
savedQueryId = data.saved_object_id;
savedQueryName = data.id;
});
loadSavedQuery({
ecs_mapping: {},
interval: '3600',
query: 'select * from uptime;',
}).then((data) => {
nomappingSavedQueryId = data.saved_object_id;
nomappingSavedQueryName = data.id;
});
loadSavedQuery({
ecs_mapping: {
'client.geo.continent_name': {
field: 'seconds',
},
},
interval: '3600',
query: 'select * from uptime;',
}).then((data) => {
oneMappingSavedQueryId = data.saved_object_id;
oneMappingSavedQueryName = data.id;
});
loadSavedQuery({
ecs_mapping: {
labels: {
field: 'days',
},
tags: {
field: 'seconds',
},
'client.address': {
field: 'total_seconds',
},
},
interval: '3600',
query: 'select * from uptime;',
}).then((data) => {
multipleMappingsSavedQueryId = data.saved_object_id;
multipleMappingsSavedQueryName = data.id;
});
});
beforeEach(() => {
login(ROLE.soc_manager);
navigateTo('/app/osquery');
});
after(() => {
cleanupSavedQuery(savedQueryId);
cleanupSavedQuery(nomappingSavedQueryId);
cleanupSavedQuery(oneMappingSavedQueryId);
cleanupSavedQuery(multipleMappingsSavedQueryId);
});
describe('Check if result type is correct', () => {
let resultTypePackId: string;
before(() => {
interceptPackId((pack) => {
resultTypePackId = pack;
});
});
after(() => {
cleanupPack(resultTypePackId);
});
it('Check if result type is correct', () => {
const packName = 'ResultType' + generateRandomStringName(1)[0];
cy.contains('Packs').click();
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', packName);
findAndClickButton('Add query');
cy.contains('Attach next query');
getIdFormField().type('Query1');
inputQuery('select * from uptime;');
cy.wait(500); // wait for the validation to trigger - cypress is way faster than users ;)
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findAndClickButton('Add query');
cy.contains('Attach next query');
getIdFormField().type('Query2');
inputQuery('select * from uptime;');
cy.getBySel('resultsTypeField').click();
cy.contains('Differential').click();
cy.wait(500); // wait for the validation to trigger - cypress is way faster than users ;)
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findAndClickButton('Add query');
cy.contains('Attach next query');
getIdFormField().type('Query3');
inputQuery('select * from uptime;');
cy.getBySel('resultsTypeField').click();
cy.contains('Differential (Ignore removals)').click();
cy.wait(500); // wait for the validation to trigger - cypress is way faster than users ;)
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findAndClickButton('Save pack');
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.react('ScheduledQueryNameComponent', {
props: {
name: packName,
},
}).click();
findAndClickButton('Edit');
cy.contains('Query1');
cy.contains('Query2');
cy.contains('Query3');
cy.react('CustomItemAction', {
props: { index: 0, item: { id: 'Query1' } },
}).click();
cy.getBySel('resultsTypeField').contains('Snapshot').click();
cy.contains('Differential').click();
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('CustomItemAction', {
props: { index: 0, item: { id: 'Query2' } },
}).click();
cy.getBySel('resultsTypeField').contains('Differential').click();
cy.contains('Differential (Ignore removals)').click();
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('CustomItemAction', {
props: { index: 0, item: { id: 'Query3' } },
}).click();
cy.getBySel('resultsTypeField').contains('(Ignore removals)').click();
cy.contains('Snapshot').click();
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findFormFieldByRowsLabelAndType(
'Scheduled agent policies (optional)',
'fleet server {downArrow} {enter}'
);
findAndClickButton('Update pack');
closeModalIfVisible();
cy.contains(
'Create packs to organize sets of queries and to schedule queries for agent policies.'
);
const queries = {
Query1: {
interval: 3600,
query: 'select * from uptime;',
removed: true,
snapshot: false,
},
Query2: {
interval: 3600,
query: 'select * from uptime;',
removed: false,
snapshot: false,
},
Query3: {
interval: 3600,
query: 'select * from uptime;',
},
};
request<{ items: PackagePolicy[] }>({
url: '/internal/osquery/fleet_wrapper/package_policies',
headers: {
'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
}).then((response) => {
const item = response.body.items.find(
(policy: PackagePolicy) => policy.policy_id === 'fleet-server-policy'
);
expect(item?.inputs[0].config?.osquery.value.packs[packName].queries).to.deep.equal(
queries
);
});
});
});
describe('Check if pack is created', () => {
const packName = 'Pack-name' + generateRandomStringName(1)[0];
let packId: string;
before(() => {
interceptPackId((pack) => {
packId = pack;
});
});
after(() => {
cleanupPack(packId);
});
it('should add a pack from a saved query', () => {
cy.contains('Packs').click();
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', packName);
findFormFieldByRowsLabelAndType('Description (optional)', 'Pack description');
findFormFieldByRowsLabelAndType('Scheduled agent policies (optional)', DEFAULT_POLICY);
findAndClickButton('Add query');
cy.contains('Attach next query');
getSavedQueriesDropdown().type(`${savedQueryName}{downArrow}{enter}`);
cy.react('EuiFormRow', { props: { label: 'Interval (s)' } })
.click()
.clear()
.type('5');
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('EuiTableRow').contains(savedQueryName);
findAndClickButton('Save pack');
cy.contains('Save and deploy changes');
findAndClickButton('Save and deploy changes');
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.contains(packName);
cy.contains(`Successfully created "${packName}" pack`);
closeToastIfVisible();
});
});
describe('to click the edit button and edit pack', () => {
const newQueryName = 'new-query-name' + generateRandomStringName(1)[0];
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
findAndClickButton('Edit');
cy.contains(`Edit ${packName}`);
findAndClickButton('Add query');
cy.contains('Attach next query');
inputQuery('select * from uptime');
findFormFieldByRowsLabelAndType('ID', savedQueryName);
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.contains('ID must be unique').should('exist');
findFormFieldByRowsLabelAndType('ID', newQueryName);
cy.contains('ID must be unique').should('not.exist');
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('EuiTableRow').contains(newQueryName);
findAndClickButton('Update pack');
cy.contains('Save and deploy changes');
findAndClickButton('Save and deploy changes');
cy.contains(`Successfully updated "${packName}" pack`);
closeToastIfVisible();
});
});
describe('should trigger validation when saved query is being chosen', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
findAndClickButton('Edit');
findAndClickButton('Add query');
cy.contains('Attach next query');
cy.contains('ID must be unique').should('not.exist');
getSavedQueriesDropdown().type(`${savedQueryName}{downArrow}{enter}`);
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.contains('ID must be unique').should('exist');
cy.react('EuiFlyoutFooter').react('EuiButtonEmpty').contains('Cancel').click();
});
});
describe('should open lens in new tab', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
let lensUrl = '';
cy.window().then((win) => {
cy.stub(win, 'open')
.as('windowOpen')
.callsFake((url) => {
lensUrl = url;
});
});
preparePack(packName);
cy.getBySel('docsLoading').should('exist');
cy.getBySel('docsLoading').should('not.exist');
cy.get(`[aria-label="View in Lens"]`).eq(0).click();
cy.window()
.its('open')
.then(() => {
cy.visit(lensUrl);
});
cy.getBySel('lnsWorkspace').should('exist');
cy.getBySel('breadcrumbs').contains(`Action pack_${packName}_${savedQueryName}`);
});
});
describe.skip('should open discover in new tab', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.react('CustomItemAction', {
props: { index: 0, item: { id: savedQueryName } },
})
.should('exist')
.within(() => {
cy.get('a')
.should('have.attr', 'href')
.then(($href) => {
// @ts-expect-error-next-line href string - check types
cy.visit($href);
cy.getBySel('breadcrumbs').contains('Discover').should('exist');
cy.contains(`action_id: pack_${PACK_NAME}_${savedQueryName}`);
cy.getBySel('superDatePickerToggleQuickMenuButton').click();
cy.getBySel('superDatePickerCommonlyUsed_Today').click();
cy.getBySel('discoverDocTable', { timeout: 60000 }).contains(
`pack_${PACK_NAME}_${savedQueryName}`
);
});
});
});
});
describe('deactivate and activate pack', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
cy.contains('Packs').click();
deactivatePack(packName);
activatePack(packName);
});
});
describe('should verify that packs are triggered', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 60, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.contains(`${packName} details`).should('exist');
recurse<string>(
() => {
cy.waitForReact();
cy.getBySel('docsLoading').should('exist');
cy.getBySel('docsLoading').should('not.exist');
return cy.get('tbody .euiTableRow > td:nth-child(5)').invoke('text');
},
(response) => response === 'Docs1',
{
timeout: 300000,
post: () => {
cy.reload();
},
}
);
cy.react('ScheduledQueryLastResults', { options: { timeout: 3000 } })
.should('exist')
.within(() => {
cy.react('FormattedRelative');
});
cy.react('DocsColumnResults').within(() => {
cy.react('EuiNotificationBadge').contains('1');
});
cy.react('AgentsColumnResults').within(() => {
cy.react('EuiNotificationBadge').contains('1');
});
cy.getBySel('packResultsErrorsEmpty').should('have.length', 1);
});
});
describe('delete all queries in the pack', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.contains(/^Edit$/).click();
cy.getBySel('checkboxSelectAll').click();
cy.contains(/^Delete \d+ quer(y|ies)/).click();
cy.contains(/^Update pack$/).click();
cy.react('EuiButtonDisplay')
.contains(/^Save and deploy changes$/)
.click();
cy.get('a').contains(packName).click();
cy.contains(`${packName} details`).should('exist');
cy.contains(/^No items found/).should('exist');
});
});
describe('enable changing saved queries and ecs_mappings', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.contains(/^Edit$/).click();
findAndClickButton('Add query');
getSavedQueriesDropdown().type(`${multipleMappingsSavedQueryName} {downArrow} {enter}`);
cy.contains('Custom key/value pairs').should('exist');
cy.contains('Days of uptime').should('exist');
cy.contains('List of keywords used to tag each').should('exist');
cy.contains('Seconds of uptime').should('exist');
cy.contains('Client network address.').should('exist');
cy.contains('Total uptime seconds').should('exist');
cy.getBySel('ECSMappingEditorForm').should('have.length', 4);
getSavedQueriesDropdown().type(`${nomappingSavedQueryName} {downArrow} {enter}`);
cy.contains('Custom key/value pairs').should('not.exist');
cy.contains('Days of uptime').should('not.exist');
cy.contains('List of keywords used to tag each').should('not.exist');
cy.contains('Seconds of uptime').should('not.exist');
cy.contains('Client network address.').should('not.exist');
cy.contains('Total uptime seconds').should('not.exist');
cy.getBySel('ECSMappingEditorForm').should('have.length', 1);
getSavedQueriesDropdown().type(`${oneMappingSavedQueryName} {downArrow} {enter}`);
cy.contains('Name of the continent').should('exist');
cy.contains('Seconds of uptime').should('exist');
cy.getBySel('ECSMappingEditorForm').should('have.length', 2);
findAndClickButton('Save');
cy.react('CustomItemAction', {
props: { index: 0, item: { id: oneMappingSavedQueryName } },
}).click();
cy.contains('Name of the continent').should('exist');
cy.contains('Seconds of uptime').should('exist');
});
});
describe('to click delete button', () => {
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packName = pack.name;
});
});
it('', () => {
preparePack(packName);
findAndClickButton('Edit');
deleteAndConfirm('pack');
});
});
});
describe('Validate that agent policy is getting removed from pack if we remove agent policy', () => {
beforeEach(() => {
login();
});
const AGENT_POLICY_NAME = `PackTest` + generateRandomStringName(1)[0];
const REMOVING_PACK = 'removing-pack' + generateRandomStringName(1)[0];
it('add integration', () => {
cy.visit(FLEET_AGENT_POLICIES);
cy.contains('Create agent policy').click();
cy.get('input[placeholder*="Choose a name"]').type(AGENT_POLICY_NAME);
cy.get('.euiFlyoutFooter').contains('Create agent policy').click();
cy.contains(`Agent policy '${AGENT_POLICY_NAME}' created`);
cy.visit(FLEET_AGENT_POLICIES);
cy.contains(AGENT_POLICY_NAME).click();
cy.contains('Add integration').click();
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');
closeToastIfVisible();
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.react('ScheduledQueryNameComponent', { props: { name: REMOVING_PACK } }).click();
cy.contains(`${REMOVING_PACK} details`).should('exist');
findAndClickButton('Edit');
cy.react('EuiComboBoxInput', { props: { value: AGENT_POLICY_NAME } }).should('exist');
cy.visit(FLEET_AGENT_POLICIES);
cy.contains(AGENT_POLICY_NAME).click();
cy.get('.euiTableCellContent')
.get('.euiPopover__anchor')
.get(`[aria-label="Open"]`)
.first()
.click();
cy.contains(/^Delete integration$/).click();
closeModalIfVisible();
cy.contains(/^Deleted integration 'osquery_manager-*/);
navigateTo('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');
});
});
describe('Load prebuilt packs', () => {
beforeEach(() => {
login(ROLE.soc_manager);
navigateTo('/app/osquery/packs');
});
after(() => {
cleanupAllPrebuiltPacks();
});
const PREBUILD_PACK_NAME = 'it-compliance';
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);
});
it('should be able to activate pack', () => {
activatePack(PREBUILD_PACK_NAME);
deactivatePack(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)',
'fleet server {downArrow}{enter}'
);
cy.contains('Update pack').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);
});
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.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', () => {
cy.contains(PREBUILD_PACK_NAME).click();
cy.contains('Edit').click();
deleteAndConfirm('pack');
cy.contains(PREBUILD_PACK_NAME).should('not.exist');
cy.contains('Update Elastic prebuilt packs').click();
cy.contains('Successfully updated prebuilt packs');
cy.contains(PREBUILD_PACK_NAME).should('exist');
});
it('should be able to run live prebuilt pack', () => {
navigateTo('/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');
cy.getBySel('select-live-pack').click().type('osquery-monitoring{downArrow}{enter}');
selectAllAgents();
submitQuery();
cy.getBySel('live-query-loading').should('exist');
cy.getBySel('live-query-loading', { timeout: 10000 }).should('not.exist');
cy.getBySel('toggleIcon-events').click();
checkResults();
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: false,
});
navigateTo('/app/osquery');
cy.contains('osquery-monitoring');
});
});
describe('Global packs', () => {
beforeEach(() => {
login();
navigateTo('/app/osquery/packs');
});
describe('add proper shard to policies packs config', () => {
const globalPack = 'globalPack' + generateRandomStringName(1)[0];
const agentPolicy = 'testGlobal' + generateRandomStringName(1)[0];
let globalPackId: string;
let agentPolicyId: string;
before(() => {
interceptPackId((pack) => {
globalPackId = pack;
});
interceptAgentPolicyId((policyId) => {
agentPolicyId = policyId;
});
});
after(() => {
cleanupPack(globalPackId);
cleanupAgentPolicy(agentPolicyId);
});
it('add global packs to policies', () => {
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', globalPack);
cy.getBySel('policyIdsComboBox').should('exist');
cy.getBySel('osqueryPackTypeGlobal').click();
cy.getBySel('policyIdsComboBox').should('not.exist');
findAndClickButton('Save pack');
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.contains(globalPack);
cy.contains(`Successfully created "${globalPack}" pack`);
closeToastIfVisible();
cy.visit(FLEET_AGENT_POLICIES);
cy.contains('Create agent policy').click();
cy.getBySel('createAgentPolicyNameField').type(agentPolicy);
cy.getBySel('createAgentPolicyFlyoutBtn').click();
cy.contains(`Agent policy '${agentPolicy}' created`).click();
cy.contains(agentPolicy).click();
cy.contains('Add integration').click();
cy.contains(integration).click();
addIntegration(agentPolicy);
cy.contains('Add Elastic Agent later').click();
cy.contains('osquery_manager-');
request<{ items: PackagePolicy[] }>({
url: '/internal/osquery/fleet_wrapper/package_policies',
headers: {
'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
}).then((response) => {
const item = find(response.body.items, ['policy_id', agentPolicyId]);
expect(item?.inputs[0].config?.osquery.value.packs[globalPack]).to.deep.equal({
shard: 100,
queries: {},
});
});
cy.visit('/app/fleet/policies');
cy.contains('td', agentPolicy)
.parent()
.within(() => {
cy.contains('rev. 2').click();
});
});
});
describe('add proper shard to policies packs config', () => {
let shardPackId: string;
before(() => {
interceptPackId((pack) => {
shardPackId = pack;
});
});
after(() => {
cleanupPack(shardPackId);
});
it('', () => {
const shardPack = 'shardPack' + generateRandomStringName(1)[0];
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', shardPack);
cy.contains('Partial deployment (shards)').click();
cy.getBySel('packShardsForm-0').within(() => {
cy.getBySel('shards-field-policy').type(`${DEFAULT_POLICY}{downArrow}{enter}`);
cy.get('#shardsPercentage0').type('{backspace}{backspace}5');
});
cy.getBySel('packShardsForm-1').within(() => {
cy.getBySel('shards-field-policy').type(`${OSQUERY_POLICY}{downArrow}{enter}`);
cy.get('#shardsPercentage1').type('{backspace}{backspace}{backspace}');
});
findAndClickButton('Save pack');
cy.contains(`Successfully created "${shardPack}" pack`);
closeToastIfVisible();
request<{ items: PackagePolicy[] }>({
url: '/internal/osquery/fleet_wrapper/package_policies',
headers: {
'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
}).then((response) => {
const shardPolicy = response.body.items.find(
(policy: PackagePolicy) => policy.policy_id === 'fleet-server-policy'
);
expect(shardPolicy?.inputs[0].config?.osquery.value.packs[shardPack]).to.deep.equal({
shard: 15,
queries: {},
});
});
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.contains(shardPack).click();
cy.contains('Edit').click();
cy.get('#shardsPercentage0').should('have.value', '15');
cy.getBySel('packShardsForm-1').within(() => {
cy.getBySel('shards-field-policy').contains(OSQUERY_POLICY);
cy.get('#shardsPercentage1').should('have.value', '0');
});
cy.getBySel('policyIdsComboBox').within(() => {
cy.contains(OSQUERY_POLICY).should('not.exist');
});
cy.getBySel('comboBoxInput').contains(OSQUERY_POLICY).should('exist');
cy.getBySel('policyIdsComboBox').click();
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');
});
});
});
});

View file

@ -0,0 +1,628 @@
/*
* 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 { recurse } from 'cypress-recurse';
import type { PackagePolicy } from '@kbn/fleet-plugin/common';
import { API_VERSIONS } from '../../../common/constants';
import { navigateTo } from '../../tasks/navigation';
import {
deleteAndConfirm,
findAndClickButton,
findFormFieldByRowsLabelAndType,
inputQuery,
} from '../../tasks/live_query';
import { ROLE, login } from '../../tasks/login';
import { activatePack, deactivatePack, preparePack } from '../../tasks/packs';
import {
closeModalIfVisible,
closeToastIfVisible,
generateRandomStringName,
interceptPackId,
} from '../../tasks/integrations';
import { DEFAULT_POLICY } from '../../screens/fleet';
import { getIdFormField, getSavedQueriesDropdown } from '../../screens/live_query';
import { loadSavedQuery, cleanupSavedQuery, cleanupPack, loadPack } from '../../tasks/api_fixtures';
import { request } from '../../tasks/common';
describe('Packs - Create and Edit', () => {
let savedQueryId: string;
let savedQueryName: string;
let nomappingSavedQueryId: string;
let nomappingSavedQueryName: string;
let oneMappingSavedQueryId: string;
let oneMappingSavedQueryName: string;
let multipleMappingsSavedQueryId: string;
let multipleMappingsSavedQueryName: string;
const PACK_NAME = 'Pack-name' + generateRandomStringName(1)[0];
before(() => {
loadSavedQuery().then((data) => {
savedQueryId = data.saved_object_id;
savedQueryName = data.id;
});
loadSavedQuery({
ecs_mapping: {},
interval: '3600',
query: 'select * from uptime;',
}).then((data) => {
nomappingSavedQueryId = data.saved_object_id;
nomappingSavedQueryName = data.id;
});
loadSavedQuery({
ecs_mapping: {
'client.geo.continent_name': {
field: 'seconds',
},
},
interval: '3600',
query: 'select * from uptime;',
}).then((data) => {
oneMappingSavedQueryId = data.saved_object_id;
oneMappingSavedQueryName = data.id;
});
loadSavedQuery({
ecs_mapping: {
labels: {
field: 'days',
},
tags: {
field: 'seconds',
},
'client.address': {
field: 'total_seconds',
},
},
interval: '3600',
query: 'select * from uptime;',
}).then((data) => {
multipleMappingsSavedQueryId = data.saved_object_id;
multipleMappingsSavedQueryName = data.id;
});
});
beforeEach(() => {
login(ROLE.soc_manager);
navigateTo('/app/osquery');
});
after(() => {
cleanupSavedQuery(savedQueryId);
cleanupSavedQuery(nomappingSavedQueryId);
cleanupSavedQuery(oneMappingSavedQueryId);
cleanupSavedQuery(multipleMappingsSavedQueryId);
});
describe('Check if result type is correct', () => {
let resultTypePackId: string;
before(() => {
interceptPackId((pack) => {
resultTypePackId = pack;
});
});
after(() => {
cleanupPack(resultTypePackId);
});
it('Check if result type is correct', () => {
const packName = 'ResultType' + generateRandomStringName(1)[0];
cy.contains('Packs').click();
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', packName);
findAndClickButton('Add query');
cy.contains('Attach next query');
getIdFormField().type('Query1');
inputQuery('select * from uptime;');
cy.wait(500); // wait for the validation to trigger - cypress is way faster than users ;)
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findAndClickButton('Add query');
cy.contains('Attach next query');
getIdFormField().type('Query2');
inputQuery('select * from uptime;');
cy.getBySel('resultsTypeField').click();
cy.contains('Differential').click();
cy.wait(500); // wait for the validation to trigger - cypress is way faster than users ;)
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findAndClickButton('Add query');
cy.contains('Attach next query');
getIdFormField().type('Query3');
inputQuery('select * from uptime;');
cy.getBySel('resultsTypeField').click();
cy.contains('Differential (Ignore removals)').click();
cy.wait(500); // wait for the validation to trigger - cypress is way faster than users ;)
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findAndClickButton('Save pack');
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.react('ScheduledQueryNameComponent', {
props: {
name: packName,
},
}).click();
findAndClickButton('Edit');
cy.contains('Query1');
cy.contains('Query2');
cy.contains('Query3');
cy.react('CustomItemAction', {
props: { index: 0, item: { id: 'Query1' } },
}).click();
cy.getBySel('resultsTypeField').contains('Snapshot').click();
cy.contains('Differential').click();
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('CustomItemAction', {
props: { index: 0, item: { id: 'Query2' } },
}).click();
cy.getBySel('resultsTypeField').contains('Differential').click();
cy.contains('Differential (Ignore removals)').click();
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('CustomItemAction', {
props: { index: 0, item: { id: 'Query3' } },
}).click();
cy.getBySel('resultsTypeField').contains('(Ignore removals)').click();
cy.contains('Snapshot').click();
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findFormFieldByRowsLabelAndType(
'Scheduled agent policies (optional)',
'fleet server {downArrow} {enter}'
);
findAndClickButton('Update pack');
closeModalIfVisible();
cy.contains(
'Create packs to organize sets of queries and to schedule queries for agent policies.'
);
const queries = {
Query1: {
interval: 3600,
query: 'select * from uptime;',
removed: true,
snapshot: false,
},
Query2: {
interval: 3600,
query: 'select * from uptime;',
removed: false,
snapshot: false,
},
Query3: {
interval: 3600,
query: 'select * from uptime;',
},
};
request<{ items: PackagePolicy[] }>({
url: '/internal/osquery/fleet_wrapper/package_policies',
headers: {
'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
}).then((response) => {
const item = response.body.items.find(
(policy: PackagePolicy) => policy.policy_id === 'fleet-server-policy'
);
expect(item?.inputs[0].config?.osquery.value.packs[packName].queries).to.deep.equal(
queries
);
});
});
});
describe('Check if pack is created', () => {
const packName = 'Pack-name' + generateRandomStringName(1)[0];
let packId: string;
before(() => {
interceptPackId((pack) => {
packId = pack;
});
});
after(() => {
cleanupPack(packId);
});
it('should add a pack from a saved query', () => {
cy.contains('Packs').click();
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', packName);
findFormFieldByRowsLabelAndType('Description (optional)', 'Pack description');
findFormFieldByRowsLabelAndType('Scheduled agent policies (optional)', DEFAULT_POLICY);
findAndClickButton('Add query');
cy.contains('Attach next query');
getSavedQueriesDropdown().type(`${savedQueryName}{downArrow}{enter}`);
cy.react('EuiFormRow', { props: { label: 'Interval (s)' } })
.click()
.clear()
.type('5');
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('EuiTableRow').contains(savedQueryName);
findAndClickButton('Save pack');
cy.contains('Save and deploy changes');
findAndClickButton('Save and deploy changes');
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.contains(packName);
cy.contains(`Successfully created "${packName}" pack`);
closeToastIfVisible();
});
});
describe('to click the edit button and edit pack', () => {
const newQueryName = 'new-query-name' + generateRandomStringName(1)[0];
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
findAndClickButton('Edit');
cy.contains(`Edit ${packName}`);
findAndClickButton('Add query');
cy.contains('Attach next query');
inputQuery('select * from uptime');
findFormFieldByRowsLabelAndType('ID', savedQueryName);
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.contains('ID must be unique').should('exist');
findFormFieldByRowsLabelAndType('ID', newQueryName);
cy.contains('ID must be unique').should('not.exist');
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.react('EuiTableRow').contains(newQueryName);
findAndClickButton('Update pack');
cy.contains('Save and deploy changes');
findAndClickButton('Save and deploy changes');
cy.contains(`Successfully updated "${packName}" pack`);
closeToastIfVisible();
});
});
describe('should trigger validation when saved query is being chosen', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
findAndClickButton('Edit');
findAndClickButton('Add query');
cy.contains('Attach next query');
cy.contains('ID must be unique').should('not.exist');
getSavedQueriesDropdown().type(`${savedQueryName}{downArrow}{enter}`);
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
cy.contains('ID must be unique').should('exist');
cy.react('EuiFlyoutFooter').react('EuiButtonEmpty').contains('Cancel').click();
});
});
describe('should open lens in new tab', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
let lensUrl = '';
cy.window().then((win) => {
cy.stub(win, 'open')
.as('windowOpen')
.callsFake((url) => {
lensUrl = url;
});
});
preparePack(packName);
cy.getBySel('docsLoading').should('exist');
cy.getBySel('docsLoading').should('not.exist');
cy.get(`[aria-label="View in Lens"]`).eq(0).click();
cy.window()
.its('open')
.then(() => {
cy.visit(lensUrl);
});
cy.getBySel('lnsWorkspace').should('exist');
cy.getBySel('breadcrumbs').contains(`Action pack_${packName}_${savedQueryName}`);
});
});
describe.skip('should open discover in new tab', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.react('CustomItemAction', {
props: { index: 0, item: { id: savedQueryName } },
})
.should('exist')
.within(() => {
cy.get('a')
.should('have.attr', 'href')
.then(($href) => {
// @ts-expect-error-next-line href string - check types
cy.visit($href);
cy.getBySel('breadcrumbs').contains('Discover').should('exist');
cy.contains(`action_id: pack_${PACK_NAME}_${savedQueryName}`);
cy.getBySel('superDatePickerToggleQuickMenuButton').click();
cy.getBySel('superDatePickerCommonlyUsed_Today').click();
cy.getBySel('discoverDocTable', { timeout: 60000 }).contains(
`pack_${PACK_NAME}_${savedQueryName}`
);
});
});
});
});
describe('deactivate and activate pack', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
cy.contains('Packs').click();
deactivatePack(packName);
activatePack(packName);
});
});
describe('should verify that packs are triggered', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 60, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.contains(`${packName} details`).should('exist');
recurse<string>(
() => {
cy.waitForReact();
cy.getBySel('docsLoading').should('exist');
cy.getBySel('docsLoading').should('not.exist');
return cy.get('tbody .euiTableRow > td:nth-child(5)').invoke('text');
},
(response) => response === 'Docs1',
{
timeout: 300000,
post: () => {
cy.reload();
},
}
);
cy.react('ScheduledQueryLastResults', { options: { timeout: 3000 } })
.should('exist')
.within(() => {
cy.react('FormattedRelative');
});
cy.react('DocsColumnResults').within(() => {
cy.react('EuiNotificationBadge').contains('1');
});
cy.react('AgentsColumnResults').within(() => {
cy.react('EuiNotificationBadge').contains('1');
});
cy.getBySel('packResultsErrorsEmpty').should('have.length', 1);
});
});
describe('delete all queries in the pack', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.contains(/^Edit$/).click();
cy.getBySel('checkboxSelectAll').click();
cy.contains(/^Delete \d+ quer(y|ies)/).click();
cy.contains(/^Update pack$/).click();
cy.react('EuiButtonDisplay')
.contains(/^Save and deploy changes$/)
.click();
cy.get('a').contains(packName).click();
cy.contains(`${packName} details`).should('exist');
cy.contains(/^No items found/).should('exist');
});
});
describe('enable changing saved queries and ecs_mappings', () => {
let packId: string;
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packId = pack.saved_object_id;
packName = pack.name;
});
});
after(() => {
cleanupPack(packId);
});
it('', () => {
preparePack(packName);
cy.contains(/^Edit$/).click();
findAndClickButton('Add query');
getSavedQueriesDropdown().type(`${multipleMappingsSavedQueryName} {downArrow} {enter}`);
cy.contains('Custom key/value pairs').should('exist');
cy.contains('Days of uptime').should('exist');
cy.contains('List of keywords used to tag each').should('exist');
cy.contains('Seconds of uptime').should('exist');
cy.contains('Client network address.').should('exist');
cy.contains('Total uptime seconds').should('exist');
cy.getBySel('ECSMappingEditorForm').should('have.length', 4);
getSavedQueriesDropdown().type(`${nomappingSavedQueryName} {downArrow} {enter}`);
cy.contains('Custom key/value pairs').should('not.exist');
cy.contains('Days of uptime').should('not.exist');
cy.contains('List of keywords used to tag each').should('not.exist');
cy.contains('Seconds of uptime').should('not.exist');
cy.contains('Client network address.').should('not.exist');
cy.contains('Total uptime seconds').should('not.exist');
cy.getBySel('ECSMappingEditorForm').should('have.length', 1);
getSavedQueriesDropdown().type(`${oneMappingSavedQueryName} {downArrow} {enter}`);
cy.contains('Name of the continent').should('exist');
cy.contains('Seconds of uptime').should('exist');
cy.getBySel('ECSMappingEditorForm').should('have.length', 2);
findAndClickButton('Save');
cy.react('CustomItemAction', {
props: { index: 0, item: { id: oneMappingSavedQueryName } },
}).click();
cy.contains('Name of the continent').should('exist');
cy.contains('Seconds of uptime').should('exist');
});
});
describe('to click delete button', () => {
let packName: string;
before(() => {
loadPack({
policy_ids: ['fleet-server-policy'],
queries: {
[savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
},
}).then((pack) => {
packName = pack.name;
});
});
it('', () => {
preparePack(packName);
findAndClickButton('Edit');
deleteAndConfirm('pack');
});
});
});

View file

@ -0,0 +1,319 @@
/*
* 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 { 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 {
checkActionItemsInResults,
checkResults,
deleteAndConfirm,
findAndClickButton,
findFormFieldByRowsLabelAndType,
selectAllAgents,
submitQuery,
} from '../../tasks/live_query';
import { ROLE, login } from '../../tasks/login';
import { activatePack, cleanupAllPrebuiltPacks, deactivatePack } from '../../tasks/packs';
import {
addIntegration,
closeModalIfVisible,
closeToastIfVisible,
generateRandomStringName,
interceptPackId,
interceptAgentPolicyId,
} from '../../tasks/integrations';
import { DEFAULT_POLICY, OSQUERY_POLICY } from '../../screens/fleet';
import { LIVE_QUERY_EDITOR } from '../../screens/live_query';
import { cleanupPack, cleanupAgentPolicy } from '../../tasks/api_fixtures';
import { request } from '../../tasks/common';
describe('ALL - Packs', () => {
const integration = 'Osquery Manager';
describe('Validate that agent policy is getting removed from pack if we remove agent policy', () => {
beforeEach(() => {
login();
});
const AGENT_POLICY_NAME = `PackTest` + generateRandomStringName(1)[0];
const REMOVING_PACK = 'removing-pack' + generateRandomStringName(1)[0];
it('add integration', () => {
cy.visit(FLEET_AGENT_POLICIES);
cy.contains('Create agent policy').click();
cy.get('input[placeholder*="Choose a name"]').type(AGENT_POLICY_NAME);
cy.get('.euiFlyoutFooter').contains('Create agent policy').click();
cy.contains(`Agent policy '${AGENT_POLICY_NAME}' created`);
cy.visit(FLEET_AGENT_POLICIES);
cy.contains(AGENT_POLICY_NAME).click();
cy.contains('Add integration').click();
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');
closeToastIfVisible();
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.react('ScheduledQueryNameComponent', { props: { name: REMOVING_PACK } }).click();
cy.contains(`${REMOVING_PACK} details`).should('exist');
findAndClickButton('Edit');
cy.react('EuiComboBoxInput', { props: { value: AGENT_POLICY_NAME } }).should('exist');
cy.visit(FLEET_AGENT_POLICIES);
cy.contains(AGENT_POLICY_NAME).click();
cy.get('.euiTableCellContent')
.get('.euiPopover__anchor')
.get(`[aria-label="Open"]`)
.first()
.click();
cy.contains(/^Delete integration$/).click();
closeModalIfVisible();
cy.contains(/^Deleted integration 'osquery_manager-*/);
navigateTo('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');
});
});
describe('Load prebuilt packs', () => {
beforeEach(() => {
login(ROLE.soc_manager);
navigateTo('/app/osquery/packs');
});
after(() => {
cleanupAllPrebuiltPacks();
});
const PREBUILD_PACK_NAME = 'it-compliance';
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);
});
it('should be able to activate pack', () => {
activatePack(PREBUILD_PACK_NAME);
deactivatePack(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)',
'fleet server {downArrow}{enter}'
);
cy.contains('Update pack').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);
});
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.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', () => {
cy.contains(PREBUILD_PACK_NAME).click();
cy.contains('Edit').click();
deleteAndConfirm('pack');
cy.contains(PREBUILD_PACK_NAME).should('not.exist');
cy.contains('Update Elastic prebuilt packs').click();
cy.contains('Successfully updated prebuilt packs');
cy.contains(PREBUILD_PACK_NAME).should('exist');
});
it('should be able to run live prebuilt pack', () => {
navigateTo('/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');
cy.getBySel('select-live-pack').click().type('osquery-monitoring{downArrow}{enter}');
selectAllAgents();
submitQuery();
cy.getBySel('live-query-loading').should('exist');
cy.getBySel('live-query-loading', { timeout: 10000 }).should('not.exist');
cy.getBySel('toggleIcon-events').click();
checkResults();
checkActionItemsInResults({
lens: true,
discover: true,
cases: true,
timeline: false,
});
navigateTo('/app/osquery');
cy.contains('osquery-monitoring');
});
});
describe('Global packs', () => {
beforeEach(() => {
login();
navigateTo('/app/osquery/packs');
});
describe('add proper shard to policies packs config', () => {
const globalPack = 'globalPack' + generateRandomStringName(1)[0];
const agentPolicy = 'testGlobal' + generateRandomStringName(1)[0];
let globalPackId: string;
let agentPolicyId: string;
before(() => {
interceptPackId((pack) => {
globalPackId = pack;
});
interceptAgentPolicyId((policyId) => {
agentPolicyId = policyId;
});
});
after(() => {
cleanupPack(globalPackId);
cleanupAgentPolicy(agentPolicyId);
});
it('add global packs to policies', () => {
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', globalPack);
cy.getBySel('policyIdsComboBox').should('exist');
cy.getBySel('osqueryPackTypeGlobal').click();
cy.getBySel('policyIdsComboBox').should('not.exist');
findAndClickButton('Save pack');
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.contains(globalPack);
cy.contains(`Successfully created "${globalPack}" pack`);
closeToastIfVisible();
cy.visit(FLEET_AGENT_POLICIES);
cy.contains('Create agent policy').click();
cy.getBySel('createAgentPolicyNameField').type(agentPolicy);
cy.getBySel('createAgentPolicyFlyoutBtn').click();
cy.contains(`Agent policy '${agentPolicy}' created`).click();
cy.contains(agentPolicy).click();
cy.contains('Add integration').click();
cy.contains(integration).click();
addIntegration(agentPolicy);
cy.contains('Add Elastic Agent later').click();
cy.contains('osquery_manager-');
request<{ items: PackagePolicy[] }>({
url: '/internal/osquery/fleet_wrapper/package_policies',
headers: {
'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
}).then((response) => {
const item = find(response.body.items, ['policy_id', agentPolicyId]);
expect(item?.inputs[0].config?.osquery.value.packs[globalPack]).to.deep.equal({
shard: 100,
queries: {},
});
});
cy.visit('/app/fleet/policies');
cy.contains('td', agentPolicy)
.parent()
.within(() => {
cy.contains('rev. 2').click();
});
});
});
describe('add proper shard to policies packs config', () => {
let shardPackId: string;
before(() => {
interceptPackId((pack) => {
shardPackId = pack;
});
});
after(() => {
cleanupPack(shardPackId);
});
it('', () => {
const shardPack = 'shardPack' + generateRandomStringName(1)[0];
findAndClickButton('Add pack');
findFormFieldByRowsLabelAndType('Name', shardPack);
cy.contains('Partial deployment (shards)').click();
cy.getBySel('packShardsForm-0').within(() => {
cy.getBySel('shards-field-policy').type(`${DEFAULT_POLICY}{downArrow}{enter}`);
cy.get('#shardsPercentage0').type('{backspace}{backspace}5');
});
cy.getBySel('packShardsForm-1').within(() => {
cy.getBySel('shards-field-policy').type(`${OSQUERY_POLICY}{downArrow}{enter}`);
cy.get('#shardsPercentage1').type('{backspace}{backspace}{backspace}');
});
findAndClickButton('Save pack');
cy.contains(`Successfully created "${shardPack}" pack`);
closeToastIfVisible();
request<{ items: PackagePolicy[] }>({
url: '/internal/osquery/fleet_wrapper/package_policies',
headers: {
'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
}).then((response) => {
const shardPolicy = response.body.items.find(
(policy: PackagePolicy) => policy.policy_id === 'fleet-server-policy'
);
expect(shardPolicy?.inputs[0].config?.osquery.value.packs[shardPack]).to.deep.equal({
shard: 15,
queries: {},
});
});
cy.getBySel('tablePaginationPopoverButton').click();
cy.getBySel('tablePagination-50-rows').click();
cy.contains(shardPack).click();
cy.contains('Edit').click();
cy.get('#shardsPercentage0').should('have.value', '15');
cy.getBySel('packShardsForm-1').within(() => {
cy.getBySel('shards-field-policy').contains(OSQUERY_POLICY);
cy.get('#shardsPercentage1').should('have.value', '0');
});
cy.getBySel('policyIdsComboBox').within(() => {
cy.contains(OSQUERY_POLICY).should('not.exist');
});
cy.getBySel('comboBoxInput').contains(OSQUERY_POLICY).should('exist');
cy.getBySel('policyIdsComboBox').click();
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');
});
});
});
});

View file

@ -97,6 +97,7 @@ describe('Alert Test', () => {
cy.getBySel('expand-event').first().click();
cy.wait(500);
cy.getBySel('securitySolutionDocumentDetailsFlyoutInvestigationGuideButton').click();
cy.contains('Get processes').click();
});

View file

@ -65,7 +65,8 @@ describe('None', () => {
cy.visit(`/app/security/rules/id/${ruleId}/alerts`);
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('responseActionsViewTab').click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click();
cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click();
cy.contains('Permission denied').should('exist');
});
});

View file

@ -26,7 +26,9 @@
export {};
import 'cypress-react-selector';
// import './coverage';
import registerCypressGrep from '@cypress/grep';
registerCypressGrep();
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace

View file

@ -229,6 +229,7 @@ export const cleanupCase = (id: string) => {
method: 'DELETE',
url: '/api/cases',
qs: { ids: JSON.stringify([id]) },
failOnStatusCode: false,
});
};

View file

@ -6,6 +6,7 @@
*/
import { LIVE_QUERY_EDITOR } from '../screens/live_query';
import { ROLE, login } from './login';
export const DEFAULT_QUERY = 'select * from processes;';
export const BIG_QUERY = 'select * from processes, users limit 110;';
@ -100,6 +101,7 @@ export const toggleRuleOffAndOn = (ruleName: string) => {
};
export const loadRuleAlerts = (ruleName: string) => {
login(ROLE.soc_manager);
cy.visit('/app/security/rules');
cy.contains(ruleName).click();
cy.getBySel('alertsTable').within(() => {

View file

@ -5,8 +5,12 @@
"private": true,
"license": "Elastic License 2.0",
"scripts": {
"cypress:burn": "yarn cypress:run --env burn=2 --concurrency=1 --headed",
"cypress:changed-specs-only": "yarn cypress:run --changed-specs-only --env burn=2",
"cypress:open": "node ../security_solution/scripts/start_cypress_parallel open --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../x-pack/test/osquery_cypress/cli_config",
"cypress:run": "node ../security_solution/scripts/start_cypress_parallel run --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../x-pack/test/osquery_cypress/cli_config --concurrency 1",
"nyc": "../../../node_modules/.bin/nyc report --reporter=text-summary"
"nyc": "../../../node_modules/.bin/nyc report --reporter=text-summary",
"junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-osquery/cypress/results/mochawesome*.json > ../../../target/kibana-osquery/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-osquery/cypress/results/output.json --reportDir ../../../target/kibana-osquery/cypress/results && yarn junit:transform && mkdir -p ../../../target/junit && cp ../../../target/kibana-osquery/cypress/results/*.xml ../../../target/junit/",
"junit:transform": "node ../security_solution/scripts/junit_transformer --pathPattern '../../../target/kibana-osquery/cypress/results/*.xml' --rootDirectory ../../../ --reportName 'Osquery Cypress' --writeInPlace"
}
}

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { pick } from 'lodash';
import { map, pick } from 'lodash';
import type { Client, estypes } from '@elastic/elasticsearch';
import type {
Agent,
@ -35,6 +35,7 @@ import type {
} from '@kbn/fleet-plugin/common/types';
import nodeFetch from 'node-fetch';
import semver from 'semver';
import axios from 'axios';
import { catchAxiosErrorFormatAndThrow } from './format_axios_error';
import { FleetAgentGenerator } from '../../../common/endpoint/data_generators/fleet_agent_generator';
@ -236,7 +237,13 @@ export const getAgentVersionMatchingCurrentStack = async (
kbnClient: KbnClient
): Promise<string> => {
const kbnStatus = await kbnClient.status.get();
let version = kbnStatus.version.number;
const agentVersions = await axios
.get('https://artifacts-api.elastic.co/v1/versions')
.then((response) => map(response.data.versions, (version) => version.split('-SNAPSHOT')[0]));
let version =
semver.maxSatisfying(agentVersions, `<=${kbnStatus.version.number}`) ??
kbnStatus.version.number;
// Add `-SNAPSHOT` if version indicates it was from a snapshot or the build hash starts
// with `xxxxxxxxx` (value that seems to be present when running kibana from source)

View file

@ -105,6 +105,10 @@ export const cli = () => {
// eslint-disable-next-line no-process-exit
return process.exit(0);
}
// to avoid running too many tests, we limit the number of files to 3
// we may extend this in the future
files = files.slice(0, 3);
}
if (!files?.length) {