diff --git a/src/platform/packages/shared/kbn-es/src/serverless_resources/project_roles/security/roles.yml b/src/platform/packages/shared/kbn-es/src/serverless_resources/project_roles/security/roles.yml index b194d79f4b745..e6e8dabf7e758 100644 --- a/src/platform/packages/shared/kbn-es/src/serverless_resources/project_roles/security/roles.yml +++ b/src/platform/packages/shared/kbn-es/src/serverless_resources/project_roles/security/roles.yml @@ -125,6 +125,7 @@ editor: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all @@ -315,6 +316,7 @@ t3_analyst: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all @@ -464,6 +466,7 @@ rule_author: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_read - feature_siemV3.blocklist_all # Elastic Defend Policy Management @@ -540,6 +543,7 @@ soc_manager: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all @@ -680,6 +684,7 @@ platform_engineer: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all # Elastic Defend Policy Management @@ -756,6 +761,7 @@ endpoint_operations_analyst: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all diff --git a/x-pack/solutions/security/plugins/security_solution/common/constants.ts b/x-pack/solutions/security/plugins/security_solution/common/constants.ts index 9f0bb5dfc0581..e8a2beefa30b5 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/constants.ts @@ -142,6 +142,7 @@ export const APP_POLICIES_PATH = `${APP_PATH}${POLICIES_PATH}` as const; export const APP_ENDPOINT_EXCEPTIONS_PATH = `${APP_PATH}${ENDPOINT_EXCEPTIONS_PATH}` as const; export const APP_MANAGE_PATH = `${APP_PATH}${MANAGE_PATH}` as const; export const APP_TRUSTED_APPS_PATH = `${APP_PATH}${TRUSTED_APPS_PATH}` as const; +export const APP_TRUSTED_DEVICES_PATH = `${APP_PATH}${TRUSTED_DEVICES_PATH}` as const; export const APP_EVENT_FILTERS_PATH = `${APP_PATH}${EVENT_FILTERS_PATH}` as const; export const APP_HOST_ISOLATION_EXCEPTIONS_PATH = `${APP_PATH}${HOST_ISOLATION_EXCEPTIONS_PATH}` as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/artifacts/trusted_devices.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/artifacts/trusted_devices.cy.ts new file mode 100644 index 0000000000000..574cab36ed474 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/artifacts/trusted_devices.cy.ts @@ -0,0 +1,159 @@ +/* + * 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 { ENDPOINT_ARTIFACT_LISTS } from '@kbn/securitysolution-list-constants'; +import { + createArtifactList, + createPerPolicyArtifact, + removeExceptionsList, + trustedDevicesFormSelectors, +} from '../../tasks/artifacts'; +import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; +import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet'; +import { login } from '../../tasks/login'; + +const { + openTrustedDevices, + selectOs, + selectField, + selectOperator, + fillValue, + fillOutTrustedDevicesFlyout, + submitForm, + validateSuccessPopup, + validateRenderedCondition, + deleteTrustedDeviceItem, +} = trustedDevicesFormSelectors; + +describe( + 'Trusted Devices', + { + tags: ['@ess', '@serverless', '@skipInServerlessMKI'], + env: { + ftrConfig: { + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], + }, + }, + }, + () => { + let indexedPolicy: IndexedFleetEndpointPolicyResponse; + + before(() => { + getEndpointIntegrationVersion().then((version) => { + createAgentPolicyTask(version).then((data) => { + indexedPolicy = data; + }); + }); + }); + + beforeEach(() => { + login(); + }); + + after(() => { + if (indexedPolicy) { + cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy); + } + }); + + const createArtifactBodyRequest = () => ({ + list_id: ENDPOINT_ARTIFACT_LISTS.trustedDevices.id, + entries: [ + { + field: 'user.name', + operator: 'included', + type: 'match', + value: 'test-user', + }, + ], + os_types: ['windows', 'macos'], + }); + + describe('Renders Trusted Devices form fields', () => { + it('Correctly renders trusted devices form for Windows and Mac', () => { + openTrustedDevices({ create: true }); + + selectOs('Windows and Mac'); + + selectField('Username'); + selectOperator('is'); + fillValue('test-user'); + }); + + it('Renders all field options correctly', () => { + openTrustedDevices({ create: true }); + selectOs('Windows and Mac'); + + const fields: Array<'Username' | 'Host' | 'Device ID' | 'Manufacturer' | 'Product ID'> = [ + 'Username', + 'Host', + 'Device ID', + 'Manufacturer', + 'Product ID', + ]; + + fields.forEach((field) => { + selectField(field); + cy.getByTestSubj('trustedDevices-form-fieldSelect').should('contain', field); + }); + }); + }); + + describe('Handles CRUD with device fields', () => { + afterEach(() => { + removeExceptionsList(ENDPOINT_ARTIFACT_LISTS.trustedDevices.id); + }); + + it('Correctly creates a trusted device with a single username field on Windows and Mac', () => { + const expectedCondition = /user\.name\s*IS\s*test-user/i; + + openTrustedDevices({ create: true }); + fillOutTrustedDevicesFlyout(); + selectOs('Windows and Mac'); + selectField('Username'); + selectOperator('is'); + fillValue('test-user'); + submitForm(); + + validateSuccessPopup('create'); + validateRenderedCondition(expectedCondition); + }); + + describe('Correctly updates and deletes trusted device with single username field', () => { + let itemId: string; + + beforeEach(() => { + createArtifactList(ENDPOINT_ARTIFACT_LISTS.trustedDevices.id); + createPerPolicyArtifact('Test Trusted Device', createArtifactBodyRequest()).then( + (response) => { + itemId = response.body.item_id; + } + ); + }); + + it('Updates trusted device username field item', () => { + const expectedCondition = /user\.name\s*IS\s*updated-user/i; + + openTrustedDevices({ itemId }); + fillValue('updated-user'); + submitForm(); + + validateSuccessPopup('update'); + validateRenderedCondition(expectedCondition); + }); + + it('Deletes a trusted device item', () => { + openTrustedDevices(); + deleteTrustedDeviceItem(); + validateSuccessPopup('delete'); + }); + }); + }); + } +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/artifacts/trusted_devices_rbac.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/artifacts/trusted_devices_rbac.cy.ts new file mode 100644 index 0000000000000..1fd8fa1ca0685 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/artifacts/trusted_devices_rbac.cy.ts @@ -0,0 +1,25 @@ +/* + * 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 { getArtifactsListTestDataForArtifact } from '../../fixtures/artifacts_page'; +import { getArtifactMockedDataTests } from '../../support/artifacts_rbac_runner'; + +describe( + 'Trusted devices RBAC', + { + tags: ['@ess', '@serverless', '@skipInServerlessMKI'], + env: { + ftrConfig: { + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], + }, + }, + }, + + getArtifactMockedDataTests(getArtifactsListTestDataForArtifact('trustedDevices'), ['siemV3']) +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac.cy.ts index e1c4055bbabf4..c5b25dab080a5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac.cy.ts @@ -20,6 +20,13 @@ describe( 'When defining a kibana role for Endpoint security access', { tags: '@ess', + env: { + ftrConfig: { + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], + }, + }, }, () => { const getAllSubFeatureRows = (): Cypress.Chainable> => { @@ -55,6 +62,7 @@ describe( 'Automatic Troubleshooting Access to the automatic troubleshooting.Automatic Troubleshooting sub-feature privilegeAllReadNone', 'Global Artifact Management Manage global assignment of endpoint artifacts (e.g., Trusted Applications, Event Filters) across all policies. This privilege controls global assignment rights only; privileges for each artifact type are required for full artifact management.Global Artifact Management sub-feature privilegeAllNone', 'Trusted Applications Helps mitigate conflicts with other software, usually other antivirus or endpoint security applications.Trusted Applications sub-feature privilegeAllReadNone', + 'Trusted Devices Allows management of trusted USB and external devices that bypass device control protections.Trusted Devices sub-feature privilegeAllReadNone', 'Host Isolation Exceptions Add specific IP addresses that isolated hosts are still allowed to communicate with, even when isolated from the rest of the network.Host Isolation Exceptions sub-feature privilegeAllReadNone', 'Blocklist Extend Elastic Defend’s protection against malicious processes and protect against potentially harmful applications.Blocklist sub-feature privilegeAllReadNone', 'Event Filters Filter out endpoint events that you do not need or want stored in Elasticsearch.Event Filters sub-feature privilegeAllReadNone', diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts index e5f8c1bf4aad0..80871ec94a4c1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/endpoint_role_rbac_with_space_awareness.cy.ts @@ -38,6 +38,7 @@ describe( kbnServerArgs: [ `--xpack.securitySolution.enableExperimental=${JSON.stringify([ 'endpointManagementSpaceAwarenessEnabled', + 'trustedDevices', ])}`, ], }, @@ -107,6 +108,7 @@ describe( 'Automatic TroubleshootingNone', 'Global Artifact ManagementNone', 'Trusted ApplicationsNone', + 'Trusted DevicesNone', 'Host Isolation ExceptionsNone', 'BlocklistNone', 'Event FiltersNone', diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts index d95a11752a63b..ccc2c1468aa8e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts @@ -9,137 +9,168 @@ import * as ServerlessHeaders from '@kbn/test-suites-xpack-security/security_sol import * as EssHeaders from '@kbn/test-suites-xpack-security/security_solution_cypress/cypress/screens/security_header'; import { login, ROLE } from '../../tasks/login'; import { loadPage } from '../../tasks/common'; +import type { SiemVersion } from '../../common/constants'; import { SIEM_VERSIONS } from '../../common/constants'; - -describe('Navigation RBAC', () => { - const isServerless = Cypress.env('IS_SERVERLESS'); - - const Selectors = isServerless ? ServerlessHeaders : EssHeaders; - const MenuButtonSelector = isServerless - ? ServerlessHeaders.ASSETS_PANEL_BTN - : EssHeaders.SETTINGS_PANEL_BTN; - - const pages = [ - { - name: 'Endpoints', - privilegePrefix: 'endpoint_list_', - selector: Selectors.ENDPOINTS, - }, - { - name: 'Policies', - privilegePrefix: 'policy_management_', - selector: Selectors.POLICIES, - }, - { - name: 'Trusted applications', - privilegePrefix: 'trusted_applications_', - selector: Selectors.TRUSTED_APPS, +import { SECURITY_FEATURE_ID } from '../../../../../common/constants'; + +describe( + 'Navigation RBAC', + { + env: { + ftrConfig: { + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], + }, }, - { - name: 'Event filters', - privilegePrefix: 'event_filters_', - selector: Selectors.EVENT_FILTERS, - }, - { - name: 'Blocklist', - privilegePrefix: 'blocklist_', - selector: Selectors.BLOCKLIST, - }, - { - name: 'Host isolation exceptions', - privilegePrefix: 'host_isolation_exceptions_', - selector: Selectors.HOST_ISOLATION_EXCEPTIONS, - }, - { - name: 'Response actions history', - privilegePrefix: 'actions_log_management_', - selector: Selectors.RESPONSE_ACTIONS_HISTORY, - }, - ]; - - describe('ESS - using custom roles', { tags: ['@ess'] }, () => { - for (const siemVersion of SIEM_VERSIONS) { - describe(siemVersion, () => { - describe('NONE access', () => { - beforeEach(() => { - login.withCustomKibanaPrivileges({ [siemVersion]: ['all'] }); - }); + }, + () => { + const isServerless = Cypress.env('IS_SERVERLESS'); + + const Selectors = isServerless ? ServerlessHeaders : EssHeaders; + const MenuButtonSelector = isServerless + ? ServerlessHeaders.ASSETS_PANEL_BTN + : EssHeaders.SETTINGS_PANEL_BTN; + + const allPages = [ + { + name: 'Endpoints', + privilegePrefix: 'endpoint_list_', + selector: Selectors.ENDPOINTS, + }, + { + name: 'Policies', + privilegePrefix: 'policy_management_', + selector: Selectors.POLICIES, + }, + { + name: 'Trusted applications', + privilegePrefix: 'trusted_applications_', + selector: Selectors.TRUSTED_APPS, + }, + { + name: 'Trusted devices', + privilegePrefix: 'trusted_devices_', + selector: Selectors.TRUSTED_DEVICES, + siemVersions: [SECURITY_FEATURE_ID as SiemVersion], // Only available in siemV3 + }, + { + name: 'Event filters', + privilegePrefix: 'event_filters_', + selector: Selectors.EVENT_FILTERS, + }, + { + name: 'Blocklist', + privilegePrefix: 'blocklist_', + selector: Selectors.BLOCKLIST, + }, + { + name: 'Host isolation exceptions', + privilegePrefix: 'host_isolation_exceptions_', + selector: Selectors.HOST_ISOLATION_EXCEPTIONS, + }, + { + name: 'Response actions history', + privilegePrefix: 'actions_log_management_', + selector: Selectors.RESPONSE_ACTIONS_HISTORY, + }, + ]; + + const getPagesForSiemVersion = (siemVersion: SiemVersion) => { + return allPages.filter( + (page) => !page.siemVersions || page.siemVersions.includes(siemVersion) + ); + }; + + describe('ESS - using custom roles', { tags: ['@ess'] }, () => { + for (const siemVersion of SIEM_VERSIONS) { + describe(siemVersion, () => { + const pages = getPagesForSiemVersion(siemVersion); + + describe('NONE access', () => { + beforeEach(() => { + login.withCustomKibanaPrivileges({ [siemVersion]: ['all'] }); + }); - it(`none of the links should be visible in navigation bar`, () => { - loadPage('/app/security'); - cy.get(MenuButtonSelector).click(); + it(`none of the links should be visible in navigation bar`, () => { + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); - for (const page of pages) { - cy.get(page.selector).should('not.exist'); - } - }); + for (const page of pages) { + cy.get(page.selector).should('not.exist'); + } + }); - it(`none of the cards should be visible on Management page`, () => { - loadPage('/app/security/manage'); + it(`none of the cards should be visible on Management page`, () => { + loadPage('/app/security/manage'); - for (const page of pages) { - cy.getByTestSubj('LandingItem').should('not.contain.text', page.name); - } + for (const page of pages) { + cy.getByTestSubj('LandingItem').should('not.contain.text', page.name); + } + }); }); - }); - for (const access of ['read', 'all']) { - for (const page of pages) { - describe(`${access.toUpperCase()} access only to ${page.name}`, () => { - beforeEach(() => { - login.withCustomKibanaPrivileges({ - [siemVersion]: ['read', `${page.privilegePrefix}${access}`], + for (const access of ['read', 'all']) { + for (const page of pages) { + describe(`${access.toUpperCase()} access only to ${page.name}`, () => { + beforeEach(() => { + login.withCustomKibanaPrivileges({ + [siemVersion]: ['read', `${page.privilegePrefix}${access}`], + }); }); - }); - it(`only ${page.name} link should be displayed in navigation bar`, () => { - loadPage('/app/security'); - cy.get(MenuButtonSelector).click(); + it(`only ${page.name} link should be displayed in navigation bar`, () => { + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); - cy.get(page.selector); - pages - .filter((iterator) => iterator.name !== page.name) - .forEach((otherPage) => cy.get(otherPage.selector).should('not.exist')); - }); + cy.get(page.selector); + pages + .filter((iterator) => iterator.name !== page.name) + .forEach((otherPage) => cy.get(otherPage.selector).should('not.exist')); + }); - it(`only ${page.name} card should be displayed on Management page`, () => { - loadPage('/app/security/manage'); + it(`only ${page.name} card should be displayed on Management page`, () => { + loadPage('/app/security/manage'); - cy.contains(page.name); - pages - .filter((iterator) => iterator.name !== page.name) - .forEach((otherPage) => - cy.getByTestSubj('LandingItem').should('not.contain.text', otherPage.name) - ); + cy.contains(page.name); + pages + .filter((iterator) => iterator.name !== page.name) + .forEach((otherPage) => + cy.getByTestSubj('LandingItem').should('not.contain.text', otherPage.name) + ); + }); }); - }); + } } - } - }); - } - }); - - describe('Serverless - using prebuilt roles (for now)', { tags: ['@serverless'] }, () => { - it('without access to any of the subpages, none of those should be displayed', () => { - login(ROLE.detections_admin); - loadPage('/app/security'); - cy.get(MenuButtonSelector).click(); - cy.get('[data-test-subj~="sideNavPanel-id-securityGroup:assets"]'); - - for (const page of pages) { - cy.get(page.selector).should('not.exist'); + }); } }); - it('with access to all of the subpages, all of those should be displayed', () => { - login(ROLE.soc_manager); - loadPage('/app/security'); - cy.get(MenuButtonSelector).click(); - cy.get('[data-test-subj~="sideNavPanel-id-securityGroup:assets"]'); + describe('Serverless - using prebuilt roles (for now)', { tags: ['@serverless'] }, () => { + it('without access to any of the subpages, none of those should be displayed', () => { + login(ROLE.detections_admin); + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); + cy.get('[data-test-subj~="sideNavPanel-id-securityGroup:assets"]'); - for (const page of pages) { - cy.get(page.selector); - } + for (const page of allPages) { + cy.get(page.selector).should('not.exist'); + } + }); + + it('with access to all of the subpages, all of those should be displayed', () => { + login(ROLE.soc_manager); + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); + cy.get('[data-test-subj~="sideNavPanel-id-securityGroup:assets"]'); + + for (const page of allPages) { + if (page.selector !== Selectors.TRUSTED_DEVICES) { + // Skip Trusted Devices for now — soc_manager does not yet have the required privilege in controller (MKI would fail otherwise). + cy.get(page.selector); + } + } + }); }); - }); -}); + } +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts index db3daf1bf466e..bc513fe6905b6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete.cy.ts @@ -20,11 +20,9 @@ describe( productTypes: [{ product_line: 'security', product_tier: 'complete' }], // This is not needed for this test, but it's a good example of // how to enable experimental features in the Cypress tests. - // kbnServerArgs: [ - // `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - // 'featureFlagName', - // ])}`, - // ], + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], }, }, }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts index fa48a2589a9c9..a35f5f223b401 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/complete_with_endpoint.cy.ts @@ -24,13 +24,9 @@ describe( { product_line: 'security', product_tier: 'complete' }, { product_line: 'endpoint', product_tier: 'complete' }, ], - // This is not needed for this test, but it's a good example of - // how to enable experimental features in the Cypress tests. - // kbnServerArgs: [ - // `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - // 'featureFlagName', - // ])}`, - // ], + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], }, }, }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts index f1089f3ded978..86ed4c37fa4fa 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials.cy.ts @@ -18,13 +18,9 @@ describe( env: { ftrConfig: { productTypes: [{ product_line: 'security', product_tier: 'essentials' }], - // This is not needed for this test, but it's a good example of - // how to enable experimental features in the Cypress tests. - // kbnServerArgs: [ - // `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - // 'featureFlagName', - // ])}`, - // ], + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], }, }, }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts index b700df4880a7d..4d0835b6bae9e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/feature_access/essentials_with_endpoint.cy.ts @@ -24,13 +24,9 @@ describe( { product_line: 'security', product_tier: 'essentials' }, { product_line: 'endpoint', product_tier: 'essentials' }, ], - // This is not needed for this test, but it's a good example of - // how to enable experimental features in the Cypress tests. - // kbnServerArgs: [ - // `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - // 'featureFlagName', - // ])}`, - // ], + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], }, }, }, @@ -44,7 +40,11 @@ describe( allPages.blocklist, allPages.eventFilters, ]; - const deniedPages = [allPages.responseActionLog, allPages.hostIsolationExceptions]; + const deniedPages = [ + allPages.responseActionLog, + allPages.hostIsolationExceptions, + allPages.trustedDevices, + ]; let username: string; let password: string; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts index ca3d0b9f6c1a1..ca22891247698 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/complete_with_endpoint_roles.cy.ts @@ -40,11 +40,9 @@ describe( { product_line: 'security', product_tier: 'complete' }, { product_line: 'endpoint', product_tier: 'complete' }, ], - // This is not needed for this test, but it's a good example of - // how to enable experimental features in the Cypress tests. - // kbnServerArgs: [ - // `--xpack.securitySolution.enableExperimental=${JSON.stringify(['featureFlagName'])}`, - // ], + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], }, }, }, @@ -110,6 +108,7 @@ describe( describe('for role: t3_analyst', () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.hostIsolationExceptions, pageById.blocklist, @@ -224,6 +223,7 @@ describe( describe('for role: rule_author', () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, ]; @@ -273,6 +273,7 @@ describe( describe('for role: soc_manager', () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, pageById.hostIsolationExceptions, @@ -319,6 +320,7 @@ describe( describe('for role: endpoint_operations_analyst', () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, pageById.hostIsolationExceptions, @@ -362,6 +364,7 @@ describe( describe(`for role: ${roleName}`, () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, pageById.hostIsolationExceptions, diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts index 31f5578ab07c2..4e776025f7d59 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts @@ -34,6 +34,9 @@ describe.skip( { product_line: 'security', product_tier: 'essentials' }, { product_line: 'endpoint', product_tier: 'essentials' }, ], + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['trustedDevices'])}`, + ], }, }, }, @@ -85,6 +88,7 @@ describe.skip( describe('for role: t3_analyst', () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, ]; @@ -159,6 +163,7 @@ describe.skip( describe('for role: rule_author', () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, ]; @@ -202,6 +207,7 @@ describe.skip( describe('for role: soc_manager', () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, ]; @@ -246,6 +252,7 @@ describe.skip( describe(`for role: ${roleName}`, () => { const artifactPagesFullAccess = [ pageById.trustedApps, + pageById.trustedDevices, pageById.eventFilters, pageById.blocklist, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts index 2630a64cdb794..eb4bfd9b4c409 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts @@ -508,4 +508,116 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [ os_types: ['windows', 'linux', 'macos'], }, }, + { + title: 'Trusted devices', + pagePrefix: 'trustedDevicesList', + tabId: 'trustedDevices', + nextTabId: 'trustedApps', + artifactName: 'Trusted device name', + privilegePrefix: 'trusted_devices_', + create: { + formActions: [ + { + type: 'input', + selector: 'trustedDevices-form-nameTextField', + value: 'Trusted device name', + }, + { + type: 'input', + selector: 'trustedDevices-form-descriptionField', + value: 'This is the trusted device description', + }, + { + type: 'click', + selector: 'trustedDevices-form-osSelectField', + }, + { + type: 'click', + customSelector: '[role="option"]:contains("Windows and Mac")', + }, + { + type: 'click', + selector: 'trustedDevices-form-fieldSelect', + }, + { + type: 'click', + customSelector: '[role="option"]:contains("Username")', + }, + { + type: 'input', + selector: 'trustedDevices-form-valueField', + value: 'test-user', + }, + ], + checkResults: [ + { + selector: 'trustedDevicesList-card-criteriaConditions', + value: ' OSIS Windows, MacAND user.nameIS test-user', + }, + ], + }, + update: { + formActions: [ + { + type: 'clear', + selector: 'trustedDevices-form-nameTextField', + }, + { + type: 'input', + selector: 'trustedDevices-form-nameTextField', + value: 'Trusted device name edited', + }, + { + type: 'clear', + selector: 'trustedDevices-form-descriptionField', + }, + { + type: 'input', + selector: 'trustedDevices-form-descriptionField', + value: 'This is the trusted device description edited', + }, + { + type: 'clear', + selector: 'trustedDevices-form-valueField', + }, + { + type: 'input', + selector: 'trustedDevices-form-valueField', + value: 'updated-user', + }, + ], + checkResults: [ + { + selector: 'trustedDevicesList-card-criteriaConditions', + value: ' OSIS Windows, MacAND user.nameIS test-user', + }, + { + selector: 'trustedDevicesList-card-header-title', + value: 'Trusted device name edited', + }, + { + selector: 'trustedDevicesList-card-description', + value: 'This is the trusted device description edited', + }, + ], + }, + delete: { + confirmSelector: 'trustedDevicesList-deleteModal-submitButton', + card: 'trustedDevicesList-card', + }, + urlPath: 'trusted_devices', + emptyState: 'trustedDevicesList-emptyState', + createRequestBody: { + list_id: ENDPOINT_ARTIFACT_LISTS.trustedDevices.id, + entries: [ + { + field: 'user.name', + operator: 'included', + type: 'match', + value: 'test-user', + }, + ], + os_types: ['windows', 'macos'], + }, + }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/artifacts.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/artifacts.ts index 10bd7728197d7..994b1d94056ca 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/artifacts.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/artifacts.ts @@ -13,6 +13,7 @@ import type { UserAuthzAccessLevel } from './types'; const artifactPageTopTestSubjPrefix: Readonly> = { trustedApps: 'trustedAppsListPage', + trustedDevices: 'trustedDevicesList', eventFilters: 'EventFiltersListPage', hostIsolationExceptions: 'hostIsolationExceptionsListPage', blocklist: 'blocklistPage', diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/page_reference.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/page_reference.ts index 5ebdeda5ddcbb..890517a924ee4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/page_reference.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/screens/page_reference.ts @@ -14,12 +14,14 @@ import { APP_POLICIES_PATH, APP_RESPONSE_ACTIONS_HISTORY_PATH, APP_TRUSTED_APPS_PATH, + APP_TRUSTED_DEVICES_PATH, } from '../../../../common/constants'; export interface EndpointManagementPageMap { endpointList: EndpointManagementPage; policyList: EndpointManagementPage; trustedApps: EndpointManagementPage; + trustedDevices: EndpointManagementPage; eventFilters: EndpointManagementPage; hostIsolationExceptions: EndpointManagementPage; blocklist: EndpointManagementPage; @@ -29,7 +31,7 @@ export interface EndpointManagementPageMap { export type EndpointManagementPageId = keyof EndpointManagementPageMap; export type EndpointArtifactPageId = keyof Pick< EndpointManagementPageMap, - 'trustedApps' | 'eventFilters' | 'hostIsolationExceptions' | 'blocklist' + 'trustedApps' | 'trustedDevices' | 'eventFilters' | 'hostIsolationExceptions' | 'blocklist' >; interface EndpointManagementPage { @@ -59,6 +61,12 @@ export const getEndpointManagementPageList = (): EndpointManagementPage[] => { url: APP_TRUSTED_APPS_PATH, pageTestSubj: 'trustedAppsListPage-container', }, + { + id: 'trustedDevices', + title: 'Trusted Devices Page', + url: APP_TRUSTED_DEVICES_PATH, + pageTestSubj: 'trustedDevicesList-container', + }, { id: 'eventFilters', title: 'Event Filters page', diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/support/artifacts_rbac_runner.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/support/artifacts_rbac_runner.ts index 5095699e79a57..27ca4930275fd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/support/artifacts_rbac_runner.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/support/artifacts_rbac_runner.ts @@ -18,6 +18,7 @@ import { performUserActions } from '../tasks/perform_user_actions'; import { indexEndpointHosts } from '../tasks/index_endpoint_hosts'; import type { ReturnTypeFromChainable } from '../types'; import { SIEM_VERSIONS } from '../common/constants'; +import type { SiemVersion } from '../common/constants'; import { SECURITY_FEATURE_ID } from '../../../../common'; /** @@ -32,181 +33,190 @@ import { SECURITY_FEATURE_ID } from '../../../../common'; * * Possible improvement: use custom roles on serverless to test the same as on ESS. */ -export const getArtifactMockedDataTests = (testData: ArtifactsFixtureType) => () => { - let endpointData: ReturnTypeFromChainable | undefined; - - const isServerless = Cypress.env('IS_SERVERLESS'); - const siemVersionsToTest = isServerless ? [SECURITY_FEATURE_ID] : SIEM_VERSIONS; - - let loginWithoutAccess: () => void; - let loginWithReadAccess: () => void; - let loginWithWriteAccess: () => void; - - before(() => { - indexEndpointHosts().then((indexEndpoints) => { - endpointData = indexEndpoints; +export const getArtifactMockedDataTests = + (testData: ArtifactsFixtureType, overrideSiemVersions?: SiemVersion[]) => () => { + let endpointData: ReturnTypeFromChainable | undefined; + + const isServerless = Cypress.env('IS_SERVERLESS'); + const siemVersionsToTest = isServerless + ? [SECURITY_FEATURE_ID] + : overrideSiemVersions || SIEM_VERSIONS; + + let loginWithoutAccess: () => void; + let loginWithReadAccess: () => void; + let loginWithWriteAccess: () => void; + + before(() => { + indexEndpointHosts().then((indexEndpoints) => { + endpointData = indexEndpoints; + }); }); - }); - beforeEach(() => { - removeAllArtifacts(); - }); - - after(() => { - removeAllArtifacts(); + beforeEach(() => { + removeAllArtifacts(); + }); - endpointData?.cleanup(); - endpointData = undefined; - }); + after(() => { + removeAllArtifacts(); - for (const siemVersion of siemVersionsToTest) { - describe(siemVersion, () => { - describe(`When on the ${testData.title} entries list`, () => { - beforeEach(() => { - const { privilegePrefix } = testData; + endpointData?.cleanup(); + endpointData = undefined; + }); - loginWithWriteAccess = () => { - if (isServerless) { - login(ROLE.endpoint_policy_manager); - } else { + for (const siemVersion of siemVersionsToTest) { + describe(siemVersion, () => { + describe(`When on the ${testData.title} entries list`, () => { + beforeEach(() => { + const { privilegePrefix } = testData; + + loginWithWriteAccess = () => { + if (isServerless) { + login(ROLE.endpoint_policy_manager); + } else { + login.withCustomKibanaPrivileges({ + [siemVersion]: ['read', `${privilegePrefix}all`], + }); + } + }; + + loginWithReadAccess = () => { + expect(isServerless, 'Testing read access is implemented only on ESS').to.equal( + false + ); login.withCustomKibanaPrivileges({ - [siemVersion]: ['read', `${privilegePrefix}all`], + [siemVersion]: ['read', `${privilegePrefix}read`], }); - } - }; - - loginWithReadAccess = () => { - expect(isServerless, 'Testing read access is implemented only on ESS').to.equal(false); - login.withCustomKibanaPrivileges({ [siemVersion]: ['read', `${privilegePrefix}read`] }); - }; - - loginWithoutAccess = () => { - if (isServerless) { - login(ROLE.t1_analyst); - } else { - login.withCustomKibanaPrivileges({ [siemVersion]: ['read'] }); - } - }; - }); - - describe('given there are no artifacts yet', () => { - it(`no access - should show no privileges callout`, () => { - loginWithoutAccess(); - loadPage(`/app/security/administration/${testData.urlPath}`); - cy.getByTestSubj('noPrivilegesPage').should('exist'); - cy.getByTestSubj('empty-page-feature-action').should('exist'); - cy.getByTestSubj(testData.emptyState).should('not.exist'); - cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).should('not.exist'); + }; + + loginWithoutAccess = () => { + if (isServerless) { + login(ROLE.t1_analyst); + } else { + login.withCustomKibanaPrivileges({ [siemVersion]: ['read'] }); + } + }; }); - it( - `read - should show empty state page if there is no ${testData.title} entry and the add button does not exist`, - // there is no such role in Serverless environment that only reads artifacts - { tags: ['@skipInServerless'] }, - () => { - loginWithReadAccess(); + describe('given there are no artifacts yet', () => { + it(`no access - should show no privileges callout`, () => { + loginWithoutAccess(); loadPage(`/app/security/administration/${testData.urlPath}`); - cy.getByTestSubj(testData.emptyState).should('exist'); + cy.getByTestSubj('noPrivilegesPage').should('exist'); + cy.getByTestSubj('empty-page-feature-action').should('exist'); + cy.getByTestSubj(testData.emptyState).should('not.exist'); cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).should('not.exist'); - } - ); - - it(`write - should show empty state page if there is no ${testData.title} entry and the add button exists`, () => { - loginWithWriteAccess(); - loadPage(`/app/security/administration/${testData.urlPath}`); - cy.getByTestSubj(testData.emptyState).should('exist'); - cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).should('exist'); - }); - - it(`write - should create new ${testData.title} entry`, () => { - loginWithWriteAccess(); - loadPage(`/app/security/administration/${testData.urlPath}`); - // Opens add flyout - cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).click(); + }); + + it( + `read - should show empty state page if there is no ${testData.title} entry and the add button does not exist`, + // there is no such role in Serverless environment that only reads artifacts + { tags: ['@skipInServerless'] }, + () => { + loginWithReadAccess(); + loadPage(`/app/security/administration/${testData.urlPath}`); + cy.getByTestSubj(testData.emptyState).should('exist'); + cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).should('not.exist'); + } + ); + + it(`write - should show empty state page if there is no ${testData.title} entry and the add button exists`, () => { + loginWithWriteAccess(); + loadPage(`/app/security/administration/${testData.urlPath}`); + cy.getByTestSubj(testData.emptyState).should('exist'); + cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).should('exist'); + }); - performUserActions(testData.create.formActions); + it(`write - should create new ${testData.title} entry`, () => { + loginWithWriteAccess(); + loadPage(`/app/security/administration/${testData.urlPath}`); + // Opens add flyout + cy.getByTestSubj(`${testData.pagePrefix}-emptyState-addButton`).click(); - // Submit create artifact form - cy.getByTestSubj(`${testData.pagePrefix}-flyout-submitButton`).click(); + performUserActions(testData.create.formActions); - // Check new artifact is in the list - for (const checkResult of testData.create.checkResults) { - cy.getByTestSubj(checkResult.selector).should('have.text', checkResult.value); - } + // Submit create artifact form + cy.getByTestSubj(`${testData.pagePrefix}-flyout-submitButton`).click(); - // Title is shown after adding an item - cy.getByTestSubj('header-page-title').contains(testData.title); - }); - }); + // Check new artifact is in the list + for (const checkResult of testData.create.checkResults) { + cy.getByTestSubj(checkResult.selector).should('have.text', checkResult.value); + } - describe('given there is an existing artifact', () => { - beforeEach(() => { - createArtifactList(testData.createRequestBody.list_id); - createPerPolicyArtifact(testData.artifactName, testData.createRequestBody); + // Title is shown after adding an item + cy.getByTestSubj('header-page-title').contains(testData.title); + }); }); - it( - `read - should not be able to update/delete an existing ${testData.title} entry`, - // there is no such role in Serverless environment that only reads artifacts - { tags: ['@skipInServerless'] }, - () => { - loginWithReadAccess(); - loadPage(`/app/security/administration/${testData.urlPath}`); - cy.getByTestSubj('header-page-title').contains(testData.title); - cy.getByTestSubj(`${testData.pagePrefix}-card-header-actions-button`).should( - 'not.exist' - ); - cy.getByTestSubj(`${testData.pagePrefix}-card-cardEditAction`).should('not.exist'); - cy.getByTestSubj(`${testData.pagePrefix}-card-cardDeleteAction`).should('not.exist'); - } - ); - - it( - `read - should not be able to create a new ${testData.title} entry`, - // there is no such role in Serverless environment that only reads artifacts - { tags: ['@skipInServerless'] }, - () => { - loginWithReadAccess(); + describe('given there is an existing artifact', () => { + beforeEach(() => { + createArtifactList(testData.createRequestBody.list_id); + createPerPolicyArtifact(testData.artifactName, testData.createRequestBody); + }); + + it( + `read - should not be able to update/delete an existing ${testData.title} entry`, + // there is no such role in Serverless environment that only reads artifacts + { tags: ['@skipInServerless'] }, + () => { + loginWithReadAccess(); + loadPage(`/app/security/administration/${testData.urlPath}`); + cy.getByTestSubj('header-page-title').contains(testData.title); + cy.getByTestSubj(`${testData.pagePrefix}-card-header-actions-button`).should( + 'not.exist' + ); + cy.getByTestSubj(`${testData.pagePrefix}-card-cardEditAction`).should('not.exist'); + cy.getByTestSubj(`${testData.pagePrefix}-card-cardDeleteAction`).should( + 'not.exist' + ); + } + ); + + it( + `read - should not be able to create a new ${testData.title} entry`, + // there is no such role in Serverless environment that only reads artifacts + { tags: ['@skipInServerless'] }, + () => { + loginWithReadAccess(); + loadPage(`/app/security/administration/${testData.urlPath}`); + cy.getByTestSubj('header-page-title').contains(testData.title); + cy.getByTestSubj(`${testData.pagePrefix}-pageAddButton`).should('not.exist'); + } + ); + + it(`write - should be able to update an existing ${testData.title} entry`, () => { + loginWithWriteAccess(); loadPage(`/app/security/administration/${testData.urlPath}`); - cy.getByTestSubj('header-page-title').contains(testData.title); - cy.getByTestSubj(`${testData.pagePrefix}-pageAddButton`).should('not.exist'); - } - ); - - it(`write - should be able to update an existing ${testData.title} entry`, () => { - loginWithWriteAccess(); - loadPage(`/app/security/administration/${testData.urlPath}`); - // Opens edit flyout - cy.getByTestSubj(`${testData.pagePrefix}-card-header-actions-button`).click(); - cy.getByTestSubj(`${testData.pagePrefix}-card-cardEditAction`).click(); + // Opens edit flyout + cy.getByTestSubj(`${testData.pagePrefix}-card-header-actions-button`).click(); + cy.getByTestSubj(`${testData.pagePrefix}-card-cardEditAction`).click(); - performUserActions(testData.update.formActions); + performUserActions(testData.update.formActions); - // Submit edit artifact form - cy.getByTestSubj(`${testData.pagePrefix}-flyout-submitButton`).click(); + // Submit edit artifact form + cy.getByTestSubj(`${testData.pagePrefix}-flyout-submitButton`).click(); - for (const checkResult of testData.update.checkResults) { - cy.getByTestSubj(checkResult.selector).should('have.text', checkResult.value); - } + for (const checkResult of testData.update.checkResults) { + cy.getByTestSubj(checkResult.selector).should('have.text', checkResult.value); + } - // Title still shown after editing an item - cy.getByTestSubj('header-page-title').contains(testData.title); - }); + // Title still shown after editing an item + cy.getByTestSubj('header-page-title').contains(testData.title); + }); - it(`write - should be able to delete the existing ${testData.title} entry`, () => { - loginWithWriteAccess(); - loadPage(`/app/security/administration/${testData.urlPath}`); - // Remove it - cy.getByTestSubj(`${testData.pagePrefix}-card-header-actions-button`).click(); - cy.getByTestSubj(`${testData.pagePrefix}-card-cardDeleteAction`).click(); - cy.getByTestSubj(`${testData.pagePrefix}-deleteModal-submitButton`).click(); - // No card visible after removing it - cy.getByTestSubj(testData.delete.card).should('not.exist'); - // Empty state is displayed after removing last item - cy.getByTestSubj(testData.emptyState).should('exist'); + it(`write - should be able to delete the existing ${testData.title} entry`, () => { + loginWithWriteAccess(); + loadPage(`/app/security/administration/${testData.urlPath}`); + // Remove it + cy.getByTestSubj(`${testData.pagePrefix}-card-header-actions-button`).click(); + cy.getByTestSubj(`${testData.pagePrefix}-card-cardDeleteAction`).click(); + cy.getByTestSubj(`${testData.pagePrefix}-deleteModal-submitButton`).click(); + // No card visible after removing it + cy.getByTestSubj(testData.delete.card).should('not.exist'); + // Empty state is displayed after removing last item + cy.getByTestSubj(testData.emptyState).should('exist'); + }); }); }); }); - }); - } -}; + } + }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/tasks/artifacts.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/tasks/artifacts.ts index e1518ac403569..7dcde4e06d43f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/tasks/artifacts.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/tasks/artifacts.ts @@ -18,7 +18,11 @@ import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL, } from '@kbn/securitysolution-list-constants'; -import { APP_BLOCKLIST_PATH, APP_TRUSTED_APPS_PATH } from '../../../../common/constants'; +import { + APP_BLOCKLIST_PATH, + APP_TRUSTED_APPS_PATH, + APP_TRUSTED_DEVICES_PATH, +} from '../../../../common/constants'; import { loadPage, request } from './common'; export const removeAllArtifacts = () => { @@ -232,6 +236,81 @@ export const trustedAppsFormSelectors = { }, }; +export const trustedDevicesFormSelectors = { + selectOs: (osOption: 'Windows and Mac' | 'Windows' | 'Mac') => { + cy.getByTestSubj('trustedDevices-form-osSelectField').click(); + cy.get('[role="option"]').contains(osOption).click(); + }, + + selectField: (field: 'Username' | 'Host' | 'Device ID' | 'Manufacturer' | 'Product ID') => { + cy.getByTestSubj('trustedDevices-form-fieldSelect').click(); + cy.get('[role="option"]').contains(field).click(); + }, + + selectOperator: (operator: 'is' | 'matches') => { + cy.getByTestSubj('trustedDevices-form-operatorSelect').click(); + cy.get('[role="option"]') + .contains(operator === 'is' ? 'is' : 'matches') + .click(); + }, + + fillValue: (value: string) => { + cy.getByTestSubj('trustedDevices-form-valueField').clear(); + cy.getByTestSubj('trustedDevices-form-valueField').type(value); + }, + + fillOutTrustedDevicesFlyout: (name = 'Test Trusted Device', description = 'Test Description') => { + cy.getByTestSubj('trustedDevices-form-nameTextField').clear(); + cy.getByTestSubj('trustedDevices-form-nameTextField').type(name); + cy.getByTestSubj('trustedDevices-form-descriptionField').clear(); + cy.getByTestSubj('trustedDevices-form-descriptionField').type(description); + }, + + submitForm: () => { + cy.getByTestSubj('trustedDevicesList-flyout-submitButton').click(); + }, + + validateSuccessPopup: (action: 'create' | 'update' | 'delete') => { + const messages = { + create: 'has been added to your trusted devices list', + update: 'has been updated', + delete: 'has been removed from the trusted devices list', + }; + cy.get('[data-test-subj="globalToastList"]').should('contain.text', messages[action]); + }, + + validateRenderedCondition: (expectedCondition: RegExp) => { + cy.getByTestSubj('trustedDevicesList-card') + .first() + .within(() => { + cy.getByTestSubj('trustedDevicesList-card-criteriaConditions-condition') + .invoke('text') + .should('match', expectedCondition); + }); + }, + + deleteTrustedDeviceItem: () => { + cy.getByTestSubj('trustedDevicesList-card') + .first() + .within(() => { + cy.getByTestSubj('trustedDevicesList-card-header-actions-button').click(); + }); + + cy.getByTestSubj('trustedDevicesList-card-cardDeleteAction').click(); + cy.getByTestSubj('trustedDevicesList-deleteModal-submitButton').click(); + }, + + openTrustedDevices: ({ create, itemId }: { create?: boolean; itemId?: string } = {}) => { + if (!create && !itemId) { + loadPage(APP_TRUSTED_DEVICES_PATH); + } else if (create) { + loadPage(`${APP_TRUSTED_DEVICES_PATH}?show=create`); + } else if (itemId) { + loadPage(`${APP_TRUSTED_DEVICES_PATH}?itemId=${itemId}&show=edit`); + } + }, +}; + export const blocklistFormSelectors = { expectSingleOperator: (field: 'Path' | 'Signature' | 'Hash') => { cy.getByTestSubj('blocklist-form-field-select').contains(field); diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/detections_admin.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/detections_admin.ts index 8719fe03dee2c..61e4bc9e0d667 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/detections_admin.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/detections_admin.ts @@ -18,19 +18,7 @@ export const getDetectionsAdmin: () => Omit = () => { ...noResponseActionsRole.kibana[0], feature: { ...noResponseActionsRole.kibana[0].feature, - [SECURITY_FEATURE_ID]: [ - 'all', - - 'policy_management_read', - - 'global_artifact_management_all', - 'trusted_applications_read', - 'event_filters_read', - 'host_isolation_exceptions_read', - 'blocklist_all', - - 'actions_log_management_read', - ], + [SECURITY_FEATURE_ID]: ['all', 'global_artifact_management_all'], securitySolutionTimeline: ['all'], securitySolutionNotes: ['all'], }, diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts index 586c99049f497..2b34518df8179 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts @@ -67,6 +67,7 @@ export const getEndpointOperationsAnalyst: () => Omit = () => { 'endpoint_list_all', 'global_artifact_management_all', 'trusted_applications_all', + 'trusted_devices_all', 'event_filters_all', 'host_isolation_exceptions_all', 'blocklist_all', diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/platform_engineer.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/platform_engineer.ts index 889abe32d5746..3c9a4205e23ff 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/platform_engineer.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/platform_engineer.ts @@ -25,6 +25,7 @@ export const getPlatformEngineer: () => Omit = () => { 'global_artifact_management_all', 'trusted_applications_all', + 'trusted_devices_all', 'event_filters_all', 'host_isolation_exceptions_all', 'blocklist_all', diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts index aaa622113f21d..c4fcd7592bbb7 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/rule_author.ts @@ -26,6 +26,7 @@ export const getRuleAuthor: () => Omit = () => { 'endpoint_list_all', 'global_artifact_management_all', 'trusted_applications_all', + 'trusted_devices_all', 'event_filters_all', 'host_isolation_exceptions_read', 'blocklist_all', diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml index 57a1f78479b0f..f8ba3b5de322d 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml @@ -145,6 +145,7 @@ editor: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all @@ -335,6 +336,7 @@ t3_analyst: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all @@ -481,6 +483,7 @@ rule_author: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_read - feature_siemV3.blocklist_all # Elastic Defend Policy Management @@ -558,6 +561,7 @@ soc_manager: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all @@ -700,6 +704,7 @@ platform_engineer: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all # Elastic Defend Policy Management @@ -777,6 +782,7 @@ endpoint_operations_analyst: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all @@ -860,6 +866,7 @@ endpoint_policy_manager: - feature_siemV3.endpoint_list_all - feature_siemV3.global_artifact_management_all - feature_siemV3.trusted_applications_all + - feature_siemV3.trusted_devices_all - feature_siemV3.event_filters_all - feature_siemV3.host_isolation_exceptions_all - feature_siemV3.blocklist_all # Elastic Defend Policy Management diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/soc_manager.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/soc_manager.ts index 9b4ac9913b5f1..50d3dc5694a65 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/soc_manager.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/soc_manager.ts @@ -25,6 +25,7 @@ export const getSocManager: () => Omit = () => { 'global_artifact_management_all', 'trusted_applications_all', + 'trusted_devices_all', 'event_filters_all', 'host_isolation_exceptions_all', 'blocklist_all', diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.ts index 219083cbebc7d..6fdd359a99503 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/t3_analyst.ts @@ -25,6 +25,7 @@ export const getT3Analyst: () => Omit = () => { 'endpoint_list_all', 'global_artifact_management_all', 'trusted_applications_all', + 'trusted_devices_all', 'event_filters_all', 'host_isolation_exceptions_all', 'blocklist_all', diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/with_artifact_read_privileges_role.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/with_artifact_read_privileges_role.ts index d3fd073268136..16327c6a1a91d 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/with_artifact_read_privileges_role.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/with_artifact_read_privileges_role.ts @@ -22,6 +22,7 @@ export const getWithArtifactReadPrivilegesRole: () => Omit = () => 'all', 'blocklist_read', 'trusted_applications_read', + 'trusted_devices_read', 'host_isolation_exceptions_read', 'event_filters_read', ], diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/without_response_actions_role.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/without_response_actions_role.ts index 9a2ea9537f3a6..96b012ccac9fa 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/without_response_actions_role.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/roles_users/without_response_actions_role.ts @@ -49,6 +49,8 @@ export const getNoResponseActionsRole: () => Omit = () => ({ 'endpoint_list_read', 'trusted_applications_all', 'trusted_applications_read', + 'trusted_devices_all', + 'trusted_devices_read', 'host_isolation_exceptions_all', 'host_isolation_exceptions_read', 'blocklist_all', diff --git a/x-pack/solutions/security/test/security_solution_cypress/cypress/screens/security_header.ts b/x-pack/solutions/security/test/security_solution_cypress/cypress/screens/security_header.ts index a671748dbb7c9..3b5bbc5688605 100644 --- a/x-pack/solutions/security/test/security_solution_cypress/cypress/screens/security_header.ts +++ b/x-pack/solutions/security/test/security_solution_cypress/cypress/screens/security_header.ts @@ -50,6 +50,8 @@ export const POLICIES = '[data-test-subj="solutionSideNavPanelLink-policy"]'; export const TRUSTED_APPS = '[data-test-subj="solutionSideNavPanelLink-trusted_apps"]'; +export const TRUSTED_DEVICES = '[data-test-subj="solutionSideNavPanelLink-trusted_devices"]'; + export const EVENT_FILTERS = '[data-test-subj="solutionSideNavPanelLink-event_filters"]'; export const BLOCKLIST = '[data-test-subj="solutionSideNavPanelLink-blocklist"]'; @@ -119,6 +121,7 @@ export const openNavigationPanelFor = (page: string) => { } case ENDPOINTS: case TRUSTED_APPS: + case TRUSTED_DEVICES: case EVENT_FILTERS: case POLICIES: case ENDPOINT_EXCEPTIONS: