mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[Security Solution] Add e2e tests for Endpoint policy updates on Endpoints (#153938)
**>> Reopened to avoid unnecessary notifications for unrelated teams <<** Original PR with original comments: https://github.com/elastic/kibana/pull/152097 ## Summary Added test cases: - `endpoints.cy.ts`: - Edit a Policy assigned to a real Endpoint and confirm that the Endpoint returns a successful Policy response - `artifacts.cy.ts`: - Add a trusted application and confirm that the Endpoint returns a successful Policy response - Add an Event filter and confirm that the Endpoint returns a successful Policy response - Add a Blocklist entry and confirm that the Endpoint returns a successful Policy response - Add a Host Isolation exception and confirm that the Endpoint returns a successful Policy response To open Cypress for the new e2e test suite, first run this command: `node scripts/build_kibana_platform_plugins` Then use this command: `yarn --cwd x-pack/plugins/security_solution cypress:dw:endpoint:open-as-ci` > **Warning** > The `Endpoint reassignment` test group in `endpoints.cy.ts` will most probably fail, due to this bug: https://github.com/elastic/endpoint-dev/issues/12499 (as mentioned in the PR for that test: https://github.com/elastic/kibana/pull/151887) > > So it's the best to skip that one, otherwise the endpoint will freeze in *Out-of-date* state and you need to spin up the test suite again. --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
684203944c
commit
7ea4722fb2
7 changed files with 179 additions and 23 deletions
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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 { HOST_METADATA_LIST_ROUTE } from '../../../../../common/endpoint/constants';
|
||||
import type { MetadataListResponse } from '../../../../../common/endpoint/types';
|
||||
import { APP_ENDPOINTS_PATH } from '../../../../../common/constants';
|
||||
import { getArtifactsListTestsData } from '../../fixtures/artifacts_page';
|
||||
import { removeAllArtifacts } from '../../tasks/artifacts';
|
||||
import { loadEndpointDataForEventFiltersIfNeeded } from '../../tasks/load_endpoint_data';
|
||||
import { login } from '../../tasks/login';
|
||||
import { performUserActions } from '../../tasks/perform_user_actions';
|
||||
import { request } from '../../tasks/common';
|
||||
import { yieldEndpointPolicyRevision } from '../../tasks/fleet';
|
||||
|
||||
const yieldAppliedEndpointRevision = (): Cypress.Chainable<number> =>
|
||||
request<MetadataListResponse>({
|
||||
method: 'GET',
|
||||
url: HOST_METADATA_LIST_ROUTE,
|
||||
}).then(({ body }) => {
|
||||
expect(body.data.length).is.lte(1); // during update it can be temporary zero
|
||||
return Number(body.data?.[0]?.metadata.Endpoint.policy.applied.endpoint_policy_version) ?? -1;
|
||||
});
|
||||
|
||||
const parseRevNumber = (revString: string) => Number(revString.match(/\d+/)?.[0]);
|
||||
|
||||
describe('Artifact pages', () => {
|
||||
before(() => {
|
||||
login();
|
||||
loadEndpointDataForEventFiltersIfNeeded();
|
||||
removeAllArtifacts();
|
||||
|
||||
// wait for ManifestManager to pick up artifact changes that happened either here
|
||||
// or in a previous test suite `after`
|
||||
cy.wait(6000); // packagerTaskInterval + 1s
|
||||
|
||||
yieldEndpointPolicyRevision().then((actualEndpointPolicyRevision) => {
|
||||
const hasReachedActualRevision = (revision: number) =>
|
||||
revision === actualEndpointPolicyRevision;
|
||||
|
||||
// need to wait until revision is bumped to ensure test success
|
||||
recurse(yieldAppliedEndpointRevision, hasReachedActualRevision, { delay: 1500 });
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
removeAllArtifacts();
|
||||
});
|
||||
|
||||
for (const testData of getArtifactsListTestsData()) {
|
||||
describe(`${testData.title}`, () => {
|
||||
it(`should update Endpoint Policy on Endpoint when adding ${testData.artifactName}`, () => {
|
||||
cy.visit(APP_ENDPOINTS_PATH);
|
||||
|
||||
cy.getByTestSubj('policyListRevNo')
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then(parseRevNumber)
|
||||
.then((initialRevisionNumber) => {
|
||||
cy.visit(`/app/security/administration/${testData.urlPath}`);
|
||||
|
||||
cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).click();
|
||||
performUserActions(testData.create.formActions);
|
||||
cy.getByTestSubj(`${testData.pagePrefix}-flyout-submitButton`).click();
|
||||
|
||||
// Check new artifact is in the list
|
||||
for (const checkResult of testData.create.checkResults) {
|
||||
cy.getByTestSubj(checkResult.selector).should('have.text', checkResult.value);
|
||||
}
|
||||
|
||||
cy.visit(APP_ENDPOINTS_PATH);
|
||||
|
||||
// depends on the 10s auto refresh
|
||||
cy.getByTestSubj('policyListRevNo')
|
||||
.first()
|
||||
.should(($div) => {
|
||||
const revisionNumber = parseRevNumber($div.text());
|
||||
expect(revisionNumber).to.eq(initialRevisionNumber + 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { Agent } from '@kbn/fleet-plugin/common';
|
||||
import { APP_ENDPOINTS_PATH } from '../../../../../common/constants';
|
||||
import { ENDPOINT_VM_NAME } from '../../tasks/common';
|
||||
import {
|
||||
getAgentByHostName,
|
||||
|
@ -13,7 +14,6 @@ import {
|
|||
reassignAgentPolicy,
|
||||
} from '../../tasks/fleet';
|
||||
import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy';
|
||||
import { getEndpointListPath } from '../../../common/routing';
|
||||
import { login } from '../../tasks/login';
|
||||
import {
|
||||
AGENT_HOSTNAME_CELL,
|
||||
|
@ -34,7 +34,7 @@ describe('Endpoints page', () => {
|
|||
});
|
||||
|
||||
it('Shows endpoint on the list', () => {
|
||||
cy.visit(getEndpointListPath({ name: 'endpointList' }));
|
||||
cy.visit(APP_ENDPOINTS_PATH);
|
||||
cy.contains('Hosts running Elastic Defend').should('exist');
|
||||
cy.getByTestSubj(AGENT_HOSTNAME_CELL).should('have.text', endpointHostname);
|
||||
});
|
||||
|
@ -48,9 +48,12 @@ describe('Endpoints page', () => {
|
|||
initialAgentData = agentData;
|
||||
});
|
||||
getEndpointIntegrationVersion().then((version) => {
|
||||
const policyName = `Reassign ${Math.random().toString(36).substring(2, 7)}`;
|
||||
|
||||
cy.task<IndexedFleetEndpointPolicyResponse>('indexFleetEndpointPolicy', {
|
||||
policyName: `Reassign ${Math.random().toString(36).substr(2, 5)}`,
|
||||
policyName,
|
||||
endpointPackageVersion: version,
|
||||
agentPolicyName: policyName,
|
||||
}).then((data) => {
|
||||
response = data;
|
||||
});
|
||||
|
@ -71,7 +74,7 @@ describe('Endpoints page', () => {
|
|||
});
|
||||
|
||||
it('User can reassign a single endpoint to a different Agent Configuration', () => {
|
||||
cy.visit(getEndpointListPath({ name: 'endpointList' }));
|
||||
cy.visit(APP_ENDPOINTS_PATH);
|
||||
const hostname = cy
|
||||
.getByTestSubj(AGENT_HOSTNAME_CELL)
|
||||
.filter(`:contains("${endpointHostname}")`);
|
||||
|
@ -92,4 +95,38 @@ describe('Endpoints page', () => {
|
|||
.should('have.text', response.agentPolicies[0].name);
|
||||
});
|
||||
});
|
||||
|
||||
it('should update endpoint policy on Endpoint', () => {
|
||||
const parseRevNumber = (revString: string) => Number(revString.match(/\d+/)?.[0]);
|
||||
|
||||
cy.visit(APP_ENDPOINTS_PATH);
|
||||
|
||||
cy.getByTestSubj('policyListRevNo')
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then(parseRevNumber)
|
||||
.then((initialRevisionNumber) => {
|
||||
// Update policy
|
||||
cy.getByTestSubj('policyNameCellLink').first().click();
|
||||
|
||||
cy.getByTestSubj('policyDetailsSaveButton').click();
|
||||
cy.getByTestSubj('policyDetailsConfirmModal').should('exist');
|
||||
cy.getByTestSubj('confirmModalConfirmButton').click();
|
||||
cy.contains(/has been updated/);
|
||||
|
||||
cy.getByTestSubj('policyDetailsBackLink').click();
|
||||
|
||||
// Assert disappearing 'Out-of-date' indicator, Success Policy Status and increased revision number
|
||||
cy.getByTestSubj('rowPolicyOutOfDate').should('exist');
|
||||
cy.getByTestSubj('rowPolicyOutOfDate').should('not.exist'); // depends on the 10s auto-refresh
|
||||
|
||||
cy.getByTestSubj('policyStatusCellLink').first().should('contain', 'Success');
|
||||
|
||||
cy.getByTestSubj('policyListRevNo')
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then(parseRevNumber)
|
||||
.should('equal', initialRevisionNumber + 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -81,12 +81,12 @@ describe('Artifact tabs in Policy Details page', () => {
|
|||
});
|
||||
|
||||
for (const testData of getArtifactsListTestsData()) {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
removeExceptionsList(testData.createRequestBody.list_id);
|
||||
});
|
||||
|
||||
describe(`${testData.title} tab`, () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
removeExceptionsList(testData.createRequestBody.list_id);
|
||||
});
|
||||
|
||||
it(`[NONE] User cannot see the tab for ${testData.title}`, () => {
|
||||
loginWithPrivilegeNone(testData.privilegePrefix);
|
||||
visitPolicyDetailsPage();
|
||||
|
|
|
@ -54,12 +54,19 @@ export const dataLoaders = (
|
|||
indexFleetEndpointPolicy: async ({
|
||||
policyName,
|
||||
endpointPackageVersion,
|
||||
agentPolicyName,
|
||||
}: {
|
||||
policyName: string;
|
||||
endpointPackageVersion: string;
|
||||
agentPolicyName?: string;
|
||||
}) => {
|
||||
const { kbnClient } = await stackServicesPromise;
|
||||
return indexFleetEndpointPolicy(kbnClient, policyName, endpointPackageVersion);
|
||||
return indexFleetEndpointPolicy(
|
||||
kbnClient,
|
||||
policyName,
|
||||
endpointPackageVersion,
|
||||
agentPolicyName
|
||||
);
|
||||
},
|
||||
|
||||
deleteIndexedFleetEndpointPolicies: async (indexData: IndexedFleetEndpointPolicyResponse) => {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { GetPackagePoliciesResponse } from '@kbn/fleet-plugin/common';
|
||||
import { PACKAGE_POLICY_API_ROOT } from '@kbn/fleet-plugin/common';
|
||||
import type {
|
||||
ExceptionListItemSchema,
|
||||
|
@ -79,14 +80,11 @@ export const createPerPolicyArtifact = (name: string, body: object, policyId?: '
|
|||
});
|
||||
};
|
||||
|
||||
export const yieldFirstPolicyID = () => {
|
||||
return cy
|
||||
.request({
|
||||
method: 'GET',
|
||||
url: `${PACKAGE_POLICY_API_ROOT}?page=1&perPage=1&kuery=ingest-package-policies.package.name: endpoint`,
|
||||
})
|
||||
.then(({ body }) => {
|
||||
expect(body.items.length).to.be.least(1);
|
||||
return body.items[0].id;
|
||||
});
|
||||
};
|
||||
export const yieldFirstPolicyID = (): Cypress.Chainable<string> =>
|
||||
request<GetPackagePoliciesResponse>({
|
||||
method: 'GET',
|
||||
url: `${PACKAGE_POLICY_API_ROOT}?page=1&perPage=1&kuery=ingest-package-policies.package.name: endpoint`,
|
||||
}).then(({ body }) => {
|
||||
expect(body.items.length).to.be.least(1);
|
||||
return body.items[0].id;
|
||||
});
|
||||
|
|
|
@ -5,8 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Agent, GetAgentsResponse, GetInfoResponse } from '@kbn/fleet-plugin/common';
|
||||
import { agentRouteService, epmRouteService } from '@kbn/fleet-plugin/common';
|
||||
import type {
|
||||
Agent,
|
||||
GetAgentsResponse,
|
||||
GetInfoResponse,
|
||||
GetPackagePoliciesResponse,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
agentRouteService,
|
||||
epmRouteService,
|
||||
packagePolicyRouteService,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import type { PutAgentReassignResponse } from '@kbn/fleet-plugin/common/types';
|
||||
import { request } from './common';
|
||||
|
||||
|
@ -36,3 +45,14 @@ export const reassignAgentPolicy = (
|
|||
policy_id: agentPolicyId,
|
||||
},
|
||||
});
|
||||
|
||||
export const yieldEndpointPolicyRevision = (): Cypress.Chainable<number> =>
|
||||
request<GetPackagePoliciesResponse>({
|
||||
method: 'GET',
|
||||
url: packagePolicyRouteService.getListPath(),
|
||||
qs: {
|
||||
kuery: 'ingest-package-policies.package.name: endpoint',
|
||||
},
|
||||
}).then(({ body }) => {
|
||||
return body.items?.[0]?.revision ?? -1;
|
||||
});
|
||||
|
|
|
@ -25,6 +25,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
`--xpack.fleet.agents.elasticsearch.host=http://${hostIp}:${defendWorkflowsCypressConfig.get(
|
||||
'servers.elasticsearch.port'
|
||||
)}`,
|
||||
// set the packagerTaskInterval to 5s in order to speed up test executions when checking fleet artifacts
|
||||
'--xpack.securitySolution.packagerTaskInterval=5s',
|
||||
],
|
||||
},
|
||||
testRunner: DefendWorkflowsCypressEndpointTestRunner,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue