Skip to content

Commit

Permalink
[Security Solution] [Endpoint] Upload action endpoint tests and other…
Browse files Browse the repository at this point in the history
… missing workflow tests for response console (elastic#168005)

## Summary

Adds missing tests for upload response action workflows.

 Adds tests for 
- [x] upload response action
- [x] responder action from Alerts -> Alert details
- [x] responder action from Cases -> Alert details
- [x] responder action from Timeline view -> Alert Details

### Checklist
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: Patryk Kopycinski <[email protected]>
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
3 people authored Oct 18, 2023
1 parent 8bd62dd commit 6fd7a86
Show file tree
Hide file tree
Showing 12 changed files with 372 additions and 25 deletions.
4 changes: 2 additions & 2 deletions x-pack/plugins/fleet/server/services/files/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import { Readable } from 'stream';
import type { estypes } from '@elastic/elasticsearch';

import type {
FleetFile,
FleetFromHostFileClientInterface,
FleetToHostFileClientInterface,
HapiReadableStream,
HostUploadedFileMetadata,
} from './types';
import type { FleetFile } from './types';
import type { HostUploadedFileMetadata } from './types';

export const createFleetFromHostFilesClientMock =
(): jest.Mocked<FleetFromHostFileClientInterface> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ describe(
const [endpointAgentId, endpointHostname] = generateRandomStringName(2);

before(() => {
login(ROLE.endpoint_response_actions_access);

indexEndpointHosts({ numResponseActions: 2 }).then((indexEndpoints) => {
endpointData = indexEndpoints;
});
Expand Down Expand Up @@ -59,6 +57,10 @@ describe(
}
});

beforeEach(() => {
login(ROLE.endpoint_response_actions_access);
});

it('enable filtering by type', () => {
cy.visit(`/app/security/administration/response_actions_history`);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* 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 { closeAllToasts } from '../../tasks/toasts';
import {
getAlertsTableRows,
openAlertDetailsView,
openInvestigateInTimelineView,
openResponderFromEndpointAlertDetails,
} from '../../screens/alerts';
import { ensureOnResponder } from '../../screens/responder';
import { cleanupRule, loadRule } from '../../tasks/api_fixtures';
import type { PolicyData } from '../../../../../common/endpoint/types';
import type { CreateAndEnrollEndpointHostResponse } from '../../../../../scripts/endpoint/common/endpoint_host_services';
import { waitForEndpointListPageToBeLoaded } from '../../tasks/response_console';
import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy';
import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet';
import { toggleRuleOffAndOn, visitRuleAlerts } from '../../tasks/isolate';

import { login } from '../../tasks/login';
import { enableAllPolicyProtections } from '../../tasks/endpoint_policy';
import { createEndpointHost } from '../../tasks/create_endpoint_host';
import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data';

describe('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
let indexedPolicy: IndexedFleetEndpointPolicyResponse;
let policy: PolicyData;
let createdHost: CreateAndEnrollEndpointHostResponse;

beforeEach(() => {
login();
});

before(() => {
getEndpointIntegrationVersion().then((version) =>
createAgentPolicyTask(version).then((data) => {
indexedPolicy = data;
policy = indexedPolicy.integrationPolicies[0];

return enableAllPolicyProtections(policy.id).then(() => {
// Create and enroll a new Endpoint host
return createEndpointHost(policy.policy_id).then((host) => {
createdHost = host as CreateAndEnrollEndpointHostResponse;
});
});
})
);
});

after(() => {
if (createdHost) {
cy.task('destroyEndpointHost', createdHost);
}

if (indexedPolicy) {
cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy);
}

if (createdHost) {
deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
}
});

describe('From Alerts', () => {
let ruleId: string;
let ruleName: string;

before(() => {
loadRule(
{ query: `agent.name: ${createdHost.hostname} and agent.type: endpoint` },
false
).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
});

after(() => {
if (ruleId) {
cleanupRule(ruleId);
}
});

it('should open responder from alert details flyout', () => {
waitForEndpointListPageToBeLoaded(createdHost.hostname);
toggleRuleOffAndOn(ruleName);
visitRuleAlerts(ruleName);
closeAllToasts();
getAlertsTableRows().should('have.length.greaterThan', 0);
openAlertDetailsView();

openResponderFromEndpointAlertDetails();
ensureOnResponder();
});

it('should open responder from timeline view alert details flyout', () => {
waitForEndpointListPageToBeLoaded(createdHost.hostname);
toggleRuleOffAndOn(ruleName);
visitRuleAlerts(ruleName);
closeAllToasts();

getAlertsTableRows().should('have.length.greaterThan', 0);
openInvestigateInTimelineView();
cy.getByTestSubj('timeline-flyout').within(() => {
openAlertDetailsView();
});
openResponderFromEndpointAlertDetails();
ensureOnResponder();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* 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 { loadPage } from '../../tasks/common';
import { closeAllToasts } from '../../tasks/toasts';
import {
addAlertToCase,
getAlertsTableRows,
openAlertDetailsView,
openResponderFromEndpointAlertDetails,
} from '../../screens/alerts';
import { ensureOnResponder } from '../../screens/responder';
import { cleanupCase, cleanupRule, loadCase, loadRule } from '../../tasks/api_fixtures';
import type { PolicyData } from '../../../../../common/endpoint/types';
import type { CreateAndEnrollEndpointHostResponse } from '../../../../../scripts/endpoint/common/endpoint_host_services';
import { waitForEndpointListPageToBeLoaded } from '../../tasks/response_console';
import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy';
import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet';
import { openCaseAlertDetails, toggleRuleOffAndOn, visitRuleAlerts } from '../../tasks/isolate';

import { login } from '../../tasks/login';
import { enableAllPolicyProtections } from '../../tasks/endpoint_policy';
import { createEndpointHost } from '../../tasks/create_endpoint_host';
import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data';
import { APP_CASES_PATH } from '../../../../../common/constants';

describe('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
let indexedPolicy: IndexedFleetEndpointPolicyResponse;
let policy: PolicyData;
let createdHost: CreateAndEnrollEndpointHostResponse;

before(() => {
getEndpointIntegrationVersion().then((version) =>
createAgentPolicyTask(version).then((data) => {
indexedPolicy = data;
policy = indexedPolicy.integrationPolicies[0];

return enableAllPolicyProtections(policy.id).then(() => {
// Create and enroll a new Endpoint host
return createEndpointHost(policy.policy_id).then((host) => {
createdHost = host as CreateAndEnrollEndpointHostResponse;
});
});
})
);
});

beforeEach(() => {
login();
});

after(() => {
if (createdHost) {
cy.task('destroyEndpointHost', createdHost);
}

if (indexedPolicy) {
cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy);
}

if (createdHost) {
deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
}
});

describe('From Cases', () => {
let ruleId: string;
let ruleName: string;
let caseId: string;
const caseOwner = 'securitySolution';

beforeEach(() => {
loadRule(
{ query: `agent.name: ${createdHost.hostname} and agent.type: endpoint` },
false
).then((data) => {
ruleId = data.id;
ruleName = data.name;
});
loadCase(caseOwner).then((data) => {
caseId = data.id;
});
});

afterEach(() => {
if (ruleId) {
cleanupRule(ruleId);
}
if (caseId) {
cleanupCase(caseId);
}
});

it('should open responder', () => {
waitForEndpointListPageToBeLoaded(createdHost.hostname);
toggleRuleOffAndOn(ruleName);
visitRuleAlerts(ruleName);
closeAllToasts();

getAlertsTableRows().should('have.length.greaterThan', 0);
openAlertDetailsView();
addAlertToCase(caseId, caseOwner);

// visit case details page
cy.intercept('GET', `/api/cases/${caseId}/user_actions/_find*`).as('case');
loadPage(`${APP_CASES_PATH}/${caseId}`);

cy.wait('@case', { timeout: 30000 }).then(({ response: res }) => {
const caseAlertId = res?.body.userActions[1].id;
closeAllToasts();
openCaseAlertDetails(caseAlertId);
});

openResponderFromEndpointAlertDetails();
ensureOnResponder();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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 { ensureOnResponder } from '../../screens/responder';
import type { PolicyData } from '../../../../../common/endpoint/types';
import type { CreateAndEnrollEndpointHostResponse } from '../../../../../scripts/endpoint/common/endpoint_host_services';
import {
openResponseConsoleFromEndpointList,
waitForEndpointListPageToBeLoaded,
} from '../../tasks/response_console';
import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy';
import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet';

import { login } from '../../tasks/login';
import { enableAllPolicyProtections } from '../../tasks/endpoint_policy';
import { createEndpointHost } from '../../tasks/create_endpoint_host';
import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data';

describe('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
beforeEach(() => {
login();
});

describe('From endpoint list', () => {
let indexedPolicy: IndexedFleetEndpointPolicyResponse;
let policy: PolicyData;
let createdHost: CreateAndEnrollEndpointHostResponse;

before(() => {
getEndpointIntegrationVersion().then((version) =>
createAgentPolicyTask(version).then((data) => {
indexedPolicy = data;
policy = indexedPolicy.integrationPolicies[0];

return enableAllPolicyProtections(policy.id).then(() => {
// Create and enroll a new Endpoint host
return createEndpointHost(policy.policy_id).then((host) => {
createdHost = host as CreateAndEnrollEndpointHostResponse;
});
});
})
);
});

after(() => {
if (createdHost) {
cy.task('destroyEndpointHost', createdHost);
}

if (indexedPolicy) {
cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy);
}

if (createdHost) {
deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
}
});

it('should open responder', () => {
waitForEndpointListPageToBeLoaded(createdHost.hostname);
openResponseConsoleFromEndpointList();
ensureOnResponder();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { openAlertDetailsView } from '../../screens/alerts';
import type { PolicyData } from '../../../../../common/endpoint/types';
import { APP_CASES_PATH, APP_ENDPOINTS_PATH } from '../../../../../common/constants';
import { closeAllToasts } from '../../tasks/toasts';
Expand All @@ -14,7 +15,6 @@ import {
checkFlyoutEndpointIsolation,
filterOutIsolatedHosts,
isolateHostWithComment,
openAlertDetails,
openCaseAlertDetails,
releaseHostWithComment,
toggleRuleOffAndOn,
Expand Down Expand Up @@ -139,15 +139,15 @@ describe.skip('Isolate command', { tags: ['@ess', '@serverless', '@brokenInServe
visitRuleAlerts(ruleName);

closeAllToasts();
openAlertDetails();
openAlertDetailsView();

isolateHostWithComment(isolateComment, createdHost.hostname);

cy.getByTestSubj('hostIsolateConfirmButton').click();
cy.contains(`Isolation on host ${createdHost.hostname} successfully submitted`);

cy.getByTestSubj('euiFlyoutCloseButton').click();
openAlertDetails();
openAlertDetailsView();

checkFlyoutEndpointIsolation();

Expand All @@ -156,7 +156,7 @@ describe.skip('Isolate command', { tags: ['@ess', '@serverless', '@brokenInServe

cy.contains(`Release on host ${createdHost.hostname} successfully submitted`);
cy.getByTestSubj('euiFlyoutCloseButton').click();
openAlertDetails();
openAlertDetailsView();
cy.getByTestSubj('event-field-agent.status').within(() => {
cy.get('[title="Isolated"]').should('not.exist');
});
Expand Down Expand Up @@ -205,7 +205,7 @@ describe.skip('Isolate command', { tags: ['@ess', '@serverless', '@brokenInServe
visitRuleAlerts(ruleName);
closeAllToasts();

openAlertDetails();
openAlertDetailsView();

cy.getByTestSubj('add-to-existing-case-action').click();
cy.getByTestSubj(`cases-table-row-select-${caseId}`).click();
Expand Down
Loading

0 comments on commit 6fd7a86

Please sign in to comment.