@@ -78,6 +79,47 @@ const RiskScoreErrorPanel = ({ errors }: { errors: string[] }) => (
))}
>
+
+
+
+ {i18n.NEED_TO_HAVE}
+
+ -
+ {'all'},
+ index: {'risk-score.risk-score-*'},
+ }}
+ />
+
+ -
+
+ {'manage_index_templates'}
+ {','} {'manage_transform'}
+
+ ),
+ }}
+ />
+
+ -
+ {'Saved Objects Management'},
+ }}
+ />
+
+
+
+
>
);
diff --git a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx
index 16521b065c2a0..4f2bacf97f02b 100644
--- a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx
+++ b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx
@@ -10,14 +10,12 @@ import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiPageHeader, EuiSpacer } fro
import { RiskScorePreviewSection } from '../components/risk_score_preview_section';
import { RiskScoreEnableSection } from '../components/risk_score_enable_section';
-import { MissingPrivilegesCallOut } from '../../detections/components/callouts/missing_privileges_callout';
import { ENTITY_ANALYTICS_RISK_SCORE } from '../../app/translations';
import { BETA } from '../../common/translations';
export const EntityAnalyticsManagementPage = () => {
return (
<>
-
- }
- titleSize="s"
- tooltip={
- entityType === RiskScoreEntity.user
- ? overviewI18n.USER_RISK_TABLE_TOOLTIP
- : overviewI18n.HOST_RISK_TABLE_TOOLTIP
- }
- />
+ } titleSize="s" />
{translations.title}}
body={translations.body}
diff --git a/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx b/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx
index f49879ecf4754..b2be80f74ab71 100644
--- a/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx
+++ b/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx
@@ -125,13 +125,6 @@ export const useRiskScore = {
- refetchAll();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [timerange?.to, timerange?.from]);
-
const riskScoreResponse = useMemo(
() => ({
data: response.data,
@@ -168,7 +161,7 @@ export const useRiskScore = (timerange ? { to: timerange.to, from: timerange.from, interval: '' } : undefined),
+ [timerange]
+ );
+
useEffect(() => {
if (
!skip &&
@@ -92,32 +97,28 @@ export const useRiskScoreKpi = ({
filterQuery,
defaultIndex: [defaultIndex],
entity: riskEntity,
+ timerange: requestTimerange,
});
}
}, [
- isEnabled,
- isDeprecated,
- isAuthorized,
- isDeprecatedLoading,
- skip,
defaultIndex,
search,
filterQuery,
+ skip,
riskEntity,
+ requestTimerange,
+ isEnabled,
+ isDeprecated,
+ isAuthorized,
+ isDeprecatedLoading,
]);
const refetchAll = useCallback(() => {
if (defaultIndex) {
- refetchDeprecated(defaultIndex);
+ refetchFeatureStatus(defaultIndex);
refetch();
}
- }, [defaultIndex, refetch, refetchDeprecated]);
-
- // since query does not take timerange arg, we need to manually refetch when time range updates
- useEffect(() => {
- refetchAll();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [timerange?.to, timerange?.from]);
+ }, [defaultIndex, refetch, refetchFeatureStatus]);
useEffect(() => {
if (error) {
@@ -141,5 +142,5 @@ export const useRiskScoreKpi = ({
};
}, [result, loading, error]);
- return { error, severityCount, loading, isModuleDisabled, refetch, inspect };
+ return { error, severityCount, loading, isModuleDisabled, refetch: refetchAll, inspect };
};
diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.test.tsx b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.test.tsx
index f1bf397637617..98cfa4895fbd4 100644
--- a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.test.tsx
+++ b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.test.tsx
@@ -17,7 +17,7 @@ describe('getHostRiskScoreColumns', () => {
});
const riskScore = 10.11111111;
- const riskScoreColumn = columns[1];
+ const riskScoreColumn = columns[2];
const renderedColumn = riskScoreColumn.render!(riskScore, null);
const { queryByTestId } = render({renderedColumn});
diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.tsx b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.tsx
index de66a5bca1110..af6c0d502351e 100644
--- a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.tsx
+++ b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/columns.tsx
@@ -17,11 +17,12 @@ import { HostDetailsLink } from '../../../../common/components/links';
import type { HostRiskScoreColumns } from '.';
import * as i18n from './translations';
import { HostsTableType } from '../../store/model';
-import type { RiskSeverity } from '../../../../../common/search_strategy';
+import type { Maybe, RiskSeverity } from '../../../../../common/search_strategy';
import { RiskScoreFields, RiskScoreEntity } from '../../../../../common/search_strategy';
import { RiskScoreLevel } from '../../../components/risk_score/severity/common';
import { ENTITY_RISK_LEVEL } from '../../../components/risk_score/translations';
import { CELL_ACTIONS_TELEMETRY } from '../../../components/risk_score/constants';
+import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date';
export const getHostRiskScoreColumns = ({
dispatchSeverityUpdate,
@@ -34,6 +35,7 @@ export const getHostRiskScoreColumns = ({
truncateText: false,
mobileOptions: { show: true },
sortable: true,
+ width: '35%',
render: (hostName) => {
if (hostName != null && hostName.length > 0) {
return (
@@ -57,6 +59,19 @@ export const getHostRiskScoreColumns = ({
return getEmptyTagValue();
},
},
+ {
+ field: RiskScoreFields.timestamp,
+ name: i18n.LAST_UPDATED,
+ truncateText: false,
+ mobileOptions: { show: true },
+ sortable: true,
+ render: (lastSeen: Maybe) => {
+ if (lastSeen != null) {
+ return ;
+ }
+ return getEmptyTagValue();
+ },
+ },
{
field: RiskScoreFields.hostRiskScore,
name: i18n.HOST_RISK_SCORE,
diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/index.tsx b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/index.tsx
index 497c21e8f9dec..9c486c96fdece 100644
--- a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/index.tsx
+++ b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/index.tsx
@@ -60,6 +60,7 @@ interface HostRiskScoreTableProps {
export type HostRiskScoreColumns = [
Columns,
+ Columns,
Columns,
Columns
];
@@ -191,7 +192,6 @@ const HostRiskScoreTableComponent: React.FC = ({
headerSupplement={risk}
headerTitle={i18nHosts.HOST_RISK_TITLE}
headerUnit={i18n.UNIT(totalCount)}
- headerTooltip={i18nHosts.HOST_RISK_TABLE_TOOLTIP}
id={id}
isInspect={isInspect}
itemsPerRow={rowItems}
diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/translations.ts b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/translations.ts
index 08c685720a2e4..8ccb7addbcc30 100644
--- a/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/translations.ts
+++ b/x-pack/plugins/security_solution/public/explore/hosts/components/host_risk_score_table/translations.ts
@@ -28,16 +28,15 @@ export const HOST_RISK_TITLE = i18n.translate(
}
);
-export const HOST_RISK_TABLE_TOOLTIP = i18n.translate(
- 'xpack.securitySolution.hostsRiskTable.hostsTableTooltip',
- {
- defaultMessage:
- 'The host risk table is not affected by the KQL time range. This table shows the latest recorded risk score for each host.',
- }
-);
-
export const VIEW_HOSTS_BY_SEVERITY = (severity: string) =>
i18n.translate('xpack.securitySolution.hostsRiskTable.filteredHostsTitle', {
values: { severity },
defaultMessage: 'View {severity} risk hosts',
});
+
+export const LAST_UPDATED = i18n.translate(
+ 'xpack.securitySolution.hostsRiskTable.lastUpdatedTitle',
+ {
+ defaultMessage: 'Last updated',
+ }
+);
diff --git a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.test.tsx b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.test.tsx
index d28513800f221..3f9fe12981509 100644
--- a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.test.tsx
+++ b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.test.tsx
@@ -20,8 +20,9 @@ describe('getUserRiskScoreColumns', () => {
const columns = getUserRiskScoreColumns(defaultProps);
expect(columns[0].field).toBe('user.name');
- expect(columns[1].field).toBe(RiskScoreFields.userRiskScore);
- expect(columns[2].field).toBe(RiskScoreFields.userRisk);
+ expect(columns[1].field).toBe(RiskScoreFields.timestamp);
+ expect(columns[2].field).toBe(RiskScoreFields.userRiskScore);
+ expect(columns[3].field).toBe(RiskScoreFields.userRisk);
columns.forEach((column) => {
expect(column).toHaveProperty('name');
@@ -45,7 +46,7 @@ describe('getUserRiskScoreColumns', () => {
const columns: UserRiskScoreColumns = getUserRiskScoreColumns(defaultProps);
const riskScore = 10.11111111;
- const riskScoreColumn = columns[1];
+ const riskScoreColumn = columns[2];
const renderedColumn = riskScoreColumn.render!(riskScore, null);
const { queryByTestId } = render({renderedColumn});
diff --git a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.tsx b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.tsx
index 6de43c4dbe2fc..a23d62d0e83d5 100644
--- a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.tsx
+++ b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/columns.tsx
@@ -17,12 +17,13 @@ import { getEmptyTagValue } from '../../../../common/components/empty_value';
import type { UserRiskScoreColumns } from '.';
import * as i18n from './translations';
import { RiskScoreLevel } from '../../../components/risk_score/severity/common';
-import type { RiskSeverity } from '../../../../../common/search_strategy';
+import type { Maybe, RiskSeverity } from '../../../../../common/search_strategy';
import { RiskScoreEntity, RiskScoreFields } from '../../../../../common/search_strategy';
import { UserDetailsLink } from '../../../../common/components/links';
import { UsersTableType } from '../../store/model';
import { ENTITY_RISK_LEVEL } from '../../../components/risk_score/translations';
import { CELL_ACTIONS_TELEMETRY } from '../../../components/risk_score/constants';
+import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date';
export const getUserRiskScoreColumns = ({
dispatchSeverityUpdate,
@@ -35,6 +36,7 @@ export const getUserRiskScoreColumns = ({
truncateText: false,
mobileOptions: { show: true },
sortable: true,
+ width: '35%',
render: (userName) => {
if (userName != null && userName.length > 0) {
const id = escapeDataProviderId(`user-risk-score-table-userName-${userName}`);
@@ -60,6 +62,19 @@ export const getUserRiskScoreColumns = ({
return getEmptyTagValue();
},
},
+ {
+ field: RiskScoreFields.timestamp,
+ name: i18n.LAST_UPDATED,
+ truncateText: false,
+ mobileOptions: { show: true },
+ sortable: true,
+ render: (lastSeen: Maybe) => {
+ if (lastSeen != null) {
+ return ;
+ }
+ return getEmptyTagValue();
+ },
+ },
{
field: RiskScoreFields.userRiskScore,
name: i18n.USER_RISK_SCORE,
diff --git a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/index.tsx b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/index.tsx
index 5dc1c3c6bd08e..01a2df82b40c9 100644
--- a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/index.tsx
+++ b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/index.tsx
@@ -60,6 +60,7 @@ interface UserRiskScoreTableProps {
export type UserRiskScoreColumns = [
Columns,
+ Columns,
Columns,
Columns
];
@@ -191,7 +192,6 @@ const UserRiskScoreTableComponent: React.FC = ({
}
headerSupplement={risk}
headerTitle={i18nUsers.NAVIGATION_RISK_TITLE}
- headerTooltip={i18n.USER_RISK_TABLE_TOOLTIP}
headerUnit={i18n.UNIT(totalCount)}
id={id}
isInspect={isInspect}
diff --git a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/translations.ts b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/translations.ts
index d0cf95dea6c23..b9913bd7275cd 100644
--- a/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/translations.ts
+++ b/x-pack/plugins/security_solution/public/explore/users/components/user_risk_score_table/translations.ts
@@ -39,10 +39,6 @@ export const ROWS_10 = i18n.translate('xpack.securitySolution.usersTable.rows',
defaultMessage: '{numRows} {numRows, plural, =0 {rows} =1 {row} other {rows}}',
});
-export const USER_RISK_TABLE_TOOLTIP = i18n.translate(
- 'xpack.securitySolution.hostsRiskTable.usersTableTooltip',
- {
- defaultMessage:
- 'The user risk table is not affected by the KQL time range. This table shows the latest recorded risk score for each user.',
- }
-);
+export const LAST_UPDATED = i18n.translate('xpack.securitySolution.usersTable.lastUpdatedTitle', {
+ defaultMessage: 'Last updated',
+});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts b/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts
index a4037e32632a5..bd4c34b36de59 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/cypress.d.ts
@@ -22,6 +22,8 @@ import type {
IndexEndpointHostsCyTaskOptions,
LoadUserAndRoleCyTaskOptions,
CreateUserAndRoleCyTaskOptions,
+ UninstallAgentFromHostTaskOptions,
+ IsAgentAndEndpointUninstalledFromHostTaskOptions,
} from './types';
import type {
DeleteIndexedFleetEndpointPoliciesResponse,
@@ -203,6 +205,18 @@ declare global {
arg: CreateUserAndRoleCyTaskOptions,
options?: Partial
): Chainable;
+
+ task(
+ name: 'uninstallAgentFromHost',
+ arg: UninstallAgentFromHostTaskOptions,
+ options?: Partial
+ ): Chainable;
+
+ task(
+ name: 'isAgentAndEndpointUninstalledFromHost',
+ arg: IsAgentAndEndpointUninstalledFromHostTaskOptions,
+ options?: Partial
+ ): Chainable;
}
}
}
diff --git a/x-pack/plugins/security_solution/public/management/cypress/cypress_base.config.ts b/x-pack/plugins/security_solution/public/management/cypress/cypress_base.config.ts
index e861c5927d3fd..f235600e40340 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/cypress_base.config.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/cypress_base.config.ts
@@ -8,6 +8,7 @@
import { merge } from 'lodash';
import { dataLoaders, dataLoadersForRealEndpoints } from './support/data_loaders';
import { responseActionTasks } from './support/response_actions';
+import { agentActions } from './support/agent_actions';
export const getCypressBaseConfig = (
overrides: Cypress.ConfigOptions = {}
@@ -66,6 +67,8 @@ export const getCypressBaseConfig = (
// Data loaders specific to "real" Endpoint testing
dataLoadersForRealEndpoints(on, config);
+ agentActions(on);
+
responseActionTasks(on, config);
// eslint-disable-next-line @typescript-eslint/no-var-requires
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts
index 7205601b06493..92289a6109d0e 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts
@@ -19,8 +19,9 @@ import { RESPONSE_ACTION_TYPES } from '../../../../../common/api/detection_engin
import { login, ROLE } from '../../tasks/login';
describe('Form', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
- describe('User with no access can not create an endpoint response action', () => {
- before(() => {
+ // FLAKY: https://github.com/elastic/kibana/issues/169334
+ describe.skip('User with no access can not create an endpoint response action', () => {
+ beforeEach(() => {
login(ROLE.endpoint_response_actions_no_access);
});
@@ -35,10 +36,10 @@ describe('Form', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () =>
let ruleId: string;
const [ruleName, ruleDescription] = generateRandomStringName(2);
- before(() => {
+ beforeEach(() => {
login(ROLE.endpoint_response_actions_access);
});
- after(() => {
+ afterEach(() => {
cleanupRule(ruleId);
});
@@ -87,16 +88,14 @@ describe('Form', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () =>
const testedCommand = 'isolate';
const newDescription = 'Example isolate host description';
- before(() => {
+ beforeEach(() => {
+ login(ROLE.endpoint_response_actions_access);
loadRule().then((res) => {
ruleId = res.id;
ruleName = res.name;
});
});
- beforeEach(() => {
- login(ROLE.endpoint_response_actions_access);
- });
- after(() => {
+ afterEach(() => {
cleanupRule(ruleId);
});
@@ -145,7 +144,7 @@ describe('Form', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () =>
describe('User should not see endpoint action when no rbac', () => {
const [ruleName, ruleDescription] = generateRandomStringName(2);
- before(() => {
+ beforeEach(() => {
login(ROLE.endpoint_response_actions_no_access);
});
@@ -162,13 +161,14 @@ describe('Form', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () =>
describe('User without access can not edit, add nor delete an endpoint response action', () => {
let ruleId: string;
- before(() => {
+ beforeEach(() => {
+ login(ROLE.endpoint_response_actions_no_access);
loadRule().then((res) => {
ruleId = res.id;
});
- login(ROLE.endpoint_response_actions_no_access);
});
- after(() => {
+
+ afterEach(() => {
cleanupRule(ruleId);
});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts
index 192a4fd853bd5..d3c940b869835 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/no_license.cy.ts
@@ -19,7 +19,7 @@ describe('No License', { tags: '@ess', env: { ftrConfig: { license: 'basic' } }
describe('User cannot use endpoint action in form', () => {
const [ruleName, ruleDescription] = generateRandomStringName(2);
- before(() => {
+ beforeEach(() => {
login(ROLE.endpoint_response_actions_access);
});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/policy/policy_details_mocked_data.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/policy/policy_details_mocked_data.cy.ts
index 11800441fc035..c824360497d1c 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/e2e/policy/policy_details_mocked_data.cy.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/policy/policy_details_mocked_data.cy.ts
@@ -17,7 +17,10 @@ import type { CyIndexEndpointHosts } from '../../tasks/index_endpoint_hosts';
import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts';
import { login } from '../../tasks/login';
-describe('Policy Details', { tags: ['@ess', '@serverless'] }, () => {
+// Skipped due to flakiness:
+// https://buildkite.com/elastic/kibana-on-merge/builds/37074
+// https://buildkite.com/elastic/kibana-on-merge/builds/37077
+describe.skip('Policy Details', { tags: ['@ess', '@serverless'] }, () => {
const packagePolicyBackupHelper = new PackagePolicyBackupHelper();
let indexedHostsData: CyIndexEndpointHosts;
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/unenroll_agent_from_fleet.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/unenroll_agent_from_fleet.cy.ts
new file mode 100644
index 0000000000000..cdcef05822594
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/unenroll_agent_from_fleet.cy.ts
@@ -0,0 +1,114 @@
+/*
+ * 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 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 {
+ getEndpointIntegrationVersion,
+ createAgentPolicyTask,
+ enableAgentTamperProtectionFeatureFlagInPolicy,
+ unenrollAgent,
+} 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('Unenroll agent from fleet', { tags: ['@ess'] }, () => {
+ let indexedPolicy: IndexedFleetEndpointPolicyResponse;
+ let policy: PolicyData;
+ let indexedPolicyWithAgentTamperEnabled: IndexedFleetEndpointPolicyResponse;
+ let policyWithAgentTamperProtectionEnabled: PolicyData;
+
+ before(() => {
+ getEndpointIntegrationVersion().then((version) => {
+ createAgentPolicyTask(version).then((data) => {
+ indexedPolicy = data;
+ policy = indexedPolicy.integrationPolicies[0];
+ return enableAllPolicyProtections(policy.id);
+ });
+ createAgentPolicyTask(version).then((dataForProtectedPolicy) => {
+ indexedPolicyWithAgentTamperEnabled = dataForProtectedPolicy;
+ policyWithAgentTamperProtectionEnabled =
+ indexedPolicyWithAgentTamperEnabled.integrationPolicies[0];
+
+ return enableAgentTamperProtectionFeatureFlagInPolicy(
+ indexedPolicyWithAgentTamperEnabled.agentPolicies[0].id
+ );
+ });
+ });
+ });
+ beforeEach(() => {
+ login();
+ });
+
+ after(() => {
+ if (indexedPolicy) {
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy);
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicyWithAgentTamperEnabled);
+ }
+ });
+
+ describe('When agent tamper protection is disabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policy.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should unenroll from fleet without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ unenrollAgent(createdHost.agentId).then((isUnenrolled) => {
+ expect(isUnenrolled).to.eql(true);
+ });
+ });
+ });
+
+ describe('When agent tamper protection is enabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policyWithAgentTamperProtectionEnabled.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should unenroll from fleet without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ unenrollAgent(createdHost.agentId).then((isUnenrolled) => {
+ expect(isUnenrolled).to.eql(true);
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/unenroll_agent_from_fleet_changing_policy.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/unenroll_agent_from_fleet_changing_policy.cy.ts
new file mode 100644
index 0000000000000..e4157f7b7eea7
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/unenroll_agent_from_fleet_changing_policy.cy.ts
@@ -0,0 +1,175 @@
+/*
+ * 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 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 {
+ getEndpointIntegrationVersion,
+ createAgentPolicyTask,
+ enableAgentTamperProtectionFeatureFlagInPolicy,
+ unenrollAgent,
+ changeAgentPolicy,
+} 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('Unenroll agent from fleet changing agent policy', { tags: ['@ess'] }, () => {
+ let indexedPolicy: IndexedFleetEndpointPolicyResponse;
+ let policy: PolicyData;
+ let indexedPolicyWithAgentTamperEnabled: IndexedFleetEndpointPolicyResponse;
+ let policyWithAgentTamperProtectionEnabled: PolicyData;
+ let secondIndexedPolicyWithAgentTamperEnabled: IndexedFleetEndpointPolicyResponse;
+ let secondPolicyWithAgentTamperProtectionEnabled: PolicyData;
+
+ before(() => {
+ getEndpointIntegrationVersion().then((version) => {
+ createAgentPolicyTask(version).then((data) => {
+ indexedPolicy = data;
+ policy = indexedPolicy.integrationPolicies[0];
+ return enableAllPolicyProtections(policy.id);
+ });
+ createAgentPolicyTask(version).then((dataForProtectedPolicy) => {
+ indexedPolicyWithAgentTamperEnabled = dataForProtectedPolicy;
+ policyWithAgentTamperProtectionEnabled =
+ indexedPolicyWithAgentTamperEnabled.integrationPolicies[0];
+
+ return enableAgentTamperProtectionFeatureFlagInPolicy(
+ indexedPolicyWithAgentTamperEnabled.agentPolicies[0].id
+ );
+ });
+ createAgentPolicyTask(version).then((dataForProtectedPolicy) => {
+ secondIndexedPolicyWithAgentTamperEnabled = dataForProtectedPolicy;
+ secondPolicyWithAgentTamperProtectionEnabled =
+ secondIndexedPolicyWithAgentTamperEnabled.integrationPolicies[0];
+
+ return enableAgentTamperProtectionFeatureFlagInPolicy(
+ secondIndexedPolicyWithAgentTamperEnabled.agentPolicies[0].id
+ );
+ });
+ });
+ });
+ beforeEach(() => {
+ login();
+ });
+
+ after(() => {
+ if (indexedPolicy) {
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy);
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicyWithAgentTamperEnabled);
+ cy.task('deleteIndexedFleetEndpointPolicies', secondIndexedPolicyWithAgentTamperEnabled);
+ }
+ });
+
+ describe('When agent tamper protection is disabled but then is switched to a policy with it enabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policy.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should unenroll from fleet without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ // Change agent policy and wait for action to be completed
+ changeAgentPolicy(
+ createdHost.agentId,
+ policyWithAgentTamperProtectionEnabled.policy_id,
+ 3
+ ).then((hasChanged) => {
+ expect(hasChanged).to.eql(true);
+ unenrollAgent(createdHost.agentId).then((isUnenrolled) => {
+ expect(isUnenrolled).to.eql(true);
+ });
+ });
+ });
+ });
+
+ describe('When agent tamper protection is enabled but then is switched to a policy with it disabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policyWithAgentTamperProtectionEnabled.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should unenroll from fleet without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ // Change agent policy and wait for action to be completed
+ changeAgentPolicy(createdHost.agentId, policy.policy_id, 3).then((hasChanged) => {
+ expect(hasChanged).to.eql(true);
+ unenrollAgent(createdHost.agentId).then((isUnenrolled) => {
+ expect(isUnenrolled).to.eql(true);
+ });
+ });
+ });
+ });
+
+ describe('When agent tamper protection is enabled but then is switched to a policy with it also enabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policyWithAgentTamperProtectionEnabled.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should unenroll from fleet without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ // Change agent policy and wait for action to be completed
+ changeAgentPolicy(
+ createdHost.agentId,
+ secondPolicyWithAgentTamperProtectionEnabled.policy_id,
+ 3
+ ).then((hasChanged) => {
+ expect(hasChanged).to.eql(true);
+ unenrollAgent(createdHost.agentId).then((isUnenrolled) => {
+ expect(isUnenrolled).to.eql(true);
+ });
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/uninstall_agent_from_host.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/uninstall_agent_from_host.cy.ts
new file mode 100644
index 0000000000000..778cc510e2a37
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/uninstall_agent_from_host.cy.ts
@@ -0,0 +1,140 @@
+/*
+ * 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 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 {
+ getEndpointIntegrationVersion,
+ createAgentPolicyTask,
+ enableAgentTamperProtectionFeatureFlagInPolicy,
+ getUninstallToken,
+ isAgentAndEndpointUninstalledFromHost,
+ uninstallAgentFromHost,
+} 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('Uninstall agent from host', { tags: ['@ess'] }, () => {
+ let indexedPolicy: IndexedFleetEndpointPolicyResponse;
+ let policy: PolicyData;
+ let indexedPolicyWithAgentTamperEnabled: IndexedFleetEndpointPolicyResponse;
+ let policyWithAgentTamperProtectionEnabled: PolicyData;
+
+ before(() => {
+ getEndpointIntegrationVersion().then((version) => {
+ createAgentPolicyTask(version).then((data) => {
+ indexedPolicy = data;
+ policy = indexedPolicy.integrationPolicies[0];
+ return enableAllPolicyProtections(policy.id);
+ });
+ createAgentPolicyTask(version).then((dataForProtectedPolicy) => {
+ indexedPolicyWithAgentTamperEnabled = dataForProtectedPolicy;
+ policyWithAgentTamperProtectionEnabled =
+ indexedPolicyWithAgentTamperEnabled.integrationPolicies[0];
+
+ return enableAgentTamperProtectionFeatureFlagInPolicy(
+ indexedPolicyWithAgentTamperEnabled.agentPolicies[0].id
+ );
+ });
+ });
+ });
+ beforeEach(() => {
+ login();
+ });
+
+ after(() => {
+ if (indexedPolicy) {
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy);
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicyWithAgentTamperEnabled);
+ }
+ });
+
+ describe('When agent tamper protection is disabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policy.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should uninstall from host without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ uninstallAgentFromHost(createdHost.hostname).then((response) => {
+ expect(response).to.not.match(/(.*)Invalid uninstall token(.*)/);
+ expect(response).to.match(/(.*)Elastic Agent has been uninstalled(.*)/);
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then((isUninstalled) => {
+ expect(isUninstalled).to.eql(true);
+ });
+ });
+ });
+ });
+
+ describe('When agent tamper protection is enabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policyWithAgentTamperProtectionEnabled.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should not uninstall from host without the uninstall token', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ uninstallAgentFromHost(createdHost.hostname).then((response) => {
+ expect(response).to.match(/(.*)Invalid uninstall token(.*)/);
+ expect(response).to.not.match(/(.*)Elastic Agent has been uninstalled(.*)/);
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then((isUninstalled) => {
+ expect(isUninstalled).to.eql(false);
+ });
+ });
+ });
+
+ it('should uninstall from host with the uninstall token', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+ getUninstallToken(policyWithAgentTamperProtectionEnabled.policy_id).then((uninstallToken) => {
+ uninstallAgentFromHost(createdHost.hostname, uninstallToken.body.item.token).then(
+ (response) => {
+ expect(response).to.not.match(/(.*)Invalid uninstall token(.*)/);
+ expect(response).to.match(/(.*)Elastic Agent has been uninstalled(.*)/);
+
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then((isUninstalled) => {
+ expect(isUninstalled).to.eql(true);
+ });
+ }
+ );
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/uninstall_agent_from_host_changing_policy.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/uninstall_agent_from_host_changing_policy.cy.ts
new file mode 100644
index 0000000000000..84a15051bd3c9
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/uninstall_agent_from_host_changing_policy.cy.ts
@@ -0,0 +1,256 @@
+/*
+ * 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 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 {
+ getEndpointIntegrationVersion,
+ createAgentPolicyTask,
+ enableAgentTamperProtectionFeatureFlagInPolicy,
+ getUninstallToken,
+ changeAgentPolicy,
+ isAgentAndEndpointUninstalledFromHost,
+ uninstallAgentFromHost,
+} 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('Uninstall agent from host changing agent policy', { tags: ['@ess'] }, () => {
+ let indexedPolicy: IndexedFleetEndpointPolicyResponse;
+ let policy: PolicyData;
+ let indexedPolicyWithAgentTamperEnabled: IndexedFleetEndpointPolicyResponse;
+ let policyWithAgentTamperProtectionEnabled: PolicyData;
+ let secondIndexedPolicyWithAgentTamperEnabled: IndexedFleetEndpointPolicyResponse;
+ let secondPolicyWithAgentTamperProtectionEnabled: PolicyData;
+
+ before(() => {
+ getEndpointIntegrationVersion().then((version) => {
+ createAgentPolicyTask(version).then((data) => {
+ indexedPolicy = data;
+ policy = indexedPolicy.integrationPolicies[0];
+ return enableAllPolicyProtections(policy.id);
+ });
+ createAgentPolicyTask(version).then((dataForProtectedPolicy) => {
+ indexedPolicyWithAgentTamperEnabled = dataForProtectedPolicy;
+ policyWithAgentTamperProtectionEnabled =
+ indexedPolicyWithAgentTamperEnabled.integrationPolicies[0];
+
+ return enableAgentTamperProtectionFeatureFlagInPolicy(
+ indexedPolicyWithAgentTamperEnabled.agentPolicies[0].id
+ );
+ });
+ createAgentPolicyTask(version).then((dataForProtectedPolicy) => {
+ secondIndexedPolicyWithAgentTamperEnabled = dataForProtectedPolicy;
+ secondPolicyWithAgentTamperProtectionEnabled =
+ secondIndexedPolicyWithAgentTamperEnabled.integrationPolicies[0];
+
+ return enableAgentTamperProtectionFeatureFlagInPolicy(
+ secondIndexedPolicyWithAgentTamperEnabled.agentPolicies[0].id
+ );
+ });
+ });
+ });
+ beforeEach(() => {
+ login();
+ });
+
+ after(() => {
+ if (indexedPolicy) {
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy);
+ cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicyWithAgentTamperEnabled);
+ cy.task('deleteIndexedFleetEndpointPolicies', secondIndexedPolicyWithAgentTamperEnabled);
+ }
+ });
+
+ describe('When agent tamper protection is disabled but then is switched to a policy with it enabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policy.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should uninstall from host without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+
+ // Change agent policy and wait for action to be completed
+ changeAgentPolicy(
+ createdHost.agentId,
+ policyWithAgentTamperProtectionEnabled.policy_id,
+ 3
+ ).then((hasChanged) => {
+ expect(hasChanged).to.eql(true);
+
+ // Try to uninstall agent from host without the uninstall token
+ uninstallAgentFromHost(createdHost.hostname).then((responseWithoutToken) => {
+ expect(responseWithoutToken).to.match(/(.*)Invalid uninstall token(.*)/);
+ expect(responseWithoutToken).to.not.match(/(.*)Elastic Agent has been uninstalled(.*)/);
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then(
+ (isUninstalledWithoutToken) => {
+ expect(isUninstalledWithoutToken).to.eql(false);
+
+ // Get the uninstall token from that agent policy
+ getUninstallToken(policyWithAgentTamperProtectionEnabled.policy_id).then(
+ (uninstallToken) => {
+ // Try to uninstall agent from host using the retrieved uninstall token
+ uninstallAgentFromHost(createdHost.hostname, uninstallToken.body.item.token).then(
+ (responseWithToken) => {
+ expect(responseWithToken).to.not.match(/(.*)Invalid uninstall token(.*)/);
+ expect(responseWithToken).to.match(
+ /(.*)Elastic Agent has been uninstalled(.*)/
+ );
+
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then(
+ (isUninstalledWithToken) => {
+ expect(isUninstalledWithToken).to.eql(true);
+ }
+ );
+ }
+ );
+ }
+ );
+ }
+ );
+ });
+ });
+ });
+ });
+
+ describe('When agent tamper protection is enabled but then is switched to a policy with it disabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policyWithAgentTamperProtectionEnabled.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should uninstall from host without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+
+ changeAgentPolicy(createdHost.agentId, policy.policy_id, 3).then((hasChanged) => {
+ expect(hasChanged).to.eql(true);
+ uninstallAgentFromHost(createdHost.hostname).then((responseWithoutToken) => {
+ expect(responseWithoutToken).to.not.match(/(.*)Invalid uninstall token(.*)/);
+ expect(responseWithoutToken).to.match(/(.*)Elastic Agent has been uninstalled(.*)/);
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then(
+ (isUninstalledWithoutToken) => {
+ expect(isUninstalledWithoutToken).to.eql(true);
+ }
+ );
+ });
+ });
+ });
+ });
+
+ describe('When agent tamper protection is enabled but then is switched to a policy with it also enabled', () => {
+ let createdHost: CreateAndEnrollEndpointHostResponse;
+
+ beforeEach(() => {
+ // Create and enroll a new Endpoint host
+ return createEndpointHost(policyWithAgentTamperProtectionEnabled.policy_id).then((host) => {
+ createdHost = host as CreateAndEnrollEndpointHostResponse;
+ });
+ });
+
+ afterEach(() => {
+ if (createdHost) {
+ cy.task('destroyEndpointHost', createdHost);
+ }
+
+ if (createdHost) {
+ deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] });
+ }
+ });
+
+ it('should uninstall from host without issues', () => {
+ waitForEndpointListPageToBeLoaded(createdHost.hostname);
+
+ // Change agent policy and wait for action to be completed
+ changeAgentPolicy(
+ createdHost.agentId,
+ secondPolicyWithAgentTamperProtectionEnabled.policy_id,
+ 3
+ ).then((hasChanged) => {
+ expect(hasChanged).to.eql(true);
+
+ // Get the uninstall token from old agent policy
+ getUninstallToken(policyWithAgentTamperProtectionEnabled.policy_id).then(
+ (oldUninstallToken) => {
+ // Try to uninstall agent from host using old retrieved uninstall token
+ uninstallAgentFromHost(createdHost.hostname, oldUninstallToken.body.item.token).then(
+ (responseWithOldToken) => {
+ expect(responseWithOldToken).to.match(/(.*)Invalid uninstall token(.*)/);
+ expect(responseWithOldToken).to.not.match(
+ /(.*)Elastic Agent has been uninstalled(.*)/
+ );
+
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then(
+ (isUninstalledWithOldToken) => {
+ expect(isUninstalledWithOldToken).to.eql(false);
+
+ // Get the uninstall token from new agent policy
+ getUninstallToken(secondPolicyWithAgentTamperProtectionEnabled.policy_id).then(
+ (newUninstallToken) => {
+ // Try to uninstall agent from host using new retrieved uninstall token
+ uninstallAgentFromHost(
+ createdHost.hostname,
+ newUninstallToken.body.item.token
+ ).then((responseWithNewToken) => {
+ expect(responseWithNewToken).to.not.match(
+ /(.*)Invalid uninstall token(.*)/
+ );
+ expect(responseWithNewToken).to.match(
+ /(.*)Elastic Agent has been uninstalled(.*)/
+ );
+
+ isAgentAndEndpointUninstalledFromHost(createdHost.hostname).then(
+ (isUninstalledWithNewToken) => {
+ expect(isUninstalledWithNewToken).to.eql(true);
+ }
+ );
+ });
+ }
+ );
+ }
+ );
+ }
+ );
+ }
+ );
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/support/agent_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/support/agent_actions.ts
new file mode 100644
index 0000000000000..11a8b30a5e187
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/cypress/support/agent_actions.ts
@@ -0,0 +1,90 @@
+/*
+ * 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 type { ExecaReturnValue } from 'execa';
+import execa from 'execa';
+
+import { VAGRANT_CWD } from '../../../../scripts/endpoint/common/endpoint_host_services';
+
+export const agentActions = (on: Cypress.PluginEvents): void => {
+ on('task', {
+ uninstallAgentFromHost: async ({
+ hostname,
+ uninstallToken,
+ }: {
+ hostname: string;
+ uninstallToken?: string;
+ }): Promise => {
+ let result;
+ try {
+ if (process.env.CI) {
+ result = await execa(
+ 'vagrant',
+ [
+ 'ssh',
+ '--',
+ `sudo elastic-agent uninstall -f ${
+ uninstallToken ? `--uninstall-token ${uninstallToken}` : ''
+ }`,
+ ],
+ {
+ env: {
+ VAGRANT_CWD,
+ },
+ }
+ );
+ } else {
+ result = await execa(`multipass`, [
+ 'exec',
+ hostname,
+ '--',
+ 'sh',
+ '-c',
+ `sudo elastic-agent uninstall -f ${
+ uninstallToken ? `--uninstall-token ${uninstallToken}` : ''
+ }`,
+ ]);
+ }
+ } catch (err) {
+ return err.stderr;
+ }
+ return result.stdout;
+ },
+
+ isAgentAndEndpointUninstalledFromHost: async ({
+ hostname,
+ }: {
+ hostname: string;
+ uninstallToken?: string;
+ }): Promise => {
+ let execaReturnValue: ExecaReturnValue;
+ if (process.env.CI) {
+ execaReturnValue = await execa('vagrant', ['ssh', '--', `ls /opt/Elastic`], {
+ env: {
+ VAGRANT_CWD,
+ },
+ });
+ } else {
+ execaReturnValue = await execa(`multipass`, [
+ 'exec',
+ hostname,
+ '--',
+ 'sh',
+ '-c',
+ `ls /opt/Elastic`,
+ ]);
+ }
+
+ if (execaReturnValue.stdout === '') {
+ return true;
+ }
+
+ return false;
+ },
+ });
+};
diff --git a/x-pack/plugins/security_solution/public/management/cypress/support/e2e.ts b/x-pack/plugins/security_solution/public/management/cypress/support/e2e.ts
index 67c2a3ef0375e..e3f1c084843fe 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/support/e2e.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/support/e2e.ts
@@ -102,7 +102,7 @@ Cypress.Commands.add(
Cypress.on('uncaught:exception', () => false);
-// Login as a Platform Engineer to properly initialize Security Solution App
+// Login as a SOC_MANAGER to properly initialize Security Solution App
before(() => {
login(ROLE.soc_manager);
loadPage('/app/security/alerts');
diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts
index bd6edbea158ce..8f1da4a0ec020 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts
@@ -16,8 +16,16 @@ import {
epmRouteService,
packagePolicyRouteService,
API_VERSIONS,
+ agentPolicyRouteService,
} from '@kbn/fleet-plugin/common';
-import type { PutAgentReassignResponse } from '@kbn/fleet-plugin/common/types';
+import type {
+ GetOneAgentResponse,
+ PutAgentReassignResponse,
+ UpdateAgentPolicyResponse,
+} from '@kbn/fleet-plugin/common/types';
+import { uninstallTokensRouteService } from '@kbn/fleet-plugin/common/services/routes';
+import type { GetUninstallTokensMetadataResponse } from '@kbn/fleet-plugin/common/types/rest_spec/uninstall_token';
+import type { UninstallToken } from '@kbn/fleet-plugin/common/types/models/uninstall_token';
import type { IndexedFleetEndpointPolicyResponse } from '../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy';
import { request } from './common';
@@ -83,3 +91,143 @@ export const createAgentPolicyTask = (
agentPolicyName: policyName,
});
};
+
+export const enableAgentTamperProtectionFeatureFlagInPolicy = (agentPolicyId: string) => {
+ return request({
+ method: 'PUT',
+ url: agentPolicyRouteService.getUpdatePath(agentPolicyId),
+ body: {
+ name: `With agent tamper protection enabled ${Math.random().toString(36).substring(2, 7)}`,
+ agent_features: [{ name: 'tamper_protection', enabled: true }], // TODO: this can be removed once FF code is removed
+ is_protected: true,
+ description: 'test',
+ namespace: 'default',
+ monitoring_enabled: ['logs', 'metrics'],
+ inactivity_timeout: 1209600,
+ },
+ headers: { 'Elastic-Api-Version': API_VERSIONS.public.v1 },
+ });
+};
+
+export const getUninstallToken = (agentPolicyId: string) => {
+ return request({
+ method: 'GET',
+ url: `${uninstallTokensRouteService.getListPath()}?policyId=${agentPolicyId}`,
+ headers: { 'Elastic-Api-Version': API_VERSIONS.public.v1 },
+ }).then((uninstallTokenResponse) => {
+ return request<{ item: UninstallToken }>({
+ method: 'GET',
+ url: uninstallTokensRouteService.getInfoPath(uninstallTokenResponse.body.items[0].id),
+ headers: { 'Elastic-Api-Version': API_VERSIONS.public.v1 },
+ });
+ });
+};
+
+export const unenrollAgent = (agentId: string): Cypress.Chainable => {
+ return request({
+ method: 'POST',
+ url: agentRouteService.getUnenrollPath(agentId),
+ headers: { 'Elastic-Api-Version': API_VERSIONS.public.v1 },
+ }).then(() => {
+ return waitForIsAgentUnenrolled(agentId);
+ });
+};
+
+export const changeAgentPolicy = (
+ agentId: string,
+ policyId: string,
+ policyRevision: number
+): Cypress.Chainable => {
+ return request({
+ method: 'POST',
+ url: agentRouteService.getReassignPath(agentId),
+ body: {
+ policy_id: policyId,
+ },
+ headers: { 'Elastic-Api-Version': API_VERSIONS.public.v1 },
+ }).then(() => {
+ return waitForHasAgentPolicyChanged(agentId, policyId, policyRevision);
+ });
+};
+
+// only used in "real" endpoint tests not in mocked ones
+export const uninstallAgentFromHost = (
+ hostname: string,
+ uninstallToken?: string
+): Cypress.Chainable => {
+ return cy.task('uninstallAgentFromHost', {
+ hostname,
+ uninstallToken,
+ });
+};
+
+// only used in "real" endpoint tests not in mocked ones
+export const isAgentAndEndpointUninstalledFromHost = (
+ hostname: string
+): Cypress.Chainable => {
+ return cy.task('isAgentAndEndpointUninstalledFromHost', {
+ hostname,
+ });
+};
+
+const waitForIsAgentUnenrolled = (agentId: string): Cypress.Chainable => {
+ let isUnenrolled = false;
+ return cy
+ .waitUntil(
+ () => {
+ return request({
+ method: 'GET',
+ url: agentRouteService.getInfoPath(agentId),
+ headers: {
+ 'elastic-api-version': API_VERSIONS.public.v1,
+ },
+ }).then((response) => {
+ if (response.body.item.status === 'unenrolled' && !response.body.item.active) {
+ isUnenrolled = true;
+ return true;
+ }
+
+ return false;
+ });
+ },
+ { timeout: 120000 }
+ )
+ .then(() => {
+ return isUnenrolled;
+ });
+};
+
+const waitForHasAgentPolicyChanged = (
+ agentId: string,
+ policyId: string,
+ policyRevision: number
+): Cypress.Chainable => {
+ let isPolicyUpdated = false;
+ return cy
+ .waitUntil(
+ () => {
+ return request({
+ method: 'GET',
+ url: agentRouteService.getInfoPath(agentId),
+ headers: {
+ 'elastic-api-version': API_VERSIONS.public.v1,
+ },
+ }).then((response) => {
+ if (
+ response.body.item.status !== 'updating' &&
+ response.body.item?.policy_revision === policyRevision &&
+ response.body.item?.policy_id === policyId
+ ) {
+ isPolicyUpdated = true;
+ return true;
+ }
+
+ return false;
+ });
+ },
+ { timeout: 120000 }
+ )
+ .then(() => {
+ return isPolicyUpdated;
+ });
+};
diff --git a/x-pack/plugins/security_solution/public/management/cypress/types.ts b/x-pack/plugins/security_solution/public/management/cypress/types.ts
index aee97723c7d51..6c5dae16100de 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/types.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/types.ts
@@ -66,3 +66,12 @@ export interface LoadUserAndRoleCyTaskOptions {
export interface CreateUserAndRoleCyTaskOptions {
role: Role;
}
+
+export interface UninstallAgentFromHostTaskOptions {
+ hostname: string;
+ uninstallToken: string;
+}
+
+export interface IsAgentAndEndpointUninstalledFromHostTaskOptions {
+ hostname: string;
+}
diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/translations.ts b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/translations.ts
index a1d35310b6bfe..cc538bedae1ea 100644
--- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/translations.ts
+++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/translations.ts
@@ -24,19 +24,3 @@ export const USER_RISK_TITLE = i18n.translate(
defaultMessage: 'User Risk Scores',
}
);
-
-export const HOST_RISK_TABLE_TOOLTIP = i18n.translate(
- 'xpack.securitySolution.entityAnalytics.hostsRiskDashboard.hostsTableTooltip',
- {
- defaultMessage:
- 'The host risk table is not affected by the time range. This table shows the latest recorded risk score for each host.',
- }
-);
-
-export const USER_RISK_TABLE_TOOLTIP = i18n.translate(
- 'xpack.securitySolution.entityAnalytics.usersRiskDashboard.usersTableTooltip',
- {
- defaultMessage:
- 'The user risk table is not affected by the time range. This table shows the latest recorded risk score for each user.',
- }
-);
diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx
index cdebe0042d777..120a4cf3d4c7f 100644
--- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/columns.tsx
@@ -17,6 +17,7 @@ import { RiskScoreLevel } from '../../../../explore/components/risk_score/severi
import { CELL_ACTIONS_TELEMETRY } from '../../../../explore/components/risk_score/constants';
import type {
HostRiskScore,
+ Maybe,
RiskSeverity,
UserRiskScore,
} from '../../../../../common/search_strategy';
@@ -29,6 +30,7 @@ import {
SecurityCellActionsTrigger,
SecurityCellActionType,
} from '../../../../common/components/cell_actions';
+import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date';
type HostRiskScoreColumns = Array>;
@@ -91,6 +93,21 @@ export const getRiskScoreColumns = (
return getEmptyTagValue();
},
},
+
+ {
+ field: RiskScoreFields.timestamp,
+ name: i18n.LAST_UPDATED,
+ truncateText: false,
+ mobileOptions: { show: true },
+ sortable: true,
+ width: '20%',
+ render: (lastSeen: Maybe) => {
+ if (lastSeen != null) {
+ return ;
+ }
+ return getEmptyTagValue();
+ },
+ },
{
field:
riskEntity === RiskScoreEntity.host
@@ -114,7 +131,7 @@ export const getRiskScoreColumns = (
{
field:
riskEntity === RiskScoreEntity.host ? RiskScoreFields.hostRisk : RiskScoreFields.userRisk,
- width: '30%',
+ width: '25%',
name: i18n.ENTITY_RISK_LEVEL(riskEntity),
truncateText: false,
mobileOptions: { show: true },
diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx
index 982d68952a5c0..97cf4363f690d 100644
--- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx
@@ -26,7 +26,6 @@ import { RiskScoresNoDataDetected } from '../../../../explore/components/risk_sc
import { useRefetchQueries } from '../../../../common/hooks/use_refetch_queries';
import { Loader } from '../../../../common/components/loader';
import { Panel } from '../../../../common/components/panel';
-import * as i18n from './translations';
import { useEntityInfo } from './use_entity';
import { RiskScoreHeaderContent } from './header_content';
import { ChartContent } from './chart_content';
@@ -175,11 +174,6 @@ const EntityAnalyticsRiskScoresComponent = ({ riskEntity }: { riskEntity: RiskSc
id={entity.tableQueryId}
toggleStatus={toggleStatus}
toggleQuery={setToggleStatus}
- tooltip={
- riskEntity === RiskScoreEntity.host
- ? i18n.HOST_RISK_TABLE_TOOLTIP
- : i18n.USER_RISK_TABLE_TOOLTIP
- }
>
},
});
-export const HOST_RISK_TABLE_TOOLTIP = i18n.translate(
- 'xpack.securitySolution.entityAnalytics.riskDashboard.hostsTableTooltip',
+export const LAST_UPDATED = i18n.translate(
+ 'xpack.securitySolution.entityAnalytics.riskDashboard.lastUpdatedTitle',
{
- defaultMessage:
- 'The Host Risk Score panel displays the list of risky hosts and their latest risk score. You may filter this list using global filters in the KQL search bar. The time-range picker filter will display Alerts within the selected time range only and does not filter the list of risky hosts.',
- }
-);
-
-export const USER_RISK_TABLE_TOOLTIP = i18n.translate(
- 'xpack.securitySolution.entityAnalytics.riskDashboard.usersTableTooltip',
- {
- defaultMessage:
- 'The User Risk Score panel displays the list of risky users and their latest risk score. You may filter this list using global filters in the KQL search bar. The time-range picker filter will display Alerts within the selected time range only and does not filter the list of risky users.',
+ defaultMessage: 'Last updated',
}
);
diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx
index 2a32874a044bc..686828412977a 100644
--- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx
@@ -10,7 +10,6 @@ import { euiDarkVars as darkTheme, euiLightVars as lightTheme } from '@kbn/ui-th
import { getOr } from 'lodash/fp';
import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';
-import { useGlobalTime } from '../../../common/containers/use_global_time';
import type { HostItem } from '../../../../common/search_strategy';
import { buildHostNamesFilter, RiskScoreEntity } from '../../../../common/search_strategy';
import { DEFAULT_DARK_MODE } from '../../../../common/constants';
@@ -90,20 +89,11 @@ export const HostOverview = React.memo(
() => (hostName ? buildHostNamesFilter([hostName]) : undefined),
[hostName]
);
- const { from, to } = useGlobalTime();
- const timerange = useMemo(
- () => ({
- from,
- to,
- }),
- [from, to]
- );
const { data: hostRisk, isAuthorized } = useRiskScore({
filterQuery,
riskEntity: RiskScoreEntity.host,
skip: hostName == null,
- timerange,
});
const getDefaultRenderer = useCallback(
diff --git a/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx
index 812c3f9340b0a..446fe215a695a 100644
--- a/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx
@@ -10,7 +10,6 @@ import { euiDarkVars as darkTheme, euiLightVars as lightTheme } from '@kbn/ui-th
import { getOr } from 'lodash/fp';
import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';
-import { useGlobalTime } from '../../../common/containers/use_global_time';
import { buildUserNamesFilter, RiskScoreEntity } from '../../../../common/search_strategy';
import { DEFAULT_DARK_MODE } from '../../../../common/constants';
import type { DescriptionList } from '../../../../common/utility_types';
@@ -89,20 +88,9 @@ export const UserOverview = React.memo(
[userName]
);
- const { from, to } = useGlobalTime();
-
- const timerange = useMemo(
- () => ({
- from,
- to,
- }),
- [from, to]
- );
-
const { data: userRisk, isAuthorized } = useRiskScore({
filterQuery,
skip: userName == null,
- timerange,
riskEntity: RiskScoreEntity.user,
});
diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/kpi/query.kpi_risk_score.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/kpi/query.kpi_risk_score.dsl.ts
index 4a98089eb239c..4dfb6896ffbc9 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/kpi/query.kpi_risk_score.dsl.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/risk_score/kpi/query.kpi_risk_score.dsl.ts
@@ -13,9 +13,22 @@ export const buildKpiRiskScoreQuery = ({
defaultIndex,
filterQuery,
entity,
+ timerange,
}: RiskScoreKpiRequestOptions) => {
const filter = [...createQueryFilterClauses(filterQuery)];
+ if (timerange) {
+ filter.push({
+ range: {
+ '@timestamp': {
+ gte: timerange.from,
+ lte: timerange.to,
+ format: 'strict_date_optional_time',
+ },
+ },
+ });
+ }
+
const dslQuery = {
index: defaultIndex,
allow_no_indices: false,
diff --git a/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts b/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts
index 47fc6f8ec18ba..5d481038b0869 100644
--- a/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts
+++ b/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts
@@ -302,7 +302,6 @@ export const GetPingsParamsType = t.intersection([
monitorId: t.string,
sort: t.string,
status: t.string,
- finalAttempt: t.boolean,
}),
]);
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_monitor_pings.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_monitor_pings.tsx
index aad04f78f361c..338b62d137f96 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_monitor_pings.tsx
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_monitor_pings.tsx
@@ -13,7 +13,6 @@ import { useSelectedLocation } from './use_selected_location';
import {
getMonitorRecentPingsAction,
selectMonitorPingsMetadata,
- selectShowOnlyFinalAttempts,
selectStatusFilter,
} from '../../../state';
@@ -34,8 +33,6 @@ export const useMonitorPings = (props?: UseMonitorPingsProps) => {
const monitorId = monitor?.id;
const locationLabel = location?.label;
- const showOnlyFinalAttempts = useSelector(selectShowOnlyFinalAttempts);
-
const statusFilter = useSelector(selectStatusFilter);
useEffect(() => {
@@ -48,7 +45,6 @@ export const useMonitorPings = (props?: UseMonitorPingsProps) => {
pageIndex: props?.pageIndex,
from: props?.from,
to: props?.to,
- finalAttempt: showOnlyFinalAttempts,
statusFilter,
})
);
@@ -62,7 +58,6 @@ export const useMonitorPings = (props?: UseMonitorPingsProps) => {
props?.pageIndex,
props?.from,
props?.to,
- showOnlyFinalAttempts,
statusFilter,
]);
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table_header.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table_header.tsx
index c703c3b253c85..cb708b6175f92 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table_header.tsx
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table_header.tsx
@@ -8,17 +8,8 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { i18n } from '@kbn/i18n';
-import {
- EuiButtonEmpty,
- EuiFlexGroup,
- EuiFlexItem,
- EuiLink,
- EuiSwitch,
- EuiTitle,
-} from '@elastic/eui';
+import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiLink, EuiTitle } from '@elastic/eui';
-import { useDispatch, useSelector } from 'react-redux';
-import { selectShowOnlyFinalAttempts, showOnlyFinalAttemptsAction } from '../../../state';
import { StatusFilter } from './status_filter';
import { MONITOR_HISTORY_ROUTE } from '../../../../../../common/constants';
import { ConfigKey, Ping } from '../../../../../../common/runtime_types';
@@ -43,10 +34,6 @@ export const TestRunsTableHeader = ({
const { monitor } = useSelectedMonitor();
- const showOnlyFinalAttempts = useSelector(selectShowOnlyFinalAttempts);
-
- const dispatch = useDispatch();
-
return (
@@ -58,15 +45,6 @@ export const TestRunsTableHeader = ({
-
- dispatch(showOnlyFinalAttemptsAction(e.target.checked))}
- />
-
{showViewHistoryButton ? (
{
}
>
-
+
>
);
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/actions.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/actions.ts
index b13233f5f2282..26e0a4c7f4c41 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/actions.ts
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/actions.ts
@@ -38,5 +38,4 @@ export const getMonitorRecentPingsAction = createAsyncAction('SHOW ONLY FINAL ATTEMPTS');
export const setStatusFilter = createAction<'up' | 'down' | undefined>('SET STATUS FILTER');
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/api.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/api.ts
index fb7953dba9cd6..da81433da6c04 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/api.ts
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/api.ts
@@ -32,7 +32,6 @@ export interface MostRecentPingsRequest {
to?: string;
size?: number;
pageIndex?: number;
- finalAttempt?: boolean;
statusFilter?: 'up' | 'down';
}
@@ -43,7 +42,6 @@ export const fetchMonitorRecentPings = async ({
to,
size = 10,
pageIndex = 0,
- finalAttempt,
statusFilter,
}: MostRecentPingsRequest): Promise => {
const locations = JSON.stringify([locationId]);
@@ -59,7 +57,6 @@ export const fetchMonitorRecentPings = async ({
sort,
size,
pageIndex,
- finalAttempt,
status: statusFilter,
},
PingsResponseType
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/index.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/index.ts
index cf3fff3c428d7..162ed90dfb928 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/index.ts
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/index.ts
@@ -19,7 +19,6 @@ import {
getMonitorRecentPingsAction,
setMonitorDetailsLocationAction,
getMonitorAction,
- showOnlyFinalAttemptsAction,
setStatusFilter,
} from './actions';
@@ -39,7 +38,6 @@ export interface MonitorDetailsState {
syntheticsMonitorDispatchedAt: number;
error: IHttpSerializedFetchError | null;
selectedLocationId: string | null;
- showOnlyFinalAttempts?: boolean;
statusFilter?: 'up' | 'down' | undefined;
}
@@ -51,7 +49,6 @@ const initialState: MonitorDetailsState = {
syntheticsMonitorDispatchedAt: 0,
error: null,
selectedLocationId: null,
- showOnlyFinalAttempts: false,
};
export const monitorDetailsReducer = createReducer(initialState, (builder) => {
@@ -116,9 +113,6 @@ export const monitorDetailsReducer = createReducer(initialState, (builder) => {
state.syntheticsMonitor = action.payload;
}
})
- .addCase(showOnlyFinalAttemptsAction, (state, action) => {
- state.showOnlyFinalAttempts = action.payload;
- })
.addCase(setStatusFilter, (state, action) => {
state.statusFilter = action.payload;
});
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/selectors.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/selectors.ts
index c87e8b6775c6b..af30569836e44 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/selectors.ts
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_details/selectors.ts
@@ -25,9 +25,5 @@ export const selectPingsLoading = createSelector(getState, (state) => state.ping
export const selectMonitorPingsMetadata = createSelector(getState, (state) => state.pings);
export const selectPingsError = createSelector(getState, (state) => state.error);
-export const selectShowOnlyFinalAttempts = createSelector(
- getState,
- (state) => state.showOnlyFinalAttempts ?? false
-);
export const selectStatusFilter = createSelector(getState, (state) => state.statusFilter);
diff --git a/x-pack/plugins/synthetics/server/common/pings/query_pings.ts b/x-pack/plugins/synthetics/server/common/pings/query_pings.ts
index 1bc8e58c1b46d..7b60fc8fcf536 100644
--- a/x-pack/plugins/synthetics/server/common/pings/query_pings.ts
+++ b/x-pack/plugins/synthetics/server/common/pings/query_pings.ts
@@ -50,7 +50,6 @@ export async function queryPings(
pageIndex,
locations,
excludedLocations,
- finalAttempt,
} = params;
const size = sizeParam ?? DEFAULT_PAGE_SIZE;
@@ -65,7 +64,6 @@ export async function queryPings(
{ range: { '@timestamp': { gte: from, lte: to } } },
...(monitorId ? [{ term: { 'monitor.id': monitorId } }] : []),
...(status ? [{ term: { 'monitor.status': status } }] : []),
- ...(finalAttempt ? [{ term: { 'summary.final_attempt': finalAttempt } }] : []),
] as QueryDslQueryContainer[],
},
},
diff --git a/x-pack/plugins/synthetics/server/routes/pings/get_pings.ts b/x-pack/plugins/synthetics/server/routes/pings/get_pings.ts
index 8b464ef887a3c..bec8f6a8a845d 100644
--- a/x-pack/plugins/synthetics/server/routes/pings/get_pings.ts
+++ b/x-pack/plugins/synthetics/server/routes/pings/get_pings.ts
@@ -21,7 +21,6 @@ export const getPingsRouteQuerySchema = schema.object({
pageIndex: schema.maybe(schema.number()),
sort: schema.maybe(schema.string()),
status: schema.maybe(schema.string()),
- finalAttempt: schema.maybe(schema.boolean()),
});
type GetPingsRouteRequest = TypeOf;
@@ -44,7 +43,6 @@ export const syntheticsGetPingsRoute: SyntheticsRestApiRouteFactory = () => ({
pageIndex,
locations,
excludedLocations,
- finalAttempt,
} = request.query as GetPingsRouteRequest;
return await queryPings({
@@ -58,7 +56,6 @@ export const syntheticsGetPingsRoute: SyntheticsRestApiRouteFactory = () => ({
pageIndex,
locations: locations ? JSON.parse(locations) : [],
excludedLocations,
- finalAttempt,
});
},
});
diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts
index c0e145aa501f6..0eeb757a453eb 100644
--- a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts
+++ b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts
@@ -178,273 +178,7 @@ describe('Search Strategy EQL helper', () => {
eventsResponse
);
- expect(result.edges).toMatchInlineSnapshot(`
- Array [
- Object {
- "cursor": Object {
- "tiebreaker": null,
- "value": "",
- },
- "node": Object {
- "_id": "qhymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005",
- "data": Array [
- Object {
- "field": "@timestamp",
- "value": Array [
- "2021-02-08T21:50:28.3377092Z",
- ],
- },
- Object {
- "field": "event.action",
- "value": Array [
- "log_on",
- ],
- },
- Object {
- "field": "event.category",
- "value": Array [
- "authentication",
- "session",
- ],
- },
- Object {
- "field": "host.name",
- "value": Array [
- "win2019-endpoint-mr-pedro",
- ],
- },
- Object {
- "field": "message",
- "value": Array [
- "Endpoint security event",
- ],
- },
- ],
- "ecs": Object {
- "@timestamp": Array [
- "2021-02-08T21:50:28.3377092Z",
- ],
- "_id": "qhymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005",
- "agent": Object {
- "id": Array [
- "1d15cf9e-3dc7-5b97-f586-743f7c2518b2",
- ],
- "type": Array [
- "endpoint",
- ],
- },
- "event": Object {
- "action": Array [
- "log_on",
- ],
- "category": Array [
- "authentication",
- "session",
- ],
- "created": Array [
- "2021-02-08T21:50:28.3377092Z",
- ],
- "dataset": Array [
- "endpoint.events.security",
- ],
- "id": Array [
- "LzzWB9jjGmCwGMvk++++FG/O",
- ],
- "kind": Array [
- "event",
- ],
- "module": Array [
- "endpoint",
- ],
- "outcome": Array [
- "success",
- ],
- "type": Array [
- "start",
- ],
- },
- "host": Object {
- "id": Array [
- "d8ad572e-d224-4044-a57d-f5a84c0dfe5d",
- ],
- "ip": Array [
- "10.128.0.57",
- "fe80::9ced:8f1c:880b:3e1f",
- "127.0.0.1",
- "::1",
- ],
- "name": Array [
- "win2019-endpoint-mr-pedro",
- ],
- "os": Object {
- "family": Array [
- "windows",
- ],
- "name": Array [
- "Windows",
- ],
- },
- },
- "message": Array [
- "Endpoint security event",
- ],
- "process": Object {
- "entity_id": Array [
- "MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTUyODQtMTMyNTcyOTQ2MjMuOTk2NTkxMDAw",
- ],
- "executable": Array [
- "C:\\\\Program Files\\\\OpenSSH-Win64\\\\sshd.exe",
- ],
- "name": Array [
- "C:\\\\Program Files\\\\OpenSSH-Win64\\\\sshd.exe",
- ],
- },
- "timestamp": "2021-02-08T21:50:28.3377092Z",
- "user": Object {
- "domain": Array [
- "NT AUTHORITY",
- ],
- "name": Array [
- "SYSTEM",
- ],
- },
- },
- },
- },
- Object {
- "cursor": Object {
- "tiebreaker": null,
- "value": "",
- },
- "node": Object {
- "_id": "qxymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005",
- "data": Array [
- Object {
- "field": "@timestamp",
- "value": Array [
- "2021-02-08T21:50:28.3377142Z",
- ],
- },
- Object {
- "field": "event.action",
- "value": Array [
- "log_on",
- ],
- },
- Object {
- "field": "event.category",
- "value": Array [
- "authentication",
- "session",
- ],
- },
- Object {
- "field": "host.name",
- "value": Array [
- "win2019-endpoint-mr-pedro",
- ],
- },
- Object {
- "field": "message",
- "value": Array [
- "Endpoint security event",
- ],
- },
- ],
- "ecs": Object {
- "@timestamp": Array [
- "2021-02-08T21:50:28.3377142Z",
- ],
- "_id": "qxymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005",
- "agent": Object {
- "id": Array [
- "1d15cf9e-3dc7-5b97-f586-743f7c2518b2",
- ],
- "type": Array [
- "endpoint",
- ],
- },
- "event": Object {
- "action": Array [
- "log_on",
- ],
- "category": Array [
- "authentication",
- "session",
- ],
- "created": Array [
- "2021-02-08T21:50:28.3377142Z",
- ],
- "dataset": Array [
- "endpoint.events.security",
- ],
- "id": Array [
- "LzzWB9jjGmCwGMvk++++FG/P",
- ],
- "kind": Array [
- "event",
- ],
- "module": Array [
- "endpoint",
- ],
- "outcome": Array [
- "success",
- ],
- "type": Array [
- "start",
- ],
- },
- "host": Object {
- "id": Array [
- "d8ad572e-d224-4044-a57d-f5a84c0dfe5d",
- ],
- "ip": Array [
- "10.128.0.57",
- "fe80::9ced:8f1c:880b:3e1f",
- "127.0.0.1",
- "::1",
- ],
- "name": Array [
- "win2019-endpoint-mr-pedro",
- ],
- "os": Object {
- "family": Array [
- "windows",
- ],
- "name": Array [
- "Windows",
- ],
- },
- },
- "message": Array [
- "Endpoint security event",
- ],
- "process": Object {
- "entity_id": Array [
- "MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTU4MC0xMzI1NTA3ODY2Ny45MTg5Njc1MDA=",
- ],
- "executable": Array [
- "C:\\\\Windows\\\\System32\\\\lsass.exe",
- ],
- },
- "timestamp": "2021-02-08T21:50:28.3377142Z",
- "user": Object {
- "domain": Array [
- "NT AUTHORITY",
- ],
- "name": Array [
- "SYSTEM",
- ],
- },
- },
- },
- },
- ]
- `);
+ expect(result.edges).toMatchInlineSnapshot(`Array []`);
});
it('sequence events', async () => {
const result = await parseEqlResponse(
@@ -467,282 +201,7 @@ describe('Search Strategy EQL helper', () => {
},
sequenceResponse
);
- expect(result.edges).toMatchInlineSnapshot(`
- Array [
- Object {
- "cursor": Object {
- "tiebreaker": null,
- "value": "",
- },
- "node": Object {
- "_id": "rBymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005",
- "data": Array [
- Object {
- "field": "@timestamp",
- "value": Array [
- "2021-02-08T21:50:28.3381013Z",
- ],
- },
- Object {
- "field": "event.category",
- "value": Array [],
- },
- Object {
- "field": "host.name",
- "value": Array [
- "win2019-endpoint-mr-pedro",
- ],
- },
- Object {
- "field": "message",
- "value": Array [
- "Endpoint security event",
- ],
- },
- ],
- "ecs": Object {
- "@timestamp": Array [
- "2021-02-08T21:50:28.3381013Z",
- ],
- "_id": "rBymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.security-default-2021.02.05-000005",
- "agent": Object {
- "id": Array [
- "1d15cf9e-3dc7-5b97-f586-743f7c2518b2",
- ],
- "type": Array [
- "endpoint",
- ],
- },
- "eql": Object {
- "parentId": "rBymg3cBX5UUcOOYP3Ec",
- "sequenceNumber": "2-0",
- },
- "event": Object {
- "category": Array [],
- "created": Array [
- "2021-02-08T21:50:28.3381013Z",
- ],
- "dataset": Array [
- "endpoint.events.security",
- ],
- "id": Array [
- "LzzWB9jjGmCwGMvk++++FG/Q",
- ],
- "kind": Array [
- "event",
- ],
- "module": Array [
- "endpoint",
- ],
- "type": Array [],
- },
- "host": Object {
- "id": Array [
- "d8ad572e-d224-4044-a57d-f5a84c0dfe5d",
- ],
- "ip": Array [
- "10.128.0.57",
- "fe80::9ced:8f1c:880b:3e1f",
- "127.0.0.1",
- "::1",
- ],
- "name": Array [
- "win2019-endpoint-mr-pedro",
- ],
- "os": Object {
- "family": Array [
- "windows",
- ],
- "name": Array [
- "Windows",
- ],
- },
- },
- "message": Array [
- "Endpoint security event",
- ],
- "process": Object {
- "entity_id": Array [
- "MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTU4MC0xMzI1NTA3ODY2Ny45MTg5Njc1MDA=",
- ],
- "executable": Array [
- "C:\\\\Windows\\\\System32\\\\lsass.exe",
- ],
- },
- "timestamp": "2021-02-08T21:50:28.3381013Z",
- "user": Object {
- "domain": Array [
- "NT AUTHORITY",
- ],
- "name": Array [
- "SYSTEM",
- ],
- },
- },
- },
- },
- Object {
- "cursor": Object {
- "tiebreaker": null,
- "value": "",
- },
- "node": Object {
- "_id": "pxymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.process-default-2021.02.02-000005",
- "data": Array [
- Object {
- "field": "@timestamp",
- "value": Array [
- "2021-02-08T21:50:28.3446355Z",
- ],
- },
- Object {
- "field": "event.action",
- "value": Array [
- "start",
- ],
- },
- Object {
- "field": "event.category",
- "value": Array [
- "process",
- ],
- },
- Object {
- "field": "host.name",
- "value": Array [
- "win2019-endpoint-mr-pedro",
- ],
- },
- Object {
- "field": "message",
- "value": Array [
- "Endpoint process event",
- ],
- },
- ],
- "ecs": Object {
- "@timestamp": Array [
- "2021-02-08T21:50:28.3446355Z",
- ],
- "_id": "pxymg3cBX5UUcOOYP3Ec",
- "_index": ".ds-logs-endpoint.events.process-default-2021.02.02-000005",
- "agent": Object {
- "id": Array [
- "1d15cf9e-3dc7-5b97-f586-743f7c2518b2",
- ],
- "type": Array [
- "endpoint",
- ],
- },
- "eql": Object {
- "parentId": "rBymg3cBX5UUcOOYP3Ec",
- "sequenceNumber": "2-1",
- },
- "event": Object {
- "action": Array [
- "start",
- ],
- "category": Array [
- "process",
- ],
- "created": Array [
- "2021-02-08T21:50:28.3446355Z",
- ],
- "dataset": Array [
- "endpoint.events.process",
- ],
- "id": Array [
- "LzzWB9jjGmCwGMvk++++FG/K",
- ],
- "kind": Array [
- "event",
- ],
- "module": Array [
- "endpoint",
- ],
- "type": Array [
- "start",
- ],
- },
- "host": Object {
- "id": Array [
- "d8ad572e-d224-4044-a57d-f5a84c0dfe5d",
- ],
- "ip": Array [
- "10.128.0.57",
- "fe80::9ced:8f1c:880b:3e1f",
- "127.0.0.1",
- "::1",
- ],
- "name": Array [
- "win2019-endpoint-mr-pedro",
- ],
- "os": Object {
- "family": Array [
- "windows",
- ],
- "name": Array [
- "Windows",
- ],
- },
- },
- "message": Array [
- "Endpoint process event",
- ],
- "process": Object {
- "args": Array [
- "C:\\\\Program Files\\\\OpenSSH-Win64\\\\sshd.exe",
- "-y",
- ],
- "entity_id": Array [
- "MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTYzNjgtMTMyNTcyOTQ2MjguMzQ0NjM1NTAw",
- ],
- "executable": Array [
- "C:\\\\Program Files\\\\OpenSSH-Win64\\\\sshd.exe",
- ],
- "hash": Object {
- "md5": Array [
- "331ba0e529810ef718dd3efbd1242302",
- ],
- "sha1": Array [
- "631244d731f406394c17c7dfd85203e317c74814",
- ],
- "sha256": Array [
- "e6a972f9db27de18be225095b3b3141b945be8aadc4014c8704ae5acafe3e8e0",
- ],
- },
- "name": Array [
- "sshd.exe",
- ],
- "parent": Object {
- "name": Array [
- "sshd.exe",
- ],
- "pid": Array [
- "5284",
- ],
- },
- "pid": Array [
- "6368",
- ],
- },
- "timestamp": "2021-02-08T21:50:28.3446355Z",
- "user": Object {
- "domain": Array [
- "",
- ],
- "name": Array [
- "",
- ],
- },
- },
- },
- },
- ]
- `);
+ expect(result.edges).toMatchInlineSnapshot(`Array []`);
});
});
});
diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts
index e84bf7bd9bda9..2b4f562954df1 100644
--- a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts
+++ b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts
@@ -113,11 +113,11 @@ export const parseEqlResponse = async (
} = options;
let edges: TimelineEdges[] = [];
- if (response.rawResponse.body.hits.sequences !== undefined) {
- edges = await parseSequences(response.rawResponse.body.hits.sequences, options.fieldRequested);
- } else if (response.rawResponse.body.hits.events !== undefined) {
+ if (response.rawResponse.hits.sequences !== undefined) {
+ edges = await parseSequences(response.rawResponse.hits.sequences, options.fieldRequested);
+ } else if (response.rawResponse.hits.events !== undefined) {
edges = await Promise.all(
- response.rawResponse.body.hits.events.map(async (event) =>
+ response.rawResponse.hits.events.map(async (event) =>
formatTimelineData(options.fieldRequested, TIMELINE_EVENTS_FIELDS, event as EventHit)
)
);
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 3f6db08f7b178..f12c565dc7293 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -2442,6 +2442,25 @@
"fieldUtils.fieldNameDescription.textField": "Texte intégral tel que le corps d'un e-mail ou la description d'un produit.",
"fieldUtils.fieldNameDescription.unknownField": "Champ inconnu",
"fieldUtils.fieldNameDescription.versionField": "Versions des logiciels. Prend en charge les règles de priorité de la Gestion sémantique des versions.",
+ "unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} – Ce champ représente l'heure à laquelle les événements se sont produits.",
+ "unifiedDataTable.searchGenerationWithDescription": "Tableau généré par la recherche {searchTitle}",
+ "unifiedDataTable.searchGenerationWithDescriptionGrid": "Tableau généré par la recherche {searchTitle} ({searchDescription})",
+ "unifiedDataTable.selectedDocumentsNumber": "{nr} documents sélectionnés",
+ "unifiedDataTable.clearSelection": "Effacer la sélection",
+ "unifiedDataTable.controlColumnHeader": "Colonne de commande",
+ "unifiedDataTable.copyToClipboardJSON": "Copier les documents dans le presse-papiers (JSON)",
+ "unifiedDataTable.tableHeader.timeFieldIconTooltip": "Ce champ représente l'heure à laquelle les événements se sont produits.",
+ "unifiedDataTable.grid.copyColumnNameToClipBoardButton": "Copier le nom",
+ "unifiedDataTable.grid.copyColumnValuesToClipBoardButton": "Copier la colonne",
+ "unifiedDataTable.grid.documentHeader": "Document",
+ "unifiedDataTable.grid.editFieldButton": "Modifier le champ de la vue de données",
+ "unifiedDataTable.grid.selectDoc": "Sélectionner le document \"{rowNumber}\"",
+ "unifiedDataTable.loadingResults": "Chargement des résultats",
+ "unifiedDataTable.noResultsFound": "Résultat introuvable",
+ "unifiedDataTable.removeColumnLabel": "Supprimer la colonne",
+ "unifiedDataTable.selectColumnHeader": "Sélectionner la colonne",
+ "unifiedDataTable.showAllDocuments": "Afficher tous les documents",
+ "unifiedDataTable.showSelectedDocumentsOnly": "Afficher uniquement les documents sélectionnés",
"unifiedDocViewer.docView.table.actions.label": "Actions",
"unifiedDocViewer.docView.table.actions.open": "Actions ouvertes",
"unifiedDocViewer.docView.table.ignored.multiAboveTooltip": "Une ou plusieurs valeurs dans ce champ sont trop longues et ne peuvent pas être recherchées ni filtrées.",
@@ -14051,8 +14070,6 @@
"xpack.enterpriseSearch.errorConnectingState.setupGuideCta": "Consulter le guide de configuration",
"xpack.enterpriseSearch.errorConnectingState.title": "Impossible d'établir une connexion",
"xpack.enterpriseSearch.errorConnectingState.troubleshootAuth": "Vérifiez votre authentification utilisateur :",
- "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthNative": "Vous devez vous authentifier à l'aide d'une authentification native d'Elasticsearch, de SSO/SAML ou d'OpenID Connect.",
- "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthSAML": "Si vous utilisez un fournisseur de SSO externe, tel que SAML ou OpenID Connect, votre domaine SAML/OIDC doit également être configuré sur Enterprise Search.",
"xpack.enterpriseSearch.aiSearch.description": "Le kit d’outils permettant aux développeurs de créer des applications d’IA optimisées pour la recherche à l’aide de la plateforme Elastic.",
"xpack.enterpriseSearch.aiSearch.elser.description.elserLinkText": "Elastic Learned Sparse Encoder v2",
"xpack.enterpriseSearch.aiSearch.elserAccordion.description": "Fonctionnalités de recherche sémantique instantanée",
@@ -18420,7 +18437,6 @@
"xpack.infra.deprecations.timestampAdjustIndexing": "Ajustez votre indexation pour utiliser \"{field}\" comme horodatage.",
"xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "Dernières {duration} de données pour l'heure sélectionnée",
"xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "Une erreur s’est produite lors de la création d’une vue de données : {metricAlias}. Essayez de recharger la page.",
- "xpack.infra.hostsViewPage.landing.calloutRoleClarificationWithDocsLink": "Un rôle avec accès aux paramètres avancés dans Kibana sera nécessaire. {docsLink}",
"xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "Moyenne (de {limit} hôtes)",
"xpack.infra.hostsViewPage.kpi.subtitle.hostCount.limit": "Limité à {limit}",
"xpack.infra.hostsViewPage.table.selectedHostsButton": "Sélection effectuée de {selectedHostsCount} {selectedHostsCount, plural, =1 {hôte} one {hôtes} many {hôtes} other {hôtes}}",
@@ -18648,12 +18664,6 @@
"xpack.infra.hostsViewPage.hostLimit": "Limite de l'hôte",
"xpack.infra.hostsViewPage.hostLimit.tooltip": "Pour garantir des performances de recherche plus rapides, le nombre d'hôtes retournés est limité.",
"xpack.infra.hostsViewPage.kpi.hostCount.title": "Hôtes",
- "xpack.infra.hostsViewPage.landing.calloutReachOutToYourKibanaAdministrator": "Votre rôle d'utilisateur ne dispose pas des privilèges suffisants pour activer cette fonctionnalité - veuillez \n contacter votre administrateur Kibana et lui demander de visiter cette page pour activer la fonctionnalité.",
- "xpack.infra.hostsViewPage.landing.enableHostsView": "Activer la vue des hôtes",
- "xpack.infra.hostsViewPage.landing.introMessage": "Bienvenue sur la fonctionnalité \"Hôtes\", désormais disponible en version bêta. Avec ce puissant outil, \n vous pouvez facilement voir et analyser vos hôtes et identifier tout problème afin de les corriger rapidement. \n Obtenez une vue détaillée des indicateurs pour vos hôtes afin de savoir lesquels déclenchent le plus d’alertes, et filtrez \n les hôtes que vous voulez analyser à l'aide de tout filtre KQL ainsi que de répartitions simples comme le fournisseur cloud et \n le système d'exploitation.",
- "xpack.infra.hostsViewPage.landing.introTitle": "Analyse de l'hôte",
- "xpack.infra.hostsViewPage.landing.learnMore": "En savoir plus",
- "xpack.infra.hostsViewPage.landing.tryTheFeatureMessage": "Ceci est une version bêta de la fonctionnalité, donc nous apprécierions recevoir vos \n commentaires tandis que nous continuons à la développer et à l'améliorer. Pour accéder à la fonctionnalité, \n activez-la simplement ci-dessous (ou contactez votre administrateur interne si indisponible). \n Ne passez pas à côté de cette puissante fonctionnalité : essayez-là dès aujourd'hui !",
"xpack.infra.hostsViewPage.metrics.tooltip.cpuUsage": "Pourcentage de temps CPU utilisé dans les états autres que Inactif et IOWait, normalisée par le nombre de cœurs de processeur. Cela inclut le temps passé à la fois sur l'espace utilisateur et sur l'espace du noyau.",
"xpack.infra.hostsViewPage.metrics.tooltip.diskLatency": "Temps passé à gérer les requêtes de disque.",
"xpack.infra.hostsViewPage.metrics.tooltip.diskSpaceUsage": "Pourcentage d’espace disque utilisé.",
@@ -32359,15 +32369,11 @@
"xpack.securitySolution.entityAnalytics.header.anomalies": "Anomalies",
"xpack.securitySolution.entityAnalytics.header.criticalHosts": "Hôtes critiques",
"xpack.securitySolution.entityAnalytics.header.criticalUsers": "Utilisateurs critiques",
- "xpack.securitySolution.entityAnalytics.hostsRiskDashboard.hostsTableTooltip": "Le tableau des risques de l'hôte n'est pas affecté par la plage temporelle. Ce tableau montre le dernier score de risque enregistré pour chaque hôte.",
"xpack.securitySolution.entityAnalytics.hostsRiskDashboard.title": "Scores de risque de l'hôte",
- "xpack.securitySolution.entityAnalytics.riskDashboard.hostsTableTooltip": "Le panneau de Score de risque de l'hôte affiche la liste des hôtes à risque ainsi que leur dernier score de risque. Vous pouvez filtrer cette liste à l’aide de filtres globaux dans la barre de recherche KQL. Le filtre de sélecteur de plage temporelle affiche les alertes dans l’intervalle de temps sélectionné uniquement et ne filtre pas la liste des hôtes à risque.",
- "xpack.securitySolution.entityAnalytics.riskDashboard.usersTableTooltip": "Le panneau de score de risque de l'utilisateur affiche la liste des utilisateurs à risque et leur dernier score de risque. Vous pouvez filtrer cette liste à l’aide de filtres globaux dans la barre de recherche KQL. Le filtre de sélecteur de plage temporelle affiche uniquement les alertes dans l’intervalle de temps sélectionné et ne filtre pas la liste des utilisateurs à risque.",
"xpack.securitySolution.entityAnalytics.riskDashboard.viewAllLabel": "Afficher tout",
"xpack.securitySolution.entityAnalytics.technicalPreviewLabel": "Version d'évaluation technique",
"xpack.securitySolution.entityAnalytics.totalLabel": "Total",
"xpack.securitySolution.entityAnalytics.usersRiskDashboard.title": "Scores de risque de l'utilisateur",
- "xpack.securitySolution.entityAnalytics.usersRiskDashboard.usersTableTooltip": "Le tableau des risques de l'utilisateur n'est pas affecté par la plage temporelle. Ce tableau montre le dernier score de risque enregistré pour chaque utilisateur.",
"xpack.securitySolution.event.module.linkToElasticEndpointSecurityDescription": "Ouvrir dans Endpoint Security",
"xpack.securitySolution.event.summary.threat_indicator.modal.allMatches": "Toutes les correspondances d'indicateur",
"xpack.securitySolution.event.summary.threat_indicator.modal.close": "Fermer",
@@ -32775,10 +32781,8 @@
"xpack.securitySolution.hostsRiskTable.hostNameTitle": "Nom d'hôte",
"xpack.securitySolution.hostsRiskTable.hostRiskScoreTitle": "Score de risque de l'hôte",
"xpack.securitySolution.hostsRiskTable.hostRiskTitle": "Risque de l'hôte",
- "xpack.securitySolution.hostsRiskTable.hostsTableTooltip": "Le tableau des risques de l'hôte n'est pas affecté par la plage temporelle KQL. Ce tableau montre le dernier score de risque enregistré pour chaque hôte.",
"xpack.securitySolution.hostsRiskTable.riskTitle": "Classification de risque de l'hôte",
"xpack.securitySolution.hostsRiskTable.tableTitle": "Risque de l'hôte",
- "xpack.securitySolution.hostsRiskTable.usersTableTooltip": "Le tableau des risques de l'utilisateur n'est pas affecté par la plage temporelle KQL. Ce tableau montre le dernier score de risque enregistré pour chaque utilisateur.",
"xpack.securitySolution.hostsTable.firstLastSeenToolTip": "Par rapport à la plage de dates sélectionnée",
"xpack.securitySolution.hostsTable.hostsTitle": "Tous les hôtes",
"xpack.securitySolution.hostsTable.lastSeenTitle": "Vu en dernier",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 3e2165795ded9..a08fadcf5bebc 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -2457,6 +2457,25 @@
"fieldUtils.fieldNameDescription.textField": "電子メール本文や製品説明などの全文テキスト。",
"fieldUtils.fieldNameDescription.unknownField": "不明なフィールド",
"fieldUtils.fieldNameDescription.versionField": "ソフトウェアバージョン。「セマンティックバージョニング」優先度ルールをサポートします。",
+ "unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} - このフィールドはイベントの発生時刻を表します。",
+ "unifiedDataTable.searchGenerationWithDescription": "検索{searchTitle}で生成されたテーブル",
+ "unifiedDataTable.searchGenerationWithDescriptionGrid": "検索{searchTitle}で生成されたテーブル({searchDescription})",
+ "unifiedDataTable.selectedDocumentsNumber": "{nr}個のドキュメントが選択されました",
+ "unifiedDataTable.clearSelection": "選択した項目をクリア",
+ "unifiedDataTable.controlColumnHeader": "列の制御",
+ "unifiedDataTable.copyToClipboardJSON": "ドキュメントをクリップボードにコピー(JSON)",
+ "unifiedDataTable.tableHeader.timeFieldIconTooltip": "このフィールドはイベントの発生時刻を表します。",
+ "unifiedDataTable.grid.copyColumnNameToClipBoardButton": "名前をコピー",
+ "unifiedDataTable.grid.copyColumnValuesToClipBoardButton": "列をコピー",
+ "unifiedDataTable.grid.documentHeader": "ドキュメント",
+ "unifiedDataTable.grid.editFieldButton": "データビューフィールドを編集",
+ "unifiedDataTable.grid.selectDoc": "ドキュメント'{rowNumber}'を選択",
+ "unifiedDataTable.loadingResults": "結果を読み込み中",
+ "unifiedDataTable.noResultsFound": "結果が見つかりませんでした",
+ "unifiedDataTable.removeColumnLabel": "列を削除",
+ "unifiedDataTable.selectColumnHeader": "列を選択",
+ "unifiedDataTable.showAllDocuments": "すべてのドキュメントを表示",
+ "unifiedDataTable.showSelectedDocumentsOnly": "選択したドキュメントのみを表示",
"unifiedDocViewer.docView.table.actions.label": "アクション",
"unifiedDocViewer.docView.table.actions.open": "アクションを開く",
"unifiedDocViewer.docView.table.ignored.multiAboveTooltip": "このフィールドの1つ以上の値が長すぎるため、検索またはフィルタリングできません。",
@@ -14065,8 +14084,6 @@
"xpack.enterpriseSearch.errorConnectingState.setupGuideCta": "セットアップガイドを確認",
"xpack.enterpriseSearch.errorConnectingState.title": "接続できません",
"xpack.enterpriseSearch.errorConnectingState.troubleshootAuth": "ユーザー認証を確認してください。",
- "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthNative": "Elasticsearchネイティブ認証、SSO/SAML、またはOpenID Connectを使用して認証する必要があります。",
- "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthSAML": "SAMLやOpenID Connectなどの外部SSOプロバイダーを使用している場合は、エンタープライズ サーチでSAML/OIDCレルムを設定できる必要があります。",
"xpack.enterpriseSearch.aiSearch.description": "開発者がElasticプラットフォームを使ってAI検索エンジンを搭載したアプリケーションを構築するためのツールキット。",
"xpack.enterpriseSearch.aiSearch.elser.description.elserLinkText": "Elastic Learned Sparse Encoder v2",
"xpack.enterpriseSearch.aiSearch.elserAccordion.description": "即時セマンティック検索機能",
@@ -18434,7 +18451,6 @@
"xpack.infra.deprecations.timestampAdjustIndexing": "インデックスを調整し、\"{field}\"をタイムスタンプとして使用します。",
"xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "指定期間のデータの最後の{duration}",
"xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "データビューの作成中にエラーが発生しました:{metricAlias}。ページを再読み込みしてください。",
- "xpack.infra.hostsViewPage.landing.calloutRoleClarificationWithDocsLink": "Kibanaの高度な設定にアクセスできるロールが必要です。{docsLink}",
"xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "({limit}ホストの)平均",
"xpack.infra.hostsViewPage.kpi.subtitle.hostCount.limit": "{limit}に制限",
"xpack.infra.hostsViewPage.table.selectedHostsButton": "{selectedHostsCount}件の{selectedHostsCount, plural, =1 {ホスト} other {ホスト}}が選択済み",
@@ -18662,12 +18678,6 @@
"xpack.infra.hostsViewPage.hostLimit": "ホスト制限",
"xpack.infra.hostsViewPage.hostLimit.tooltip": "クエリパフォーマンスを確実に高めるために、返されるホスト数には制限があります",
"xpack.infra.hostsViewPage.kpi.hostCount.title": "ホスト",
- "xpack.infra.hostsViewPage.landing.calloutReachOutToYourKibanaAdministrator": "ユーザーロールには、この機能を有効にするための十分な権限がありません。 \n この機能を有効にするために、Kibana管理者に連絡して、このページにアクセスするように依頼してください。",
- "xpack.infra.hostsViewPage.landing.enableHostsView": "ホストビューを有効化",
- "xpack.infra.hostsViewPage.landing.introMessage": "「ホスト」機能へようこそ!ベータ版でご利用いただけるようになりました。この強力なツールを使用すると、\n ホストを簡単に表示、分析し、あらゆる問題を特定して、迅速に対処できます。\n ホストのメトリックを詳細に表示し、どのメトリックが最も多くのアラートをトリガーしているかを確認し、 \n 任意のKQLフィルターを使用して分析したいホストや、クラウドプロバイダーやオペレーティングシステムといった簡単な内訳をフィルターできます \n 。",
- "xpack.infra.hostsViewPage.landing.introTitle": "ホスト分析",
- "xpack.infra.hostsViewPage.landing.learnMore": "詳細",
- "xpack.infra.hostsViewPage.landing.tryTheFeatureMessage": "この機能はベータ版です。ご意見をお聞かせください。 \n 機能の開発と改善に役立てます。この機能を使用するには、\n 以下で有効化します(あるいは、使用できない場合は、社内管理者に問い合わせてください)。\n この強力な機能をぜひご利用ください。今すぐお試しください。",
"xpack.infra.hostsViewPage.metrics.tooltip.cpuUsage": "アイドルおよびIOWait以外の状態で費やされたCPU時間の割合を、CPUコア数で正規化したもの。これにはユーザースペースとカーネルスペースの両方で費やされた時間が含まれます。",
"xpack.infra.hostsViewPage.metrics.tooltip.diskLatency": "ディスクリクエストの処理に費やされた時間。",
"xpack.infra.hostsViewPage.metrics.tooltip.diskSpaceUsage": "使用済みディスク容量の割合。",
@@ -32358,15 +32368,11 @@
"xpack.securitySolution.entityAnalytics.header.anomalies": "異常",
"xpack.securitySolution.entityAnalytics.header.criticalHosts": "重要なホスト",
"xpack.securitySolution.entityAnalytics.header.criticalUsers": "重要なユーザー",
- "xpack.securitySolution.entityAnalytics.hostsRiskDashboard.hostsTableTooltip": "ホストリスク表は時間範囲の影響を受けません。この表は、各ホストの最後に記録されたリスクスコアを示します。",
"xpack.securitySolution.entityAnalytics.hostsRiskDashboard.title": "ホストリスクスコア",
- "xpack.securitySolution.entityAnalytics.riskDashboard.hostsTableTooltip": "ホストリスクスコアパネルには、リスクのあるホストの一覧と最新のリスクスコアが表示されます。KQL検索バーのグローバルフィルターを使って、この一覧をフィルタリングできます。時間範囲ピッカーフィルターは、選択した時間範囲内のアラートのみを表示し、リスクのあるホストの一覧をフィルタリングしません。",
- "xpack.securitySolution.entityAnalytics.riskDashboard.usersTableTooltip": "ユーザーリスクスコアパネルには、リスクのあるユーザーの一覧と最新のリスクスコアが表示されます。KQL検索バーのグローバルフィルターを使って、この一覧をフィルタリングできます。時間範囲ピッカーフィルターは、選択した時間範囲内のアラートのみを表示し、リスクのあるユーザーの一覧をフィルタリングしません。",
"xpack.securitySolution.entityAnalytics.riskDashboard.viewAllLabel": "すべて表示",
"xpack.securitySolution.entityAnalytics.technicalPreviewLabel": "テクニカルプレビュー",
"xpack.securitySolution.entityAnalytics.totalLabel": "合計",
"xpack.securitySolution.entityAnalytics.usersRiskDashboard.title": "ユーザーリスクスコア",
- "xpack.securitySolution.entityAnalytics.usersRiskDashboard.usersTableTooltip": "ユーザーリスク表は時間範囲の影響を受けません。この表は、各ユーザーの最後に記録されたリスクスコアを示します。",
"xpack.securitySolution.event.module.linkToElasticEndpointSecurityDescription": "Endpoint Securityで開く",
"xpack.securitySolution.event.summary.threat_indicator.modal.allMatches": "すべてのインジケーター一致",
"xpack.securitySolution.event.summary.threat_indicator.modal.close": "閉じる",
@@ -32774,10 +32780,8 @@
"xpack.securitySolution.hostsRiskTable.hostNameTitle": "ホスト名",
"xpack.securitySolution.hostsRiskTable.hostRiskScoreTitle": "ホストリスクスコア",
"xpack.securitySolution.hostsRiskTable.hostRiskTitle": "ホストリスク",
- "xpack.securitySolution.hostsRiskTable.hostsTableTooltip": "ホストリスク表はKQL時間範囲の影響を受けません。この表は、各ホストの最後に記録されたリスクスコアを示します。",
"xpack.securitySolution.hostsRiskTable.riskTitle": "ホストリスク分類",
"xpack.securitySolution.hostsRiskTable.tableTitle": "ホストリスク",
- "xpack.securitySolution.hostsRiskTable.usersTableTooltip": "ユーザーリスク表はKQL時間範囲の影響を受けません。この表は、各ユーザーの最後に記録されたリスクスコアを示します。",
"xpack.securitySolution.hostsTable.firstLastSeenToolTip": "選択された日付範囲との相関付けです",
"xpack.securitySolution.hostsTable.hostsTitle": "すべてのホスト",
"xpack.securitySolution.hostsTable.lastSeenTitle": "前回の認識",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 6172231f9a2d1..cdcbd17d43d3f 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -2457,6 +2457,25 @@
"fieldUtils.fieldNameDescription.textField": "全文本,如电子邮件正文或产品描述。",
"fieldUtils.fieldNameDescription.unknownField": "未知字段",
"fieldUtils.fieldNameDescription.versionField": "软件版本。支持“语义版本控制”优先规则。",
+ "unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} - 此字段表示事件发生的时间。",
+ "unifiedDataTable.searchGenerationWithDescription": "搜索 {searchTitle} 生成的表",
+ "unifiedDataTable.searchGenerationWithDescriptionGrid": "搜索 {searchTitle} 生成的表({searchDescription})",
+ "unifiedDataTable.selectedDocumentsNumber": "{nr} 个文档已选择",
+ "unifiedDataTable.clearSelection": "清除所选内容",
+ "unifiedDataTable.controlColumnHeader": "控制列",
+ "unifiedDataTable.copyToClipboardJSON": "将文档复制到剪贴板 (JSON)",
+ "unifiedDataTable.tableHeader.timeFieldIconTooltip": "此字段表示事件发生的时间。",
+ "unifiedDataTable.grid.copyColumnNameToClipBoardButton": "复制名称",
+ "unifiedDataTable.grid.copyColumnValuesToClipBoardButton": "复制列",
+ "unifiedDataTable.grid.documentHeader": "文档",
+ "unifiedDataTable.grid.editFieldButton": "编辑数据视图字段",
+ "unifiedDataTable.grid.selectDoc": "选择文档“{rowNumber}”",
+ "unifiedDataTable.loadingResults": "正在加载结果",
+ "unifiedDataTable.noResultsFound": "找不到结果",
+ "unifiedDataTable.removeColumnLabel": "移除列",
+ "unifiedDataTable.selectColumnHeader": "选择列",
+ "unifiedDataTable.showAllDocuments": "显示所有文档",
+ "unifiedDataTable.showSelectedDocumentsOnly": "仅显示选定的文档",
"unifiedDocViewer.docView.table.actions.label": "操作",
"unifiedDocViewer.docView.table.actions.open": "打开操作",
"unifiedDocViewer.docView.table.ignored.multiAboveTooltip": "此字段中的一个或多个值过长,无法搜索或筛选。",
@@ -14065,8 +14084,6 @@
"xpack.enterpriseSearch.errorConnectingState.setupGuideCta": "阅读设置指南",
"xpack.enterpriseSearch.errorConnectingState.title": "无法连接",
"xpack.enterpriseSearch.errorConnectingState.troubleshootAuth": "检查您的用户身份验证:",
- "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthNative": "必须使用 Elasticsearch 本机身份验证、SSO/SAML 或 OpenID Connect 执行身份验证。",
- "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthSAML": "如果使用外部 SSO 提供程序,如 SAML 或 OpenID Connect,还必须在 Enterprise Search 上设置 SAML/OIDC Realm。",
"xpack.enterpriseSearch.aiSearch.description": "工具套件,供开发者使用 Elastic 平台构建 AI 搜索驱动型应用程序。",
"xpack.enterpriseSearch.aiSearch.elser.description.elserLinkText": "Elastic Learned Sparse Encoder v2",
"xpack.enterpriseSearch.aiSearch.elserAccordion.description": "即时语义搜索功能",
@@ -18434,7 +18451,6 @@
"xpack.infra.deprecations.timestampAdjustIndexing": "调整索引以将“{field}”用作时间戳。",
"xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "选定时间过去 {duration}的数据",
"xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "尝试创建以下数据视图时出错:{metricAlias}。尝试重新加载该页面。",
- "xpack.infra.hostsViewPage.landing.calloutRoleClarificationWithDocsLink": "他们将需要有权访问 Kibana 中的高级设置的角色。{docsLink}",
"xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "平均值(属于 {limit} 台主机)",
"xpack.infra.hostsViewPage.kpi.subtitle.hostCount.limit": "限定为 {limit}",
"xpack.infra.hostsViewPage.table.selectedHostsButton": "已选定 {selectedHostsCount} 个{selectedHostsCount, plural, =1 {主机} other {主机}}",
@@ -18662,12 +18678,6 @@
"xpack.infra.hostsViewPage.hostLimit": "主机限制",
"xpack.infra.hostsViewPage.hostLimit.tooltip": "为确保更快的查询性能,对返回的主机数量实施了限制",
"xpack.infra.hostsViewPage.kpi.hostCount.title": "主机",
- "xpack.infra.hostsViewPage.landing.calloutReachOutToYourKibanaAdministrator": "您的用户角色权限不足,无法启用此功能 - 请 \n 联系您的 Kibana 管理员,要求他们访问此页面以启用该功能。",
- "xpack.infra.hostsViewPage.landing.enableHostsView": "启用主机视图",
- "xpack.infra.hostsViewPage.landing.introMessage": "欢迎使用“主机”功能,该功能现在为公测版!使用这个强大的工具,\n 您可以轻松查看并分析主机,并确定任何问题以便快速予以解决。\n 获取您主机的详细指标视图,了解哪些指标触发了大多数告警, \n 并使用任何 KQL 筛选以及云提供商和操作系统等常见细目筛选 \n 您要分析的主机。",
- "xpack.infra.hostsViewPage.landing.introTitle": "主机分析",
- "xpack.infra.hostsViewPage.landing.learnMore": "了解详情",
- "xpack.infra.hostsViewPage.landing.tryTheFeatureMessage": "这是公测版功能,我们乐于收到您的反馈, \n 以便我们继续开发和改进该功能。要访问该功能,\n 只需在下面直接启用即可(或在不可用时联系您的内部管理员)。\n 不要错过这个强大的功能 - 立即试用!",
"xpack.infra.hostsViewPage.metrics.tooltip.cpuUsage": "CPU 在空闲和 IOWait 状态以外所花费时间的百分比,按 CPU 核心数进行标准化。这包括在用户空间和内核空间上花费的时间。",
"xpack.infra.hostsViewPage.metrics.tooltip.diskLatency": "处理磁盘请求所花费的时间。",
"xpack.infra.hostsViewPage.metrics.tooltip.diskSpaceUsage": "已用磁盘空间百分比。",
@@ -32354,15 +32364,11 @@
"xpack.securitySolution.entityAnalytics.header.anomalies": "异常",
"xpack.securitySolution.entityAnalytics.header.criticalHosts": "关键主机",
"xpack.securitySolution.entityAnalytics.header.criticalUsers": "关键用户",
- "xpack.securitySolution.entityAnalytics.hostsRiskDashboard.hostsTableTooltip": "主机风险表不受时间范围影响。本表显示每台主机最新记录的风险分数。",
"xpack.securitySolution.entityAnalytics.hostsRiskDashboard.title": "主机风险分数",
- "xpack.securitySolution.entityAnalytics.riskDashboard.hostsTableTooltip": "“主机风险分数”面板显示有风险主机及其最新风险分数的列表。可以在 KQL 搜索栏中使用全局筛选来筛选此列表。时间范围选取器筛选将仅显示选定时间范围内的告警,并且不筛选有风险主机列表。",
- "xpack.securitySolution.entityAnalytics.riskDashboard.usersTableTooltip": "“用户风险分数”面板显示有风险用户及其最新风险分数的列表。可以在 KQL 搜索栏中使用全局筛选来筛选此列表。时间范围选取器筛选将仅显示选定时间范围内的告警,并且不筛选有风险用户列表。",
"xpack.securitySolution.entityAnalytics.riskDashboard.viewAllLabel": "查看全部",
"xpack.securitySolution.entityAnalytics.technicalPreviewLabel": "技术预览",
"xpack.securitySolution.entityAnalytics.totalLabel": "合计",
"xpack.securitySolution.entityAnalytics.usersRiskDashboard.title": "用户风险分数",
- "xpack.securitySolution.entityAnalytics.usersRiskDashboard.usersTableTooltip": "用户风险表不受时间范围影响。本表显示每个用户最新记录的风险分数。",
"xpack.securitySolution.event.module.linkToElasticEndpointSecurityDescription": "在 Endpoint Security 中打开",
"xpack.securitySolution.event.summary.threat_indicator.modal.allMatches": "所有指标匹配",
"xpack.securitySolution.event.summary.threat_indicator.modal.close": "关闭",
@@ -32770,10 +32776,8 @@
"xpack.securitySolution.hostsRiskTable.hostNameTitle": "主机名",
"xpack.securitySolution.hostsRiskTable.hostRiskScoreTitle": "主机风险分数",
"xpack.securitySolution.hostsRiskTable.hostRiskTitle": "主机风险",
- "xpack.securitySolution.hostsRiskTable.hostsTableTooltip": "主机风险表不受 KQL 时间范围影响。本表显示每台主机最新记录的风险分数。",
"xpack.securitySolution.hostsRiskTable.riskTitle": "主机风险分类",
"xpack.securitySolution.hostsRiskTable.tableTitle": "主机风险",
- "xpack.securitySolution.hostsRiskTable.usersTableTooltip": "用户风险表不受 KQL 时间范围影响。本表显示每个用户最新记录的风险分数。",
"xpack.securitySolution.hostsTable.firstLastSeenToolTip": "相对于选定日期范围",
"xpack.securitySolution.hostsTable.hostsTitle": "所有主机",
"xpack.securitySolution.hostsTable.lastSeenTitle": "最后看到时间",
diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts
index 74cc8a1951cb4..4bada627d2dff 100644
--- a/x-pack/test/functional/apps/infra/home_page.ts
+++ b/x-pack/test/functional/apps/infra/home_page.ts
@@ -210,6 +210,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await returnTo(INVENTORY_PATH);
});
});
+
+ it('Should show auto-refresh option', async () => {
+ const kibanaRefreshConfig = await pageObjects.timePicker.getRefreshConfig();
+ expect(kibanaRefreshConfig.interval).to.equal('5');
+ expect(kibanaRefreshConfig.units).to.equal('Seconds');
+ expect(kibanaRefreshConfig.isPaused).to.equal(true);
+ });
});
it('shows query suggestions', async () => {
diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts
index e8f7730522f42..fa9008bf5cc24 100644
--- a/x-pack/test/functional/apps/infra/hosts_view.ts
+++ b/x-pack/test/functional/apps/infra/hosts_view.ts
@@ -94,7 +94,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const kibanaServer = getService('kibanaServer');
const observability = getService('observability');
const retry = getService('retry');
- const security = getService('security');
const testSubjects = getService('testSubjects');
const pageObjects = getPageObjects([
'assetDetails',
@@ -111,47 +110,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const setHostViewEnabled = (value: boolean = true) =>
kibanaServer.uiSettings.update({ [enableInfrastructureHostsView]: value });
- const loginWithReadOnlyUser = async () => {
- const roleCreation = await security.role.create('global_hosts_read_privileges_role', {
- elasticsearch: {
- indices: [{ names: ['metricbeat-*'], privileges: ['read', 'view_index_metadata'] }],
- },
- kibana: [
- {
- feature: {
- infrastructure: ['read'],
- advancedSettings: ['read'],
- },
- spaces: ['*'],
- },
- ],
- });
-
- const userCreation = security.user.create('global_hosts_read_privileges_user', {
- password: 'global_hosts_read_privileges_user-password',
- roles: ['global_hosts_read_privileges_role'],
- full_name: 'test user',
- });
-
- await Promise.all([roleCreation, userCreation]);
-
- await pageObjects.security.forceLogout();
- await pageObjects.security.login(
- 'global_hosts_read_privileges_user',
- 'global_hosts_read_privileges_user-password',
- {
- expectSpaceSelector: false,
- }
- );
- };
-
- const logoutAndDeleteReadOnlyUser = () =>
- Promise.all([
- pageObjects.security.forceLogout(),
- security.role.delete('global_hosts_read_privileges_role'),
- security.user.delete('global_hosts_read_privileges_user'),
- ]);
-
const returnTo = async (path: string, timeout = 2000) =>
retry.waitForWithTimeout('returned to hosts view', timeout, async () => {
await browser.goBack();
@@ -200,65 +158,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(pageUrl).to.contain(HOSTS_VIEW_PATH);
});
- describe('#Landing page', () => {
- beforeEach(async () => {
- await setHostViewEnabled(false);
- });
-
- afterEach(async () => {
- await setHostViewEnabled(true);
- });
-
- describe('User with read permission', () => {
- beforeEach(async () => {
- await loginWithReadOnlyUser();
- await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
- await pageObjects.header.waitUntilLoadingHasFinished();
- });
-
- afterEach(async () => {
- await logoutAndDeleteReadOnlyUser();
- });
-
- it('Should show hosts landing page with callout when the hosts view is disabled', async () => {
- await pageObjects.infraHostsView.getBetaBadgeExists();
- const landingPageDisabled =
- await pageObjects.infraHostsView.getHostsLandingPageDisabled();
- const learnMoreDocsUrl = await pageObjects.infraHostsView.getHostsLandingPageDocsLink();
- const parsedUrl = new URL(learnMoreDocsUrl);
-
- expect(parsedUrl.host).to.be('www.elastic.co');
- expect(parsedUrl.pathname).to.be('/guide/en/kibana/current/kibana-privileges.html');
- expect(landingPageDisabled).to.contain(
- 'Your user role doesn’t have sufficient privileges to enable this feature'
- );
- });
- });
-
- describe('Admin user', () => {
- beforeEach(async () => {
- await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
- await pageObjects.header.waitUntilLoadingHasFinished();
- });
-
- it('as an admin, should see an enable button when the hosts view is disabled', async () => {
- const landingPageEnableButton =
- await pageObjects.infraHostsView.getHostsLandingPageEnableButton();
- const landingPageEnableButtonText = await landingPageEnableButton.getVisibleText();
- expect(landingPageEnableButtonText).to.eql('Enable hosts view');
- });
-
- it('as an admin, should be able to enable the hosts view feature', async () => {
- await pageObjects.infraHostsView.clickEnableHostViewButton();
-
- const titleElement = await find.byCssSelector('h1');
- const title = await titleElement.getVisibleText();
-
- expect(title).to.contain('Hosts');
- });
- });
- });
-
describe('#Single Host Flyout', () => {
before(async () => {
await setHostViewEnabled(true);
diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts
index 52da33a14c5ac..6dd953a84e4d0 100644
--- a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts
+++ b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts
@@ -89,6 +89,11 @@ export default function ({ getService }: FtrProviderContext) {
isDependentVariableInput: true,
},
],
+ advancedEditorContent: [
+ '{',
+ ` "description": "Classification job based on 'ft_bank_marketing' dataset with dependentVariable 'y' and trainingPercent '20'",`,
+ ' "source": {',
+ ],
expected: {
rocCurveColorState: [
// tick/grid/axis
@@ -321,6 +326,14 @@ export default function ({ getService }: FtrProviderContext) {
// - ⚠ Analysis fields
await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(4);
+ // switch to json editor and back
+ await ml.testExecution.logTestStep('switches to advanced editor then back to form');
+ await ml.dataFrameAnalyticsCreation.openAdvancedEditor();
+ await ml.dataFrameAnalyticsCreation.assertAdvancedEditorCodeEditorContent(
+ testData.advancedEditorContent
+ );
+ await ml.dataFrameAnalyticsCreation.closeAdvancedEditor();
+
await ml.testExecution.logTestStep('continues to the create step');
await ml.dataFrameAnalyticsCreation.continueToCreateStep();
diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts
index e7a14abbebb65..8b4514add92cb 100644
--- a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts
+++ b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts
@@ -84,6 +84,11 @@ export default function ({ getService }: FtrProviderContext) {
},
modelMemory: '5mb',
createIndexPattern: true,
+ advancedEditorContent: [
+ '{',
+ ' "description": "Outlier detection job based on ft_ihp_outlier dataset with runtime fields",',
+ ' "source": {',
+ ],
expected: {
histogramCharts: [
{ chartAvailable: true, id: '1stFlrSF', legend: '334 - 4692' },
@@ -307,6 +312,14 @@ export default function ({ getService }: FtrProviderContext) {
await ml.dataFrameAnalyticsCreation.assertValidationCalloutsExists();
await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(1);
+ // switch to json editor and back
+ await ml.testExecution.logTestStep('switches to advanced editor then back to form');
+ await ml.dataFrameAnalyticsCreation.openAdvancedEditor();
+ await ml.dataFrameAnalyticsCreation.assertAdvancedEditorCodeEditorContent(
+ testData.advancedEditorContent
+ );
+ await ml.dataFrameAnalyticsCreation.closeAdvancedEditor();
+
await ml.testExecution.logTestStep('continues to the create step');
await ml.dataFrameAnalyticsCreation.continueToCreateStep();
diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts
index fe4010264c621..b4ed75c35043a 100644
--- a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts
+++ b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts
@@ -91,6 +91,11 @@ export default function ({ getService }: FtrProviderContext) {
trainingPercent: 20,
modelMemory: '20mb',
createIndexPattern: true,
+ advancedEditorContent: [
+ '{',
+ ' "description": "Regression job based on ft_egs_regression dataset with runtime fields",',
+ ' "source": {',
+ ],
expected: {
scatterplotMatrixColorStats: [
// some marker colors of the continuous color scale
@@ -322,6 +327,14 @@ export default function ({ getService }: FtrProviderContext) {
await ml.dataFrameAnalyticsCreation.assertValidationCalloutsExists();
await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(3);
+ // switch to json editor and back
+ await ml.testExecution.logTestStep('switches to advanced editor then back to form');
+ await ml.dataFrameAnalyticsCreation.openAdvancedEditor();
+ await ml.dataFrameAnalyticsCreation.assertAdvancedEditorCodeEditorContent(
+ testData.advancedEditorContent
+ );
+ await ml.dataFrameAnalyticsCreation.closeAdvancedEditor();
+
await ml.testExecution.logTestStep('continues to the create step');
await ml.dataFrameAnalyticsCreation.continueToCreateStep();
diff --git a/x-pack/test/functional/apps/transform/edit_clone/cloning.ts b/x-pack/test/functional/apps/transform/edit_clone/cloning.ts
index 0ec4ef0b67b9e..caa6552024e14 100644
--- a/x-pack/test/functional/apps/transform/edit_clone/cloning.ts
+++ b/x-pack/test/functional/apps/transform/edit_clone/cloning.ts
@@ -190,7 +190,7 @@ export default function ({ getService }: FtrProviderContext) {
const transform = getService('transform');
// Failing: See https://github.com/elastic/kibana/issues/165883
- describe.skip('cloning', function () {
+ describe('cloning', function () {
const transformConfigWithPivot = getTransformConfig();
const transformConfigWithRuntimeMapping = getTransformConfigWithRuntimeMappings();
const transformConfigWithBoolFilterAgg = getTransformConfigWithBoolFilterAgg();
diff --git a/x-pack/test/functional/page_objects/infra_hosts_view.ts b/x-pack/test/functional/page_objects/infra_hosts_view.ts
index 83628e1eae02a..3d37fc4da913f 100644
--- a/x-pack/test/functional/page_objects/infra_hosts_view.ts
+++ b/x-pack/test/functional/page_objects/infra_hosts_view.ts
@@ -46,28 +46,6 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
return await testSubjects.click('inventory-hostsView-link-badge');
},
- // Splash screen
-
- async getHostsLandingPageDisabled() {
- const container = await testSubjects.find('hostView-no-enable-access');
- const containerText = await container.getVisibleText();
- return containerText;
- },
-
- async getHostsLandingPageDocsLink() {
- const container = await testSubjects.find('hostsView-docs-link');
- const containerText = await container.getAttribute('href');
- return containerText;
- },
-
- async getHostsLandingPageEnableButton() {
- return testSubjects.find('hostsView-enable-feature-button');
- },
-
- async clickEnableHostViewButton() {
- return testSubjects.click('hostsView-enable-feature-button');
- },
-
// Table
async getHostsTable() {
diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts
index 43bb799a5a759..beedbb145dce4 100644
--- a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts
+++ b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts
@@ -54,8 +54,40 @@ export function MachineLearningDataFrameAnalyticsCreationProvider(
await headerPage.waitUntilLoadingHasFinished();
},
+ async assertAdvancedEditorCodeEditorExists() {
+ await testSubjects.existOrFail('mlAnalyticsCreateJobWizardAdvancedEditorCodeEditor', {
+ allowHidden: true,
+ });
+ },
+
+ async assertAdvancedEditorCodeEditorContent(expectedContent: string[]) {
+ await this.assertAdvancedEditorCodeEditorExists();
+ const wrapper = await testSubjects.find('mlAnalyticsCreateJobWizardAdvancedEditorCodeEditor');
+ const editor = await wrapper.findByCssSelector('.monaco-editor .view-lines');
+ const editorContentString = await editor.getVisibleText();
+ const splicedAdvancedEditorValue = editorContentString.split('\n').splice(0, 3);
+ expect(splicedAdvancedEditorValue).to.eql(
+ expectedContent,
+ `Expected the first editor lines to be '${expectedContent}' (got '${splicedAdvancedEditorValue}')`
+ );
+ },
+
+ async openAdvancedEditor() {
+ this.assertAdvancedEditorSwitchExists();
+ await testSubjects.click('mlAnalyticsCreateJobWizardAdvancedEditorSwitch');
+ this.assertAdvancedEditorSwitchCheckState(true);
+ this.assertAdvancedEditorCodeEditorExists();
+ },
+
+ async closeAdvancedEditor() {
+ this.assertAdvancedEditorSwitchExists();
+ await testSubjects.click('mlAnalyticsCreateJobWizardAdvancedEditorSwitch');
+ this.assertAdvancedEditorSwitchCheckState(false);
+ await testSubjects.missingOrFail('mlAnalyticsCreateJobWizardAdvancedEditorCodeEditor');
+ },
+
async assertAdvancedEditorSwitchExists() {
- await testSubjects.existOrFail(`mlAnalyticsCreateJobWizardAdvancedEditorSwitch`, {
+ await testSubjects.existOrFail('mlAnalyticsCreateJobWizardAdvancedEditorSwitch', {
allowHidden: true,
});
},
diff --git a/x-pack/test/functional/services/transform/transform_table.ts b/x-pack/test/functional/services/transform/transform_table.ts
index 2af0d129ed51c..665b04b058106 100644
--- a/x-pack/test/functional/services/transform/transform_table.ts
+++ b/x-pack/test/functional/services/transform/transform_table.ts
@@ -7,6 +7,8 @@
import expect from '@kbn/expect';
+import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper';
+
import { FtrProviderContext } from '../../ftr_provider_context';
type TransformRowActionName =
@@ -19,10 +21,11 @@ type TransformRowActionName =
| 'Stop'
| 'Reauthorize';
-export function TransformTableProvider({ getService }: FtrProviderContext) {
+export function TransformTableProvider({ getPageObject, getService }: FtrProviderContext) {
const find = getService('find');
const retry = getService('retry');
const testSubjects = getService('testSubjects');
+ const commonPage = getPageObject('common');
const browser = getService('browser');
const ml = getService('ml');
@@ -89,20 +92,47 @@ export function TransformTableProvider({ getService }: FtrProviderContext) {
await this.waitForRefreshButtonLoaded();
await testSubjects.click('~transformRefreshTransformListButton');
await this.waitForRefreshButtonLoaded();
- await this.waitForTransformsToLoad();
+ await this.waitForTransformsTableToLoad();
+ }
+
+ public async waitForTransformsTableToStartLoading() {
+ await testSubjects.existOrFail(`~transformListTable`, { timeout: 60 * 1000 });
+
+ // After invoking an action that caused the table to start loading, the loading
+ // should start quickly after the table exists. Sometimes it is even so quick that
+ // the loading is already done when we try to check for it, so we're not failing
+ // in that case and just move on.
+ await testSubjects.exists(`transformListTable loading`, { timeout: 3 * 1000 });
}
- public async waitForTransformsToLoad() {
+ public async waitForTransformsTableToLoad() {
await testSubjects.existOrFail('~transformListTable', { timeout: 60 * 1000 });
await testSubjects.existOrFail('transformListTable loaded', { timeout: 30 * 1000 });
}
- public async filterWithSearchString(filter: string, expectedRowCount: number = 1) {
- await this.waitForTransformsToLoad();
+ async getSearchInput(): Promise {
const tableListContainer = await testSubjects.find('transformListTableContainer');
- const searchBarInput = await tableListContainer.findByClassName('euiFieldSearch');
+ return await tableListContainer.findByClassName('euiFieldSearch');
+ }
+
+ public async assertSearchInputValue(expectedSearchValue: string) {
+ const searchBarInput = await this.getSearchInput();
+ const actualSearchValue = await searchBarInput.getAttribute('value');
+ expect(actualSearchValue).to.eql(
+ expectedSearchValue,
+ `Search input value should be '${expectedSearchValue}' (got '${actualSearchValue}')`
+ );
+ }
+
+ public async filterWithSearchString(filter: string, expectedRowCount: number = 1) {
+ await this.waitForTransformsTableToLoad();
+ const searchBarInput = await this.getSearchInput();
await searchBarInput.clearValueWithKeyboard();
await searchBarInput.type(filter);
+ await commonPage.pressEnterKey();
+ await this.assertSearchInputValue(filter);
+ await this.waitForTransformsTableToStartLoading();
+ await this.waitForTransformsTableToLoad();
const rows = await this.parseTransformTable();
const filteredRows = rows.filter((row) => row.id === filter);
@@ -113,7 +143,7 @@ export function TransformTableProvider({ getService }: FtrProviderContext) {
}
public async clearSearchString(expectedRowCount: number = 1) {
- await this.waitForTransformsToLoad();
+ await this.waitForTransformsTableToLoad();
const tableListContainer = await testSubjects.find('transformListTableContainer');
const searchBarInput = await tableListContainer.findByClassName('euiFieldSearch');
await searchBarInput.clearValueWithKeyboard();
diff --git a/x-pack/test/osquery_cypress/artifact_manager.ts b/x-pack/test/osquery_cypress/artifact_manager.ts
index 0f5ca38d74978..54b9a70d37aff 100644
--- a/x-pack/test/osquery_cypress/artifact_manager.ts
+++ b/x-pack/test/osquery_cypress/artifact_manager.ts
@@ -6,6 +6,5 @@
*/
export async function getLatestVersion(): Promise {
- // temporary solution until newer agents work fine with Docker
- return '8.10.4';
+ return '8.11.0-SNAPSHOT';
}
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts
index 02a77d227a4c5..f14ced2ea02cf 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts
@@ -53,89 +53,83 @@ const EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item';
const NON_EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item with future expiration';
-// TODO: https://github.com/elastic/kibana/issues/161540
-// Flaky on serverless
-describe(
- 'Detection rules, bulk duplicate',
- { tags: ['@ess', '@serverless', '@skipInServerless'] },
- () => {
- before(() => {
- cleanKibana();
+describe('Detection rules, bulk duplicate', { tags: ['@ess', '@serverless'] }, () => {
+ before(() => {
+ cleanKibana();
+ });
+
+ beforeEach(() => {
+ login();
+ // Make sure persisted rules table state is cleared
+ resetRulesTableState();
+ deleteAlertsAndRules();
+ cy.task('esArchiverResetKibana');
+ createRule(
+ getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false })
+ ).then((response) => {
+ createRuleExceptionItem(response.body.id, [
+ {
+ description: 'Exception item for rule default exception list',
+ entries: [
+ {
+ field: 'user.name',
+ operator: 'included',
+ type: 'match',
+ value: 'some value',
+ },
+ ],
+ name: EXPIRED_EXCEPTION_ITEM_NAME,
+ type: 'simple',
+ expire_time: expiredDate,
+ },
+ {
+ description: 'Exception item for rule default exception list',
+ entries: [
+ {
+ field: 'user.name',
+ operator: 'included',
+ type: 'match',
+ value: 'some value',
+ },
+ ],
+ name: NON_EXPIRED_EXCEPTION_ITEM_NAME,
+ type: 'simple',
+ expire_time: futureDate,
+ },
+ ]);
});
- beforeEach(() => {
- login();
- // Make sure persisted rules table state is cleared
- resetRulesTableState();
- deleteAlertsAndRules();
- cy.task('esArchiverResetKibana');
- createRule(
- getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false })
- ).then((response) => {
- createRuleExceptionItem(response.body.id, [
- {
- description: 'Exception item for rule default exception list',
- entries: [
- {
- field: 'user.name',
- operator: 'included',
- type: 'match',
- value: 'some value',
- },
- ],
- name: EXPIRED_EXCEPTION_ITEM_NAME,
- type: 'simple',
- expire_time: expiredDate,
- },
- {
- description: 'Exception item for rule default exception list',
- entries: [
- {
- field: 'user.name',
- operator: 'included',
- type: 'match',
- value: 'some value',
- },
- ],
- name: NON_EXPIRED_EXCEPTION_ITEM_NAME,
- type: 'simple',
- expire_time: futureDate,
- },
- ]);
- });
-
- visitRulesManagementTable();
- disableAutoRefresh();
- });
+ visitRulesManagementTable();
+ disableAutoRefresh();
+ });
+
+ it('Duplicates rules', () => {
+ selectAllRules();
+ duplicateSelectedRulesWithoutExceptions();
+ expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
+ });
- it('Duplicates rules', () => {
+ describe('With exceptions', () => {
+ it('Duplicates rules with expired exceptions', () => {
selectAllRules();
- duplicateSelectedRulesWithoutExceptions();
+ duplicateSelectedRulesWithExceptions();
expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
+ goToRuleDetailsOf(`${RULE_NAME} [Duplicate]`);
+ goToExceptionsTab();
+ assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]);
+ viewExpiredExceptionItems();
+ assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [EXPIRED_EXCEPTION_ITEM_NAME]);
});
- describe('With exceptions', () => {
- it('Duplicates rules with expired exceptions', () => {
- selectAllRules();
- duplicateSelectedRulesWithExceptions();
- expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
- goToRuleDetailsOf(`${RULE_NAME} [Duplicate]`);
- goToExceptionsTab();
- assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]);
- viewExpiredExceptionItems();
- assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [EXPIRED_EXCEPTION_ITEM_NAME]);
- });
-
- it('Duplicates rules with exceptions, excluding expired exceptions', () => {
- selectAllRules();
- duplicateSelectedRulesWithNonExpiredExceptions();
- expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
- goToRuleDetailsOf(`${RULE_NAME} [Duplicate]`);
- goToExceptionsTab();
- assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]);
- viewExpiredExceptionItems();
- assertNumberOfExceptionItemsExists(0);
- });
+ it('Duplicates rules with exceptions, excluding expired exceptions', () => {
+ selectAllRules();
+ duplicateSelectedRulesWithNonExpiredExceptions();
+ expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
+ goToRuleDetailsOf(`${RULE_NAME} [Duplicate]`);
+ goToExceptionsTab();
+ assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]);
+ viewExpiredExceptionItems();
+ assertNumberOfExceptionItemsExists(0);
});
- }
-);
+ });
+});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts
index 8d551b655fca4..74448f32dcf5e 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts
@@ -117,563 +117,558 @@ const defaultRuleData = {
timeline_id: '495ad7a7-316e-4544-8a0f-9c098daee76e',
};
-// TODO: https://github.com/elastic/kibana/issues/161540
-describe(
- 'Detection rules, bulk edit',
- { tags: ['@ess', '@serverless', '@brokenInServerless'] },
- () => {
- before(() => {
- cleanKibana();
- });
- beforeEach(() => {
- login();
- // Make sure persisted rules table state is cleared
- resetRulesTableState();
- deleteAlertsAndRules();
- preventPrebuiltRulesPackageInstallation(); // Make sure prebuilt rules aren't pulled from Fleet API
- cy.task('esArchiverResetKibana');
- createRule(getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false }));
- createRule(
- getEqlRule({ ...defaultRuleData, rule_id: '2', name: 'New EQL Rule', enabled: false })
- );
- createRule(
- getMachineLearningRule({
- name: 'New ML Rule Test',
- tags: ['test-default-tag-1', 'test-default-tag-2'],
- enabled: false,
- })
- );
- createRule(
- getNewThreatIndicatorRule({
- ...defaultRuleData,
- rule_id: '4',
- name: 'Threat Indicator Rule Test',
- enabled: false,
- })
- );
- createRule(
- getNewThresholdRule({
- ...defaultRuleData,
- rule_id: '5',
- name: 'Threshold Rule',
- enabled: false,
- })
- );
- createRule(
- getNewTermsRule({
- ...defaultRuleData,
- rule_id: '6',
- name: 'New Terms Rule',
- enabled: false,
- })
- );
-
- visitRulesManagementTable();
- disableAutoRefresh();
- });
-
- describe('Prerequisites', () => {
- const PREBUILT_RULES = [
- createRuleAssetSavedObject({
- name: 'Prebuilt rule 1',
- rule_id: 'rule_1',
- }),
- createRuleAssetSavedObject({
- name: 'Prebuilt rule 2',
- rule_id: 'rule_2',
- }),
- ];
-
- it('No rules selected', () => {
- openBulkActionsMenu();
-
- // when no rule selected all bulk edit options should be disabled
- cy.get(TAGS_RULE_BULK_MENU_ITEM).should('be.disabled');
- cy.get(INDEX_PATTERNS_RULE_BULK_MENU_ITEM).should('be.disabled');
- cy.get(APPLY_TIMELINE_RULE_BULK_MENU_ITEM).should('be.disabled');
- });
-
- it('Only prebuilt rules selected', () => {
- createAndInstallMockedPrebuiltRules(PREBUILT_RULES);
-
- // select Elastic(prebuilt) rules, check if we can't proceed further, as Elastic rules are not editable
- filterByElasticRules();
- selectAllRulesOnPage();
- clickApplyTimelineTemplatesMenuItem();
-
- getRulesManagementTableRows().then((rows) => {
- // check modal window for Elastic rule that can't be edited
- checkPrebuiltRulesCannotBeModified(rows.length);
-
- // the confirm button closes modal
- cy.get(MODAL_CONFIRMATION_BTN).should('have.text', 'Close').click();
- cy.get(MODAL_CONFIRMATION_BODY).should('not.exist');
- });
- });
+describe('Detection rules, bulk edit', { tags: ['@ess', '@serverless'] }, () => {
+ before(() => {
+ cleanKibana();
+ });
+ beforeEach(() => {
+ login();
+ // Make sure persisted rules table state is cleared
+ resetRulesTableState();
+ deleteAlertsAndRules();
+ preventPrebuiltRulesPackageInstallation(); // Make sure prebuilt rules aren't pulled from Fleet API
+ cy.task('esArchiverResetKibana');
+ createRule(getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false }));
+ createRule(
+ getEqlRule({ ...defaultRuleData, rule_id: '2', name: 'New EQL Rule', enabled: false })
+ );
+ createRule(
+ getMachineLearningRule({
+ name: 'New ML Rule Test',
+ tags: ['test-default-tag-1', 'test-default-tag-2'],
+ enabled: false,
+ })
+ );
+ createRule(
+ getNewThreatIndicatorRule({
+ ...defaultRuleData,
+ rule_id: '4',
+ name: 'Threat Indicator Rule Test',
+ enabled: false,
+ })
+ );
+ createRule(
+ getNewThresholdRule({
+ ...defaultRuleData,
+ rule_id: '5',
+ name: 'Threshold Rule',
+ enabled: false,
+ })
+ );
+ createRule(
+ getNewTermsRule({
+ ...defaultRuleData,
+ rule_id: '6',
+ name: 'New Terms Rule',
+ enabled: false,
+ })
+ );
- it('Prebuilt and custom rules selected: user proceeds with custom rules editing', () => {
- getRulesManagementTableRows().then((existedRulesRows) => {
- createAndInstallMockedPrebuiltRules(PREBUILT_RULES);
+ visitRulesManagementTable();
+ disableAutoRefresh();
+ });
- // modal window should show how many rules can be edit, how many not
- selectAllRules();
- clickAddTagsMenuItem();
+ describe('Prerequisites', () => {
+ const PREBUILT_RULES = [
+ createRuleAssetSavedObject({
+ name: 'Prebuilt rule 1',
+ rule_id: 'rule_1',
+ }),
+ createRuleAssetSavedObject({
+ name: 'Prebuilt rule 2',
+ rule_id: 'rule_2',
+ }),
+ ];
+
+ it('No rules selected', () => {
+ openBulkActionsMenu();
+
+ // when no rule selected all bulk edit options should be disabled
+ cy.get(TAGS_RULE_BULK_MENU_ITEM).should('be.disabled');
+ cy.get(INDEX_PATTERNS_RULE_BULK_MENU_ITEM).should('be.disabled');
+ cy.get(APPLY_TIMELINE_RULE_BULK_MENU_ITEM).should('be.disabled');
+ });
- waitForMixedRulesBulkEditModal(existedRulesRows.length);
+ it('Only prebuilt rules selected', () => {
+ createAndInstallMockedPrebuiltRules(PREBUILT_RULES);
- getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
- checkPrebuiltRulesCannotBeModified(availablePrebuiltRulesCount);
- });
+ // select Elastic(prebuilt) rules, check if we can't proceed further, as Elastic rules are not editable
+ filterByElasticRules();
+ selectAllRulesOnPage();
+ clickApplyTimelineTemplatesMenuItem();
- // user can proceed with custom rule editing
- cy.get(MODAL_CONFIRMATION_BTN)
- .should('have.text', `Edit ${existedRulesRows.length} custom rules`)
- .click();
+ getRulesManagementTableRows().then((rows) => {
+ // check modal window for Elastic rule that can't be edited
+ checkPrebuiltRulesCannotBeModified(rows.length);
- // action should finish
- typeTags(['test-tag']);
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: existedRulesRows.length });
- });
+ // the confirm button closes modal
+ cy.get(MODAL_CONFIRMATION_BTN).should('have.text', 'Close').click();
+ cy.get(MODAL_CONFIRMATION_BODY).should('not.exist');
});
+ });
- it('Prebuilt and custom rules selected: user cancels action', () => {
+ it('Prebuilt and custom rules selected: user proceeds with custom rules editing', () => {
+ getRulesManagementTableRows().then((existedRulesRows) => {
createAndInstallMockedPrebuiltRules(PREBUILT_RULES);
- getRulesManagementTableRows().then((rows) => {
- // modal window should show how many rules can be edit, how many not
- selectAllRules();
- clickAddTagsMenuItem();
- waitForMixedRulesBulkEditModal(rows.length);
+ // modal window should show how many rules can be edit, how many not
+ selectAllRules();
+ clickAddTagsMenuItem();
- checkPrebuiltRulesCannotBeModified(PREBUILT_RULES.length);
+ waitForMixedRulesBulkEditModal(existedRulesRows.length);
- // user cancels action and modal disappears
- cancelConfirmationModal();
+ getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
+ checkPrebuiltRulesCannotBeModified(availablePrebuiltRulesCount);
});
- });
- it('should not lose rules selection after edit action', () => {
- const rulesToUpdate = [RULE_NAME, 'New EQL Rule', 'New Terms Rule'] as const;
- // Switch to 5 rules per page, to have few pages in pagination(ideal way to test auto refresh and selection of few items)
- setRowsPerPageTo(5);
- // and make the rules order isn't changing (set sorting by rule name) over time if rules are run
- sortByTableColumn('Rule');
- selectRulesByName(rulesToUpdate);
+ // user can proceed with custom rule editing
+ cy.get(MODAL_CONFIRMATION_BTN)
+ .should('have.text', `Edit ${existedRulesRows.length} custom rules`)
+ .click();
- // open add tags form and add 2 new tags
- openBulkEditAddTagsForm();
- typeTags(['new-tag-1']);
+ // action should finish
+ typeTags(['test-tag']);
submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rulesToUpdate.length });
-
- testMultipleSelectedRulesLabel(rulesToUpdate.length);
- // check if first four(rulesCount) rules still selected and tags are updated
- for (const ruleName of rulesToUpdate) {
- getRuleRow(ruleName).find(EUI_CHECKBOX).should('be.checked');
- getRuleRow(ruleName)
- .find(RULES_TAGS_POPOVER_BTN)
- .each(($el) => {
- testTagsBadge($el, prePopulatedTags.concat(['new-tag-1']));
- });
- }
+ waitForBulkEditActionToFinish({ updatedCount: existedRulesRows.length });
});
});
- describe('Tags actions', () => {
- it('Display list of tags in tags select', () => {
+ it('Prebuilt and custom rules selected: user cancels action', () => {
+ createAndInstallMockedPrebuiltRules(PREBUILT_RULES);
+
+ getRulesManagementTableRows().then((rows) => {
+ // modal window should show how many rules can be edit, how many not
selectAllRules();
+ clickAddTagsMenuItem();
+ waitForMixedRulesBulkEditModal(rows.length);
- openBulkEditAddTagsForm();
- openTagsSelect();
+ checkPrebuiltRulesCannotBeModified(PREBUILT_RULES.length);
- cy.get(EUI_FILTER_SELECT_ITEM)
- .should('have.length', prePopulatedTags.length)
- .each(($el, index) => {
- cy.wrap($el).should('have.text', prePopulatedTags[index]);
- });
+ // user cancels action and modal disappears
+ cancelConfirmationModal();
});
+ });
- it('Add tags to custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
- const resultingTags = [...prePopulatedTags, ...tagsToBeAdded];
-
- // check if only pre-populated tags exist in the tags filter
- checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
-
- selectAllRules();
+ it('should not lose rules selection after edit action', () => {
+ const rulesToUpdate = [RULE_NAME, 'New EQL Rule', 'New Terms Rule'] as const;
+ // Switch to 5 rules per page, to have few pages in pagination(ideal way to test auto refresh and selection of few items)
+ setRowsPerPageTo(5);
+ // and make the rules order isn't changing (set sorting by rule name) over time if rules are run
+ sortByTableColumn('Rule');
+ selectRulesByName(rulesToUpdate);
+
+ // open add tags form and add 2 new tags
+ openBulkEditAddTagsForm();
+ typeTags(['new-tag-1']);
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rulesToUpdate.length });
+
+ testMultipleSelectedRulesLabel(rulesToUpdate.length);
+ // check if first four(rulesCount) rules still selected and tags are updated
+ for (const ruleName of rulesToUpdate) {
+ getRuleRow(ruleName).find(EUI_CHECKBOX).should('be.checked');
+ getRuleRow(ruleName)
+ .find(RULES_TAGS_POPOVER_BTN)
+ .each(($el) => {
+ testTagsBadge($el, prePopulatedTags.concat(['new-tag-1']));
+ });
+ }
+ });
+ });
- // open add tags form and add 2 new tags
- openBulkEditAddTagsForm();
- typeTags(tagsToBeAdded);
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ describe('Tags actions', () => {
+ it('Display list of tags in tags select', () => {
+ selectAllRules();
- // check if all rules have been updated with new tags
- testAllTagsBadges(resultingTags);
+ openBulkEditAddTagsForm();
+ openTagsSelect();
- // check that new tags were added to tags filter
- // tags in tags filter sorted alphabetically
- const resultingTagsInFilter = [...resultingTags].sort();
- checkTagsInTagsFilter(resultingTagsInFilter, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
+ cy.get(EUI_FILTER_SELECT_ITEM)
+ .should('have.length', prePopulatedTags.length)
+ .each(($el, index) => {
+ cy.wrap($el).should('have.text', prePopulatedTags[index]);
});
- });
+ });
- it('Display success toast after adding tags', () => {
- getRulesManagementTableRows().then((rows) => {
- const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
+ it('Add tags to custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
+ const resultingTags = [...prePopulatedTags, ...tagsToBeAdded];
- // check if only pre-populated tags exist in the tags filter
- checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
+ // check if only pre-populated tags exist in the tags filter
+ checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
- selectAllRules();
+ selectAllRules();
- // open add tags form and add 2 new tags
- openBulkEditAddTagsForm();
- typeTags(tagsToBeAdded);
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
- });
- });
+ // open add tags form and add 2 new tags
+ openBulkEditAddTagsForm();
+ typeTags(tagsToBeAdded);
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
- it('Overwrite tags in custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- const tagsToOverwrite = ['overwrite-tag-1'];
+ // check if all rules have been updated with new tags
+ testAllTagsBadges(resultingTags);
- // check if only pre-populated tags exist in the tags filter
- checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
+ // check that new tags were added to tags filter
+ // tags in tags filter sorted alphabetically
+ const resultingTagsInFilter = [...resultingTags].sort();
+ checkTagsInTagsFilter(resultingTagsInFilter, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
+ });
+ });
- selectAllRules();
+ it('Display success toast after adding tags', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
- // open add tags form, check overwrite tags and warning message, type tags
- openBulkEditAddTagsForm();
- checkOverwriteTagsCheckbox();
+ // check if only pre-populated tags exist in the tags filter
+ checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
- cy.get(RULES_BULK_EDIT_TAGS_WARNING).should(
- 'have.text',
- `You’re about to overwrite tags for ${rows.length} selected rules, press Save to apply changes.`
- );
+ selectAllRules();
- typeTags(tagsToOverwrite);
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ // open add tags form and add 2 new tags
+ openBulkEditAddTagsForm();
+ typeTags(tagsToBeAdded);
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ });
+ });
- // check if all rules have been updated with new tags
- testAllTagsBadges(tagsToOverwrite);
+ it('Overwrite tags in custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const tagsToOverwrite = ['overwrite-tag-1'];
- // check that only new tags are in the tag filter
- checkTagsInTagsFilter(tagsToOverwrite, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
- });
- });
+ // check if only pre-populated tags exist in the tags filter
+ checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
- it('Delete tags from custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- const tagsToDelete = prePopulatedTags.slice(0, 1);
- const resultingTags = prePopulatedTags.slice(1);
+ selectAllRules();
- // check if only pre-populated tags exist in the tags filter
- checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
+ // open add tags form, check overwrite tags and warning message, type tags
+ openBulkEditAddTagsForm();
+ checkOverwriteTagsCheckbox();
- selectAllRules();
+ cy.get(RULES_BULK_EDIT_TAGS_WARNING).should(
+ 'have.text',
+ `You’re about to overwrite tags for ${rows.length} selected rules, press Save to apply changes.`
+ );
- // open add tags form, check overwrite tags, type tags
- openBulkEditDeleteTagsForm();
- typeTags(tagsToDelete);
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ typeTags(tagsToOverwrite);
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
- // check tags has been removed from all rules
- testAllTagsBadges(resultingTags);
+ // check if all rules have been updated with new tags
+ testAllTagsBadges(tagsToOverwrite);
- // check that tags were removed from the tag filter
- checkTagsInTagsFilter(resultingTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
- });
+ // check that only new tags are in the tag filter
+ checkTagsInTagsFilter(tagsToOverwrite, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
});
});
- describe('Index patterns', () => {
- it('Index pattern action applied to custom rules, including machine learning: user proceeds with edit of custom non machine learning rule', () => {
- getRulesManagementTableRows().then((rows) => {
- const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
- const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
+ it('Delete tags from custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const tagsToDelete = prePopulatedTags.slice(0, 1);
+ const resultingTags = prePopulatedTags.slice(1);
- selectAllRules();
- clickAddIndexPatternsMenuItem();
+ // check if only pre-populated tags exist in the tags filter
+ checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
- // confirm editing custom rules, that are not Machine Learning
- checkMachineLearningRulesCannotBeModified(expectedNumberOfMachineLearningRulesToBeEdited);
- cy.get(MODAL_CONFIRMATION_BTN).click();
+ selectAllRules();
- typeIndexPatterns(indexPattersToBeAdded);
- submitBulkEditForm();
+ // open add tags form, check overwrite tags, type tags
+ openBulkEditDeleteTagsForm();
+ typeTags(tagsToDelete);
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
- waitForBulkEditActionToFinish({
- updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
- });
+ // check tags has been removed from all rules
+ testAllTagsBadges(resultingTags);
- // check if rule has been updated
- goToRuleDetailsOf(RULE_NAME);
- hasIndexPatterns(resultingIndexPatterns.join(''));
- });
+ // check that tags were removed from the tag filter
+ checkTagsInTagsFilter(resultingTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
});
+ });
+ });
+
+ describe('Index patterns', () => {
+ it('Index pattern action applied to custom rules, including machine learning: user proceeds with edit of custom non machine learning rule', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
+ const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
- it('Index pattern action applied to custom rules, including machine learning: user cancels action', () => {
selectAllRules();
clickAddIndexPatternsMenuItem();
// confirm editing custom rules, that are not Machine Learning
checkMachineLearningRulesCannotBeModified(expectedNumberOfMachineLearningRulesToBeEdited);
+ cy.get(MODAL_CONFIRMATION_BTN).click();
- // user cancels action and modal disappears
- cancelConfirmationModal();
- });
-
- it('Add index patterns to custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
- const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
-
- // select only rules that are not ML
- selectRulesByName([
- RULE_NAME,
- 'New EQL Rule',
- 'Threat Indicator Rule Test',
- 'Threshold Rule',
- 'New Terms Rule',
- ]);
-
- openBulkEditAddIndexPatternsForm();
- typeIndexPatterns(indexPattersToBeAdded);
- submitBulkEditForm();
-
- waitForBulkEditActionToFinish({
- updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
- });
+ typeIndexPatterns(indexPattersToBeAdded);
+ submitBulkEditForm();
- // check if rule has been updated
- goToRuleDetailsOf(RULE_NAME);
- hasIndexPatterns(resultingIndexPatterns.join(''));
+ waitForBulkEditActionToFinish({
+ updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
});
- });
- it('Display success toast after editing the index pattern', () => {
- getRulesManagementTableRows().then((rows) => {
- const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
-
- // select only rules that are not ML
- selectRulesByName([
- RULE_NAME,
- 'New EQL Rule',
- 'Threat Indicator Rule Test',
- 'Threshold Rule',
- 'New Terms Rule',
- ]);
-
- openBulkEditAddIndexPatternsForm();
- typeIndexPatterns(indexPattersToBeAdded);
- submitBulkEditForm();
-
- waitForBulkEditActionToFinish({
- updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
- });
- });
+ // check if rule has been updated
+ goToRuleDetailsOf(RULE_NAME);
+ hasIndexPatterns(resultingIndexPatterns.join(''));
});
+ });
+
+ it('Index pattern action applied to custom rules, including machine learning: user cancels action', () => {
+ selectAllRules();
+ clickAddIndexPatternsMenuItem();
+
+ // confirm editing custom rules, that are not Machine Learning
+ checkMachineLearningRulesCannotBeModified(expectedNumberOfMachineLearningRulesToBeEdited);
+
+ // user cancels action and modal disappears
+ cancelConfirmationModal();
+ });
- it('Overwrite index patterns in custom rules', () => {
- const rulesToSelect = [
+ it('Add index patterns to custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
+ const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
+
+ // select only rules that are not ML
+ selectRulesByName([
RULE_NAME,
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
- ] as const;
- const indexPattersToWrite = ['index-to-write-1-*', 'index-to-write-2-*'];
-
- // select only rules that are not ML
- selectRulesByName(rulesToSelect);
+ ]);
openBulkEditAddIndexPatternsForm();
-
- // check overwrite index patterns checkbox, ensure warning message is displayed and type index patterns
- checkOverwriteIndexPatternsCheckbox();
- cy.get(RULES_BULK_EDIT_INDEX_PATTERNS_WARNING).should(
- 'have.text',
- `You’re about to overwrite index patterns for ${rulesToSelect.length} selected rules, press Save to apply changes.`
- );
-
- typeIndexPatterns(indexPattersToWrite);
+ typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
+ waitForBulkEditActionToFinish({
+ updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
+ });
// check if rule has been updated
goToRuleDetailsOf(RULE_NAME);
- hasIndexPatterns(indexPattersToWrite.join(''));
+ hasIndexPatterns(resultingIndexPatterns.join(''));
});
+ });
+
+ it('Display success toast after editing the index pattern', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
- it('Delete index patterns from custom rules', () => {
- const rulesToSelect = [
+ // select only rules that are not ML
+ selectRulesByName([
RULE_NAME,
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
- ] as const;
- const indexPatternsToDelete = prePopulatedIndexPatterns.slice(0, 1);
- const resultingIndexPatterns = prePopulatedIndexPatterns.slice(1);
-
- // select only not ML rules
- selectRulesByName(rulesToSelect);
+ ]);
- openBulkEditDeleteIndexPatternsForm();
- typeIndexPatterns(indexPatternsToDelete);
+ openBulkEditAddIndexPatternsForm();
+ typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
-
- // check if rule has been updated
- goToRuleDetailsOf(RULE_NAME);
- hasIndexPatterns(resultingIndexPatterns.join(''));
+ waitForBulkEditActionToFinish({
+ updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
+ });
});
+ });
- it('Delete all index patterns from custom rules', () => {
- const rulesToSelect = [
- RULE_NAME,
- 'New EQL Rule',
- 'Threat Indicator Rule Test',
- 'Threshold Rule',
- 'New Terms Rule',
- ] as const;
+ it('Overwrite index patterns in custom rules', () => {
+ const rulesToSelect = [
+ RULE_NAME,
+ 'New EQL Rule',
+ 'Threat Indicator Rule Test',
+ 'Threshold Rule',
+ 'New Terms Rule',
+ ] as const;
+ const indexPattersToWrite = ['index-to-write-1-*', 'index-to-write-2-*'];
+
+ // select only rules that are not ML
+ selectRulesByName(rulesToSelect);
+
+ openBulkEditAddIndexPatternsForm();
+
+ // check overwrite index patterns checkbox, ensure warning message is displayed and type index patterns
+ checkOverwriteIndexPatternsCheckbox();
+ cy.get(RULES_BULK_EDIT_INDEX_PATTERNS_WARNING).should(
+ 'have.text',
+ `You’re about to overwrite index patterns for ${rulesToSelect.length} selected rules, press Save to apply changes.`
+ );
- // select only rules that are not ML
- selectRulesByName(rulesToSelect);
+ typeIndexPatterns(indexPattersToWrite);
+ submitBulkEditForm();
- openBulkEditDeleteIndexPatternsForm();
- typeIndexPatterns(prePopulatedIndexPatterns);
- submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
- // error toast should be displayed that that rules edit failed
- waitForBulkEditActionToFinish({ failedCount: rulesToSelect.length });
+ // check if rule has been updated
+ goToRuleDetailsOf(RULE_NAME);
+ hasIndexPatterns(indexPattersToWrite.join(''));
+ });
- // on error toast button click display error that index patterns can't be empty
- clickErrorToastBtn();
- cy.contains(MODAL_ERROR_BODY, "Index patterns can't be empty");
- });
+ it('Delete index patterns from custom rules', () => {
+ const rulesToSelect = [
+ RULE_NAME,
+ 'New EQL Rule',
+ 'Threat Indicator Rule Test',
+ 'Threshold Rule',
+ 'New Terms Rule',
+ ] as const;
+ const indexPatternsToDelete = prePopulatedIndexPatterns.slice(0, 1);
+ const resultingIndexPatterns = prePopulatedIndexPatterns.slice(1);
+
+ // select only not ML rules
+ selectRulesByName(rulesToSelect);
+
+ openBulkEditDeleteIndexPatternsForm();
+ typeIndexPatterns(indexPatternsToDelete);
+ submitBulkEditForm();
+
+ waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
+
+ // check if rule has been updated
+ goToRuleDetailsOf(RULE_NAME);
+ hasIndexPatterns(resultingIndexPatterns.join(''));
});
- describe('Timeline templates', () => {
- beforeEach(() => {
- loadPrepackagedTimelineTemplates();
- });
+ it('Delete all index patterns from custom rules', () => {
+ const rulesToSelect = [
+ RULE_NAME,
+ 'New EQL Rule',
+ 'Threat Indicator Rule Test',
+ 'Threshold Rule',
+ 'New Terms Rule',
+ ] as const;
- it('Apply timeline template to custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- const timelineTemplateName = 'Generic Endpoint Timeline';
+ // select only rules that are not ML
+ selectRulesByName(rulesToSelect);
- selectAllRules();
+ openBulkEditDeleteIndexPatternsForm();
+ typeIndexPatterns(prePopulatedIndexPatterns);
+ submitBulkEditForm();
- // open Timeline template form, check warning, select timeline template
- clickApplyTimelineTemplatesMenuItem();
- cy.get(RULES_BULK_EDIT_TIMELINE_TEMPLATES_WARNING).contains(
- `You're about to apply changes to ${rows.length} selected rules. If you previously applied Timeline templates to these rules, they will be overwritten or (if you select 'None') reset to none.`
- );
- selectTimelineTemplate(timelineTemplateName);
+ // error toast should be displayed that that rules edit failed
+ waitForBulkEditActionToFinish({ failedCount: rulesToSelect.length });
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ // on error toast button click display error that index patterns can't be empty
+ clickErrorToastBtn();
+ cy.contains(MODAL_ERROR_BODY, "Index patterns can't be empty");
+ });
+ });
- // check if timeline template has been updated to selected one
- goToRuleDetailsOf(RULE_NAME);
- getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', timelineTemplateName);
- });
+ describe('Timeline templates', () => {
+ beforeEach(() => {
+ loadPrepackagedTimelineTemplates();
+ });
+
+ it('Apply timeline template to custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const timelineTemplateName = 'Generic Endpoint Timeline';
+
+ selectAllRules();
+
+ // open Timeline template form, check warning, select timeline template
+ clickApplyTimelineTemplatesMenuItem();
+ cy.get(RULES_BULK_EDIT_TIMELINE_TEMPLATES_WARNING).contains(
+ `You're about to apply changes to ${rows.length} selected rules. If you previously applied Timeline templates to these rules, they will be overwritten or (if you select 'None') reset to none.`
+ );
+ selectTimelineTemplate(timelineTemplateName);
+
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
+
+ // check if timeline template has been updated to selected one
+ goToRuleDetailsOf(RULE_NAME);
+ getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', timelineTemplateName);
});
+ });
- it('Reset timeline template to None for custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- const noneTimelineTemplate = 'None';
+ it('Reset timeline template to None for custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ const noneTimelineTemplate = 'None';
- selectAllRules();
+ selectAllRules();
- // open Timeline template form, submit form without picking timeline template as None is selected by default
- clickApplyTimelineTemplatesMenuItem();
+ // open Timeline template form, submit form without picking timeline template as None is selected by default
+ clickApplyTimelineTemplatesMenuItem();
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
- // check if timeline template has been updated to selected one, by opening rule that have had timeline prior to editing
- goToRuleDetailsOf(RULE_NAME);
- getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', noneTimelineTemplate);
- });
+ // check if timeline template has been updated to selected one, by opening rule that have had timeline prior to editing
+ goToRuleDetailsOf(RULE_NAME);
+ getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', noneTimelineTemplate);
});
});
+ });
- describe('Schedule', () => {
- it('Default values are applied to bulk edit schedule fields', () => {
- getRulesManagementTableRows().then((rows) => {
- selectAllRules();
- clickUpdateScheduleMenuItem();
+ describe('Schedule', () => {
+ it('Default values are applied to bulk edit schedule fields', () => {
+ getRulesManagementTableRows().then((rows) => {
+ selectAllRules();
+ clickUpdateScheduleMenuItem();
- assertUpdateScheduleWarningExists(rows.length);
+ assertUpdateScheduleWarningExists(rows.length);
- assertDefaultValuesAreAppliedToScheduleFields({
- interval: 5,
- lookback: 1,
- });
+ assertDefaultValuesAreAppliedToScheduleFields({
+ interval: 5,
+ lookback: 1,
});
});
+ });
- it('Updates schedule for custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- selectAllRules();
- clickUpdateScheduleMenuItem();
+ it('Updates schedule for custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ selectAllRules();
+ clickUpdateScheduleMenuItem();
- assertUpdateScheduleWarningExists(rows.length);
+ assertUpdateScheduleWarningExists(rows.length);
- typeScheduleInterval('20');
- setScheduleIntervalTimeUnit('Hours');
+ typeScheduleInterval('20');
+ setScheduleIntervalTimeUnit('Hours');
- typeScheduleLookback('10');
- setScheduleLookbackTimeUnit('Minutes');
+ typeScheduleLookback('10');
+ setScheduleLookbackTimeUnit('Minutes');
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
- goToRuleDetailsOf(RULE_NAME);
+ goToRuleDetailsOf(RULE_NAME);
- assertRuleScheduleValues({
- interval: '20h',
- lookback: '10m',
- });
+ assertRuleScheduleValues({
+ interval: '20h',
+ lookback: '10m',
});
});
+ });
- it('Validates invalid inputs when scheduling for custom rules', () => {
- getRulesManagementTableRows().then((rows) => {
- selectAllRules();
- clickUpdateScheduleMenuItem();
+ it('Validates invalid inputs when scheduling for custom rules', () => {
+ getRulesManagementTableRows().then((rows) => {
+ selectAllRules();
+ clickUpdateScheduleMenuItem();
- // Validate invalid values are corrected to minimumValue - for 0 and negative values
- typeScheduleInterval('0');
- setScheduleIntervalTimeUnit('Hours');
+ // Validate invalid values are corrected to minimumValue - for 0 and negative values
+ typeScheduleInterval('0');
+ setScheduleIntervalTimeUnit('Hours');
- typeScheduleLookback('-5');
- setScheduleLookbackTimeUnit('Seconds');
+ typeScheduleLookback('-5');
+ setScheduleLookbackTimeUnit('Seconds');
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
- goToRuleDetailsOf(RULE_NAME);
+ goToRuleDetailsOf(RULE_NAME);
- assertRuleScheduleValues({
- interval: '1h',
- lookback: '1s',
- });
+ assertRuleScheduleValues({
+ interval: '1h',
+ lookback: '1s',
});
});
});
- }
-);
+ });
+});
// ES|QL rule type is supported only in ESS environment
// Adding 2 use cases only for this rule type, while it is disabled on serverless
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts
index 1d59135012a9d..48acff836f0a4 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts
@@ -74,82 +74,79 @@ const ruleNameToAssert = 'Custom rule name with actions';
const expectedExistingSlackMessage = 'Existing slack action';
const expectedSlackMessage = 'Slack action test message';
-// TODO: https://github.com/elastic/kibana/issues/161540
-describe(
- 'Detection rules, bulk edit of rule actions',
- { tags: ['@ess', '@serverless', '@brokenInServerless'] },
- () => {
- beforeEach(() => {
- cleanKibana();
- login();
- deleteAlertsAndRules();
- deleteConnectors();
- cy.task('esArchiverResetKibana');
-
- createSlackConnector().then(({ body }) => {
- const actions: RuleActionArray = [
- {
- id: body.id,
- action_type_id: '.slack',
- group: 'default',
- params: {
- message: expectedExistingSlackMessage,
- },
- frequency: {
- summary: true,
- throttle: null,
- notifyWhen: 'onActiveAlert',
- },
+describe('Detection rules, bulk edit of rule actions', { tags: ['@ess', '@serverless'] }, () => {
+ beforeEach(() => {
+ cleanKibana();
+ login();
+ deleteAlertsAndRules();
+ deleteConnectors();
+ cy.task('esArchiverResetKibana');
+
+ createSlackConnector().then(({ body }) => {
+ const actions: RuleActionArray = [
+ {
+ id: body.id,
+ action_type_id: '.slack',
+ group: 'default',
+ params: {
+ message: expectedExistingSlackMessage,
},
- ];
-
- createRule(
- getNewRule({
- rule_id: '1',
- name: ruleNameToAssert,
- max_signals: 500,
- actions,
- enabled: false,
- })
- );
- });
+ frequency: {
+ summary: true,
+ throttle: null,
+ notifyWhen: 'onActiveAlert',
+ },
+ },
+ ];
- createRule(getEqlRule({ rule_id: '2', name: 'New EQL Rule', enabled: false }));
createRule(
- getMachineLearningRule({ rule_id: '3', name: 'New ML Rule Test', enabled: false })
- );
- createRule(
- getNewThreatIndicatorRule({
- rule_id: '4',
- name: 'Threat Indicator Rule Test',
+ getNewRule({
+ rule_id: '1',
+ name: ruleNameToAssert,
+ max_signals: 500,
+ actions,
enabled: false,
})
);
- createRule(getNewThresholdRule({ rule_id: '5', name: 'Threshold Rule', enabled: false }));
- createRule(getNewTermsRule({ rule_id: '6', name: 'New Terms Rule', enabled: false }));
- createRule(
- getNewRule({ saved_id: 'mocked', rule_id: '7', name: 'New Rule Test', enabled: false })
- );
-
- createSlackConnector();
-
- // Prevent prebuilt rules package installation and mock two prebuilt rules
- preventPrebuiltRulesPackageInstallation();
-
- const RULE_1 = createRuleAssetSavedObject({
- name: 'Test rule 1',
- rule_id: 'rule_1',
- });
- const RULE_2 = createRuleAssetSavedObject({
- name: 'Test rule 2',
- rule_id: 'rule_2',
- });
+ });
- createAndInstallMockedPrebuiltRules([RULE_1, RULE_2]);
+ createRule(getEqlRule({ rule_id: '2', name: 'New EQL Rule', enabled: false }));
+ createRule(getMachineLearningRule({ rule_id: '3', name: 'New ML Rule Test', enabled: false }));
+ createRule(
+ getNewThreatIndicatorRule({
+ rule_id: '4',
+ name: 'Threat Indicator Rule Test',
+ enabled: false,
+ })
+ );
+ createRule(getNewThresholdRule({ rule_id: '5', name: 'Threshold Rule', enabled: false }));
+ createRule(getNewTermsRule({ rule_id: '6', name: 'New Terms Rule', enabled: false }));
+ createRule(
+ getNewRule({ saved_id: 'mocked', rule_id: '7', name: 'New Rule Test', enabled: false })
+ );
+
+ createSlackConnector();
+
+ // Prevent prebuilt rules package installation and mock two prebuilt rules
+ preventPrebuiltRulesPackageInstallation();
+
+ const RULE_1 = createRuleAssetSavedObject({
+ name: 'Test rule 1',
+ rule_id: 'rule_1',
});
+ const RULE_2 = createRuleAssetSavedObject({
+ name: 'Test rule 2',
+ rule_id: 'rule_2',
+ });
+
+ createAndInstallMockedPrebuiltRules([RULE_1, RULE_2]);
+ });
- context('Restricted action privileges', () => {
- it("User with no privileges can't add rule actions", () => {
+ context('Restricted action privileges', () => {
+ it(
+ "User with no privileges can't add rule actions",
+ { tags: ['@ess', '@skipInServerless'] },
+ () => {
login(ROLES.hunter_no_actions);
visitRulesManagementTable(ROLES.hunter_no_actions);
@@ -171,129 +168,129 @@ describe(
openBulkActionsMenu();
cy.get(ADD_RULE_ACTIONS_MENU_ITEM).should('be.disabled');
- });
- });
+ }
+ );
+ });
- context('All actions privileges', () => {
- beforeEach(() => {
- login();
- visitRulesManagementTable();
- disableAutoRefresh();
-
- expectManagementTableRules([
- ruleNameToAssert,
- 'New EQL Rule',
- 'New ML Rule Test',
- 'Threat Indicator Rule Test',
- 'Threshold Rule',
- 'New Terms Rule',
- 'New Rule Test',
- 'Test rule 1',
- 'Test rule 2',
- ]);
- });
+ context('All actions privileges', () => {
+ beforeEach(() => {
+ login();
+ visitRulesManagementTable();
+ disableAutoRefresh();
+
+ expectManagementTableRules([
+ ruleNameToAssert,
+ 'New EQL Rule',
+ 'New ML Rule Test',
+ 'Threat Indicator Rule Test',
+ 'Threshold Rule',
+ 'New Terms Rule',
+ 'New Rule Test',
+ 'Test rule 1',
+ 'Test rule 2',
+ ]);
+ });
- it('Add a rule action to rules (existing connector)', () => {
- const expectedActionFrequency: RuleActionCustomFrequency = {
- throttle: 1,
- throttleUnit: 'd',
- };
+ it('Add a rule action to rules (existing connector)', () => {
+ const expectedActionFrequency: RuleActionCustomFrequency = {
+ throttle: 1,
+ throttleUnit: 'd',
+ };
- excessivelyInstallAllPrebuiltRules();
+ excessivelyInstallAllPrebuiltRules();
- getRulesManagementTableRows().then((rows) => {
- // select both custom and prebuilt rules
- selectAllRules();
- openBulkEditRuleActionsForm();
+ getRulesManagementTableRows().then((rows) => {
+ // select both custom and prebuilt rules
+ selectAllRules();
+ openBulkEditRuleActionsForm();
- // ensure rule actions info callout displayed on the form
- cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible');
+ // ensure rule actions info callout displayed on the form
+ cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible');
- addSlackRuleAction(expectedSlackMessage);
- pickSummaryOfAlertsOption();
- pickCustomFrequencyOption(expectedActionFrequency);
+ addSlackRuleAction(expectedSlackMessage);
+ pickSummaryOfAlertsOption();
+ pickCustomFrequencyOption(expectedActionFrequency);
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
- // check if rule has been updated
- goToEditRuleActionsSettingsOf(ruleNameToAssert);
+ // check if rule has been updated
+ goToEditRuleActionsSettingsOf(ruleNameToAssert);
- assertSelectedSummaryOfAlertsOption();
- assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
- assertSlackRuleAction(expectedExistingSlackMessage, 0);
- assertSlackRuleAction(expectedSlackMessage, 1);
- // ensure there is no third action
- cy.get(actionFormSelector(2)).should('not.exist');
- });
+ assertSelectedSummaryOfAlertsOption();
+ assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
+ assertSlackRuleAction(expectedExistingSlackMessage, 0);
+ assertSlackRuleAction(expectedSlackMessage, 1);
+ // ensure there is no third action
+ cy.get(actionFormSelector(2)).should('not.exist');
});
+ });
- it('Overwrite rule actions in rules', () => {
- excessivelyInstallAllPrebuiltRules();
-
- getRulesManagementTableRows().then((rows) => {
- // select both custom and prebuilt rules
- selectAllRules();
- openBulkEditRuleActionsForm();
-
- addSlackRuleAction(expectedSlackMessage);
- pickSummaryOfAlertsOption();
- pickPerRuleRunFrequencyOption();
-
- // check overwrite box, ensure warning is displayed
- checkOverwriteRuleActionsCheckbox();
- cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains(
- `You're about to overwrite rule actions for ${rows.length} selected rules`
- );
-
- submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rows.length });
-
- // check if rule has been updated
- goToEditRuleActionsSettingsOf(ruleNameToAssert);
-
- assertSelectedSummaryOfAlertsOption();
- assertSelectedPerRuleRunFrequencyOption();
- assertSlackRuleAction(expectedSlackMessage);
- // ensure existing action was overwritten
- cy.get(actionFormSelector(1)).should('not.exist');
- });
- });
+ it('Overwrite rule actions in rules', () => {
+ excessivelyInstallAllPrebuiltRules();
- it('Add a rule action to rules (new connector)', () => {
- const rulesToSelect = [
- ruleNameToAssert,
- 'New EQL Rule',
- 'New ML Rule Test',
- 'Threat Indicator Rule Test',
- 'Threshold Rule',
- 'New Terms Rule',
- 'New Rule Test',
- ] as const;
- const expectedActionFrequency: RuleActionCustomFrequency = {
- throttle: 2,
- throttleUnit: 'h',
- };
- const expectedEmail = 'test@example.com';
- const expectedSubject = 'Subject';
-
- selectRulesByName(rulesToSelect);
+ getRulesManagementTableRows().then((rows) => {
+ // select both custom and prebuilt rules
+ selectAllRules();
openBulkEditRuleActionsForm();
- addEmailConnectorAndRuleAction(expectedEmail, expectedSubject);
+ addSlackRuleAction(expectedSlackMessage);
pickSummaryOfAlertsOption();
- pickCustomFrequencyOption(expectedActionFrequency);
+ pickPerRuleRunFrequencyOption();
+
+ // check overwrite box, ensure warning is displayed
+ checkOverwriteRuleActionsCheckbox();
+ cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains(
+ `You're about to overwrite rule actions for ${rows.length} selected rules`
+ );
submitBulkEditForm();
- waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
+ waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);
assertSelectedSummaryOfAlertsOption();
- assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
- assertEmailRuleAction(expectedEmail, expectedSubject);
+ assertSelectedPerRuleRunFrequencyOption();
+ assertSlackRuleAction(expectedSlackMessage);
+ // ensure existing action was overwritten
+ cy.get(actionFormSelector(1)).should('not.exist');
});
});
- }
-);
+
+ it('Add a rule action to rules (new connector)', () => {
+ const rulesToSelect = [
+ ruleNameToAssert,
+ 'New EQL Rule',
+ 'New ML Rule Test',
+ 'Threat Indicator Rule Test',
+ 'Threshold Rule',
+ 'New Terms Rule',
+ 'New Rule Test',
+ ] as const;
+ const expectedActionFrequency: RuleActionCustomFrequency = {
+ throttle: 2,
+ throttleUnit: 'h',
+ };
+ const expectedEmail = 'test@example.com';
+ const expectedSubject = 'Subject';
+
+ selectRulesByName(rulesToSelect);
+ openBulkEditRuleActionsForm();
+
+ addEmailConnectorAndRuleAction(expectedEmail, expectedSubject);
+ pickSummaryOfAlertsOption();
+ pickCustomFrequencyOption(expectedActionFrequency);
+
+ submitBulkEditForm();
+ waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
+
+ // check if rule has been updated
+ goToEditRuleActionsSettingsOf(ruleNameToAssert);
+
+ assertSelectedSummaryOfAlertsOption();
+ assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
+ assertEmailRuleAction(expectedEmail, expectedSubject);
+ });
+ });
+});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts
index b5c696da0c5ac..21c4558ce15e9 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts
@@ -53,10 +53,9 @@ const DATA_VIEW_ID = 'auditbeat';
const expectedIndexPatterns = ['index-1-*', 'index-2-*'];
-// TODO: https://github.com/elastic/kibana/issues/161540
describe(
'Bulk editing index patterns of rules with a data view only',
- { tags: ['@ess', '@serverless', '@brokenInServerless'] },
+ { tags: ['@ess', '@serverless'] },
() => {
const TESTED_CUSTOM_QUERY_RULE_DATA = getNewRule({
index: undefined,
@@ -244,7 +243,7 @@ describe(
describe(
'Bulk editing index patterns of rules with index patterns and rules with a data view',
- { tags: ['@ess', '@brokenInServerless'] },
+ { tags: ['@ess', '@serverless'] },
() => {
const TESTED_CUSTOM_QUERY_RULE_DATA_WITH_DATAVIEW = getNewRule({
name: 'with dataview',
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts
index 86168a7798948..4f4cb0a505712 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts
@@ -134,7 +134,7 @@ describe(
// init
riskEngineStatusChange();
- cy.get(RISK_SCORE_ERROR_PANEL).contains('Sorry, there was an error');
+ cy.get(RISK_SCORE_ERROR_PANEL).contains('There was an error');
});
it('should update if there legacy risk score installed', () => {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts
index 3cc088f53d301..e5ef69188a8ba 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts
@@ -5,6 +5,7 @@
* 2.0.
*/
+import moment from 'moment';
import { login } from '../../../tasks/login';
import { visitWithTimeRange } from '../../../tasks/navigation';
@@ -47,7 +48,7 @@ import { clickOnFirstHostsAlerts, clickOnFirstUsersAlerts } from '../../../tasks
import { OPTION_LIST_LABELS, OPTION_LIST_VALUES } from '../../../screens/common/filter_group';
import { setRowsPerPageTo } from '../../../tasks/table_pagination';
import { kqlSearch } from '../../../tasks/security_header';
-import { setEndDate, updateDates } from '../../../tasks/date_picker';
+import { setEndDate, setStartDate, updateDates } from '../../../tasks/date_picker';
import {
enableJob,
navigateToNextPage,
@@ -60,7 +61,9 @@ const TEST_USER_ALERTS = 2;
const TEST_USER_NAME = 'test';
const SIEM_KIBANA_HOST_ALERTS = 2;
const SIEM_KIBANA_HOST_NAME = 'siem-kibana';
-const END_DATE = 'Jan 19, 2019 @ 20:33:29.186';
+const DATE_FORMAT = 'MMM D, YYYY @ HH:mm:ss.SSS';
+const DATE_BEFORE_ALERT_CREATION = moment().format(DATE_FORMAT);
+const OLDEST_DATE = moment('2019-01-19T16:22:56.217Z').format(DATE_FORMAT);
describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
@@ -200,7 +203,8 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () =>
});
it('filters the alerts count with time range', () => {
- setEndDate(END_DATE);
+ setEndDate(DATE_BEFORE_ALERT_CREATION);
+
updateDates();
cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', 0);
@@ -282,7 +286,7 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () =>
});
it('filters the alerts count with time range', () => {
- setEndDate(END_DATE);
+ setEndDate(DATE_BEFORE_ALERT_CREATION);
updateDates();
cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', 0);
@@ -409,12 +413,24 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () =>
});
it('filters the alerts count with time range', () => {
- setEndDate(END_DATE);
+ setEndDate(DATE_BEFORE_ALERT_CREATION);
updateDates();
cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', 0);
});
+ it('filters risk scores with time range', () => {
+ const now = moment().format(DATE_FORMAT);
+ setStartDate(now);
+ updateDates();
+
+ cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible');
+
+ // CLEAR DATES
+ setStartDate(OLDEST_DATE);
+ updateDates();
+ });
+
it('opens alerts page when alerts count is clicked', () => {
clickOnFirstHostsAlerts();
cy.url().should('include', ALERTS_URL);
@@ -496,12 +512,24 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () =>
});
it('filters the alerts count with time range', () => {
- setEndDate(END_DATE);
+ setEndDate(DATE_BEFORE_ALERT_CREATION);
updateDates();
cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', 0);
});
+ it('filters risk scores with time range', () => {
+ const now = moment().format(DATE_FORMAT);
+ setStartDate(now);
+ updateDates();
+
+ cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible');
+
+ // CLEAR DATES
+ setStartDate(OLDEST_DATE);
+ updateDates();
+ });
+
it('opens alerts page when alerts count is clicked', () => {
clickOnFirstUsersAlerts();
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts
index 6a11e27bcc81a..9fcc16406793f 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts
@@ -49,9 +49,10 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => {
it('renders the table', () => {
kqlSearch('host.name: "siem-kibana" {enter}');
- cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('have.text', 'siem-kibana');
- cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', '21');
- cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Low');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', 'siem-kibana');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Mar 10, 2021 @ 14:51:05.766');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(6).should('have.text', '21');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(7).should('have.text', 'Low');
});
it.skip('filters the table', () => {
@@ -99,9 +100,10 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => {
it('renders the table', () => {
kqlSearch('host.name: "siem-kibana" {enter}');
- cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('have.text', 'siem-kibana');
- cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', '90');
- cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Critical');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', 'siem-kibana');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Mar 10, 2021 @ 14:51:05.766');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(6).should('have.text', '90');
+ cy.get(HOST_BY_RISK_TABLE_CELL).eq(7).should('have.text', 'Critical');
});
it.skip('filters the table', () => {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts
index 78ead35a49327..30a3704879f36 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts
@@ -17,7 +17,7 @@ import {
openTableInspectModal,
} from '../../tasks/inspect';
import { login } from '../../tasks/login';
-import { visit } from '../../tasks/navigation';
+import { visitWithTimeRange } from '../../tasks/navigation';
import { postDataView, waitForWelcomePanelToBeLoaded } from '../../tasks/common';
import { selectDataView } from '../../tasks/sourcerer';
@@ -46,7 +46,7 @@ describe('Inspect Explore pages', { tags: ['@ess', '@serverless', '@brokenInServ
it(`inspect ${pageName} page`, () => {
login();
- visit(url, {
+ visitWithTimeRange(url, {
visitOptions: {
onLoad: () => {
waitForWelcomePanelToBeLoaded();
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts
index d4301853029a6..5620fb953e0d3 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts
@@ -51,7 +51,8 @@ const defaultHeaders = [
];
// Flaky in serverless tests
-describe('Fields Browser', { tags: ['@ess', '@serverless'] }, () => {
+// FLAKY: https://github.com/elastic/kibana/issues/169363
+describe.skip('Fields Browser', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
cleanKibana();
});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts
index b257e340bd7cb..329e0b33144bf 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts
@@ -25,8 +25,7 @@ import { editRuleUrl } from '../../urls/edit_rule';
const mockRuleId = '5a4a0460-d822-11eb-8962-bfd4aff0a9b3';
-// FLAKY: https://github.com/elastic/kibana/issues/165710
-describe('Display not found page', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
+describe('Display not found page', { tags: ['@ess', '@serverless'] }, () => {
beforeEach(() => {
login();
visitWithTimeRange(TIMELINES_URL);
diff --git a/x-pack/test/security_solution_cypress/cypress/screens/inspect.ts b/x-pack/test/security_solution_cypress/cypress/screens/inspect.ts
index 0759fb1e4924c..ba511883c05b6 100644
--- a/x-pack/test/security_solution_cypress/cypress/screens/inspect.ts
+++ b/x-pack/test/security_solution_cypress/cypress/screens/inspect.ts
@@ -86,7 +86,6 @@ export const INSPECT_BUTTONS_IN_SECURITY: InspectButtonMetadata[] = [
altInspectId: '[data-test-subj="events-viewer-panel"]',
id: EVENT_CONTAINER_TABLE_NOT_LOADING,
},
-
{
title: 'Host risk',
tab: RISK_DETAILS_NAV,
diff --git a/x-pack/test_serverless/shared/lib/security/kibana_roles/kibana_roles.ts b/x-pack/test_serverless/shared/lib/security/kibana_roles/kibana_roles.ts
index ddfeef06c6a2e..a2d244072de87 100644
--- a/x-pack/test_serverless/shared/lib/security/kibana_roles/kibana_roles.ts
+++ b/x-pack/test_serverless/shared/lib/security/kibana_roles/kibana_roles.ts
@@ -16,16 +16,17 @@ const ROLES_YAML_FILE_PATH = path.join(__dirname, 'project_controller_security_r
const ROLE_NAMES = Object.values(ServerlessRoleName);
+interface IApplication {
+ application: string;
+ privileges: string[];
+ resources: string;
+}
export type YamlRoleDefinitions = Record<
ServerlessRoleName,
{
cluster: string[] | null;
indices: RoleIndexPrivilege[];
- applications: Array<{
- application: string;
- privileges: string[];
- resources: string;
- }>;
+ applications: IApplication[];
}
>;
@@ -48,6 +49,34 @@ export const getServerlessSecurityKibanaRoleDefinitions = (
`Un-expected role [${roleName}] found in YAML file [${ROLES_YAML_FILE_PATH}]`
);
}
+ const mapApplicationToKibanaFeaturePrivileges = (
+ application: IApplication
+ ): FeaturesPrivileges => {
+ if (application.resources !== '*') {
+ throw new Error(
+ `YAML role definition parser does not currently support 'application.resource = ${application.resources}' for ${application.application} `
+ );
+ }
+
+ const features: FeaturesPrivileges = {};
+
+ application.privileges.forEach((value) => {
+ const [feature, permission] = value.split('.');
+ const featureKey = feature.split('_')[1];
+
+ if (!features[featureKey]) {
+ features[featureKey] = [];
+ }
+
+ if (permission) {
+ features[featureKey].push(permission);
+ }
+ });
+
+ return features;
+ };
+
+ const feature = mapApplicationToKibanaFeaturePrivileges(definition.applications[0]);
const kibanaRole: Role = {
name: roleName,
@@ -60,16 +89,7 @@ export const getServerlessSecurityKibanaRoleDefinitions = (
{
base: [],
spaces: ['*'],
- feature: definition.applications.reduce((features, application) => {
- if (application.resources !== '*') {
- throw new Error(
- `YAML role definition parser does not currently support 'application.resource = ${application.resources}' for ${application.application} `
- );
- }
-
- features[application.application] = application.privileges;
- return features;
- }, {} as FeaturesPrivileges),
+ feature,
},
],
};
diff --git a/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml b/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml
index 13a8d07a79502..1444b818b10ee 100644
--- a/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml
+++ b/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml
@@ -1,6 +1,116 @@
# -----
# Source: https://github.com/elastic/project-controller/blob/main/internal/project/security/config/roles.yml
-# -----
+
+# modeled after the t1_analyst minus osquery run saved queries privilege
+viewer:
+ cluster: []
+ indices:
+ - names:
+ - ".siem-signals*"
+ - ".lists-*"
+ - ".items-*"
+ privileges:
+ - "read"
+ - "view_index_metadata"
+ allow_restricted_indices: false
+ - names:
+ - ".alerts*"
+ - ".preview.alerts*"
+ privileges:
+ - "read"
+ - "view_index_metadata"
+ allow_restricted_indices: false
+ - names:
+ - apm-*-transaction*
+ - traces-apm*
+ - auditbeat-*
+ - endgame-*
+ - filebeat-*
+ - logs-*
+ - packetbeat-*
+ - winlogbeat-*
+ - metrics-endpoint.metadata_current_*
+ - ".fleet-agents*"
+ - ".fleet-actions*"
+ - "risk-score.risk-score-*"
+ privileges:
+ - read
+ applications:
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.read
+ - feature_siem.read_alerts
+ - feature_siem.endpoint_list_read
+ - feature_securitySolutionCases.read
+ - feature_actions.read
+ - feature_builtInAlerts.read
+ - feature_osquery.read
+ resources: "*"
+ run_as: []
+
+# modeled after t3_analyst
+editor:
+ cluster: []
+ indices:
+ - names:
+ - ".siem-signals*"
+ - ".lists-*"
+ - ".items-*"
+ privileges:
+ - "read"
+ - "view_index_metadata"
+ - "write"
+ - "maintenance"
+ allow_restricted_indices: false
+ - names:
+ - apm-*-transaction*
+ - traces-apm*
+ - auditbeat-*
+ - endgame-*
+ - filebeat-*
+ - logs-*
+ - packetbeat-*
+ - winlogbeat-*
+ privileges:
+ - read
+ - write
+ - names:
+ - ".internal.alerts*"
+ - ".alerts*"
+ - ".internal.preview.alerts*"
+ - ".preview.alerts*"
+ - "risk-score.risk-score-*"
+ privileges:
+ - "read"
+ - "view_index_metadata"
+ - "write"
+ - "maintenance"
+ allow_restricted_indices: false
+ applications:
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.crud_alerts
+ - feature_siem.endpoint_list_all
+ - feature_siem.trusted_applications_all
+ - feature_siem.event_filters_all
+ - feature_siem.host_isolation_exceptions_all
+ - feature_siem.blocklist_all
+ - feature_siem.policy_management_read # Elastic Defend Policy Management
+ - feature_siem.host_isolation_all
+ - feature_siem.process_operations_all
+ - feature_siem.actions_log_management_all # Response actions history
+ - feature_siem.file_operations_all
+ - feature_securitySolutionCases.all
+ - feature_actions.read
+ - feature_builtInAlerts.all
+ - feature_osquery.all
+ resources: "*"
+ run_as: []
+
t1_analyst:
cluster:
indices:
@@ -23,39 +133,21 @@ t1_analyst:
- metrics-endpoint.metadata_current_*
- ".fleet-agents*"
- ".fleet-actions*"
+ - risk-score.risk-score-*
privileges:
- read
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - read
- - read_alerts
- - endpoint_list_read
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - read
- resources: "*"
- - application: actions
- privileges:
- - read
- resources: "*"
- - application: builtInAlerts
- privileges:
- - read
- resources: "*"
- - application: spaces
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - read
- - run_saved_queries
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.read
+ - feature_siem.read_alerts
+ - feature_siem.endpoint_list_read
+ - feature_securitySolutionCases.read
+ - feature_actions.read
+ - feature_builtInAlerts.read
+ - feature_osquery.read
+ - feature_osquery.run_saved_queries
resources: "*"
t2_analyst:
@@ -82,39 +174,21 @@ t2_analyst:
- metrics-endpoint.metadata_current_*
- .fleet-agents*
- .fleet-actions*
+ - risk-score.risk-score-*
privileges:
- read
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - read
- - read_alerts
- - endpoint_list_read
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - read
- resources: "*"
- - application: builtInAlerts
- privileges:
- - read
- resources: "*"
- - application: spaces
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - read
- - run_saved_queries
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.read
+ - feature_siem.read_alerts
+ - feature_siem.endpoint_list_read
+ - feature_securitySolutionCases.all
+ - feature_actions.read
+ - feature_builtInAlerts.read
+ - feature_osquery.read
+ - feature_osquery.run_saved_queries
resources: "*"
t3_analyst:
@@ -148,48 +222,30 @@ t3_analyst:
- metrics-endpoint.metadata_current_*
- .fleet-agents*
- .fleet-actions*
+ - risk-score.risk-score-*
privileges:
- read
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - all
- - read_alerts
- - crud_alerts
- - endpoint_list_all
- - trusted_applications_all
- - event_filters_all
- - host_isolation_exceptions_all
- - blocklist_all
- - policy_management_read # Elastic Defend Policy Management
- - host_isolation_all
- - process_operations_all
- - actions_log_management_all # Response actions history
- - file_operations_all
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - read
- resources: "*"
- - application: builtInAlerts
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - all
- resources: "*"
- - application: spaces
- privileges:
- - all
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.crud_alerts
+ - feature_siem.endpoint_list_all
+ - feature_siem.trusted_applications_all
+ - feature_siem.event_filters_all
+ - feature_siem.host_isolation_exceptions_all
+ - feature_siem.blocklist_all
+ - feature_siem.policy_management_read # Elastic Defend Policy Management
+ - feature_siem.host_isolation_all
+ - feature_siem.process_operations_all
+ - feature_siem.actions_log_management_all # Response actions history
+ - feature_siem.file_operations_all
+ - feature_securitySolutionCases.all
+ - feature_actions.read
+ - feature_builtInAlerts.all
+ - feature_osquery.all
resources: "*"
threat_intelligence_analyst:
@@ -219,39 +275,21 @@ threat_intelligence_analyst:
- metrics-endpoint.metadata_current_*
- .fleet-agents*
- .fleet-actions*
+ - risk-score.risk-score-*
privileges:
- read
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - read
- - read_alerts
- - endpoint_list_read
- - blocklist_all
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - read
- resources: "*"
- - application: builtInAlerts
- privileges:
- - read
- resources: "*"
- - application: spaces
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - all
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.read
+ - feature_siem.read_alerts
+ - feature_siem.endpoint_list_read
+ - feature_siem.blocklist_all
+ - feature_securitySolutionCases.all
+ - feature_actions.read
+ - feature_builtInAlerts.read
+ - feature_osquery.all
resources: "*"
rule_author:
@@ -289,41 +327,27 @@ rule_author:
- metrics-endpoint.metadata_current_*
- .fleet-agents*
- .fleet-actions*
+ - risk-score.risk-score-*
privileges:
- read
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - all
- - read_alerts
- - crud_alerts
- - policy_management_all
- - endpoint_list_all
- - trusted_applications_all
- - event_filters_all
- - host_isolation_exceptions_read
- - blocklist_all
- - actions_log_management_read
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - read
- resources: "*"
- - application: builtInAlerts
- privileges:
- - all
- resources: "*"
- - application: spaces
- privileges:
- - all
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.crud_alerts
+ - feature_siem.policy_management_all
+ - feature_siem.endpoint_list_all
+ - feature_siem.trusted_applications_all
+ - feature_siem.event_filters_all
+ - feature_siem.host_isolation_exceptions_read
+ - feature_siem.blocklist_all # Elastic Defend Policy Management
+ - feature_siem.actions_log_management_read
+ - feature_securitySolutionCases.all
+ - feature_actions.read
+ - feature_builtInAlerts.all
+ - feature_osquery.all
resources: "*"
soc_manager:
@@ -355,59 +379,41 @@ soc_manager:
- .items*
privileges:
- read
- - maintenance
- write
- names:
- metrics-endpoint.metadata_current_*
- .fleet-agents*
- .fleet-actions*
+ - risk-score.risk-score-*
privileges:
- read
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - all
- - read_alerts
- - crud_alerts
- - policy_management_all
- - endpoint_list_all
- - trusted_applications_all
- - event_filters_all
- - host_isolation_exceptions_all
- - blocklist_all
- - host_isolation_all
- - process_operations_all
- - actions_log_management_all
- - file_operations_all
- - execute_operations_all
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - all
- resources: "*"
- - application: builtInAlerts
- privileges:
- - all
- resources: "*"
- - application: spaces
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - all
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.crud_alerts
+ - feature_siem.policy_management_all
+ - feature_siem.endpoint_list_all
+ - feature_siem.trusted_applications_all
+ - feature_siem.event_filters_all
+ - feature_siem.host_isolation_exceptions_all
+ - feature_siem.blocklist_all
+ - feature_siem.host_isolation_all
+ - feature_siem.process_operations_all
+ - feature_siem.actions_log_management_all
+ - feature_siem.file_operations_all
+ - feature_siem.execute_operations_all
+ - feature_securitySolutionCases.all
+ - feature_actions.all
+ - feature_builtInAlerts.all
+ - feature_osquery.all
+ - feature_indexPatterns.all
resources: "*"
detections_admin:
- cluster:
+ cluster: ["manage_index_templates", "manage_transform"]
indices:
- names:
- apm-*-transaction*
@@ -434,36 +440,21 @@ detections_admin:
- .fleet-actions*
privileges:
- read
- applications:
- - application: ml
- privileges:
- - all
- resources: "*"
- - application: siem
- privileges:
- - all
- - read_alerts
- - crud_alerts
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - read
- resources: "*"
- - application: builtInAlerts
- privileges:
- - all
- resources: "*"
- - application: dev_tools
+ - names:
+ - risk-score.risk-score-*
privileges:
- all
- resources: "*"
- - application: spaces
+ applications:
+ - application: "kibana-.kibana"
privileges:
- - all
+ - feature_ml.all
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.crud_alerts
+ - feature_securitySolutionCases.all
+ - feature_actions.all
+ - feature_builtInAlerts.all
+ - feature_dev_tools.all
resources: "*"
platform_engineer:
@@ -485,53 +476,30 @@ platform_engineer:
- .siem-signals-*
- .preview.alerts-security*
- .internal.preview.alerts-security*
+ - risk-score.risk-score-*
privileges:
- all
applications:
- - application: ml
- privileges:
- - all
- resources: "*"
- - application: siem
- privileges:
- - all
- - read_alerts
- - crud_alerts
- - policy_management_all
- - endpoint_list_all
- - trusted_applications_all
- - event_filters_all
- - host_isolation_exceptions_all
- - blocklist_all
- - actions_log_management_read
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - all
- resources: "*"
- - application: builtInAlerts
- privileges:
- - all
- resources: "*"
- - application: fleet
- privileges:
- - all
- resources: "*"
- - application: fleetv2
- privileges:
- - all
- resources: "*"
- - application: spaces
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - all
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.all
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.crud_alerts
+ - feature_siem.policy_management_all
+ - feature_siem.endpoint_list_all
+ - feature_siem.trusted_applications_all
+ - feature_siem.event_filters_all
+ - feature_siem.host_isolation_exceptions_all
+ - feature_siem.blocklist_all # Elastic Defend Policy Management
+ - feature_siem.actions_log_management_read
+ - feature_securitySolutionCases.all
+ - feature_actions.all
+ - feature_builtInAlerts.all
+ - feature_fleet.all
+ - feature_fleetv2.all
+ - feature_osquery.all
+ - feature_indexPatterns.all
resources: "*"
endpoint_operations_analyst:
@@ -554,6 +522,7 @@ endpoint_operations_analyst:
- winlogbeat-*
- .lists*
- .items*
+ - risk-score.risk-score-*
privileges:
- read
- names:
@@ -565,53 +534,28 @@ endpoint_operations_analyst:
- read
- write
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - all
- - read_alerts
- - policy_management_all
- - endpoint_list_all
- - trusted_applications_all
- - event_filters_all
- - host_isolation_exceptions_all
- - blocklist_all
- - host_isolation_all
- - process_operations_all
- - actions_log_management_all # Response History
- - file_operations_all
- - execute_operations_all # Execute
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - all
- resources: "*"
- - application: builtInAlerts
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - all
- resources: "*"
- - application: fleet
- privileges:
- - all
- resources: "*"
- - application: fleetv2
- privileges:
- - all
- resources: "*"
- - application: spaces
- privileges:
- - all
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.read
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.policy_management_all
+ - feature_siem.endpoint_list_all
+ - feature_siem.trusted_applications_all
+ - feature_siem.event_filters_all
+ - feature_siem.host_isolation_exceptions_all
+ - feature_siem.blocklist_all
+ - feature_siem.host_isolation_all
+ - feature_siem.process_operations_all
+ - feature_siem.actions_log_management_all # Response History
+ - feature_siem.file_operations_all
+ - feature_siem.execute_operations_all # Execute
+ - feature_securitySolutionCases.all
+ - feature_actions.all
+ - feature_builtInAlerts.all
+ - feature_osquery.all
+ - feature_fleet.all
+ - feature_fleetv2.all
resources: "*"
endpoint_policy_manager:
@@ -634,6 +578,7 @@ endpoint_policy_manager:
- winlogbeat-*
- .lists*
- .items*
+ - risk-score.risk-score-*
privileges:
- read
- names:
@@ -646,48 +591,22 @@ endpoint_policy_manager:
- write
- manage
applications:
- - application: ml
- privileges:
- - read
- resources: "*"
- - application: siem
- privileges:
- - all
- - read_alerts
- - crud_alerts
- - policy_management_all
- - trusted_applications_all
- - event_filters_all
- - host_isolation_exceptions_all
- - blocklist_all
- - endpoint_list_all
- resources: "*"
- - application: securitySolutionCases
- privileges:
- - all
- resources: "*"
- - application: actions
- privileges:
- - all
+ - application: "kibana-.kibana"
+ privileges:
+ - feature_ml.all
+ - feature_siem.all
+ - feature_siem.read_alerts
+ - feature_siem.crud_alerts
+ - feature_siem.policy_management_all
+ - feature_siem.endpoint_list_all
+ - feature_siem.trusted_applications_all
+ - feature_siem.event_filters_all
+ - feature_siem.host_isolation_exceptions_all
+ - feature_siem.blocklist_all # Elastic Defend Policy Management
+ - feature_securitySolutionCases.all
+ - feature_actions.all
+ - feature_builtInAlerts.all
+ - feature_osquery.all
+ - feature_fleet.all
+ - feature_fleetv2.all
resources: "*"
- - application: builtInAlerts
- privileges:
- - all
- resources: "*"
- - application: osquery
- privileges:
- - all
- resources: "*"
- - application: fleet
- privileges:
- - all
- resources: "*"
- - application: fleetv2
- privileges:
- - all
- resources: "*"
- - application: spaces
- privileges:
- - all
- resources: "*"
-
diff --git a/x-pack/test_serverless/shared/lib/security/kibana_roles/role_loader.ts b/x-pack/test_serverless/shared/lib/security/kibana_roles/role_loader.ts
index a0f0f447955a6..806d6244fe90a 100644
--- a/x-pack/test_serverless/shared/lib/security/kibana_roles/role_loader.ts
+++ b/x-pack/test_serverless/shared/lib/security/kibana_roles/role_loader.ts
@@ -55,7 +55,6 @@ export class RoleAndUserLoader = Record