mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Security Solution] Prebuilt rule installation / upgrade flyout test coverage (#169537)
**Resolves: https://github.com/elastic/kibana/issues/166161**
**Flaky test runner pipelne:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3868**
## Summary
Adds test coverage based on the test plan:
https://github.com/elastic/kibana/pull/167727/files
<img width="1301" alt="272390474-1aa7aa8b-3746-4767-82ad-f4910034d5eb"
src="4ad6a27a
-eeef-467b-bb72-1caf48bfb7e5">
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
5406e2c17b
commit
e389991557
26 changed files with 2156 additions and 268 deletions
|
@ -167,7 +167,7 @@ There's a legacy prebuilt rules API and a new one. Both should be tested against
|
|||
|
||||
#### **Scenario: API can install all prebuilt rules**
|
||||
|
||||
**Automation**: 8 integration tests with mock rules: 4 examples below * 2 (we split checking API response and installed rules into two different tests).
|
||||
**Automation**: 8 integration tests with mock rules: 4 examples below \* 2 (we split checking API response and installed rules into two different tests).
|
||||
|
||||
```Gherkin
|
||||
Given the package <package_type> is installed
|
||||
|
@ -436,7 +436,7 @@ And user should see the number of rules available to install (Y)
|
|||
|
||||
#### **Scenario: User can install prebuilt rules one by one**
|
||||
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /installation/* endpoints in integration.
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /installation/\* endpoints in integration.
|
||||
|
||||
```Gherkin
|
||||
Given no prebuilt rules are installed in Kibana
|
||||
|
@ -453,7 +453,7 @@ And user should see the number of rules available to install decreased by 1
|
|||
|
||||
#### **Scenario: User can install multiple prebuilt rules selected on the page**
|
||||
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /installation/* endpoints in integration.
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /installation/\* endpoints in integration.
|
||||
|
||||
```Gherkin
|
||||
Given no prebuilt rules are installed in Kibana
|
||||
|
@ -477,7 +477,7 @@ Examples:
|
|||
|
||||
#### **Scenario: User can install all available prebuilt rules at once**
|
||||
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /installation/* endpoints in integration.
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /installation/\* endpoints in integration.
|
||||
|
||||
```Gherkin
|
||||
Given no prebuilt rules are installed in Kibana
|
||||
|
@ -506,7 +506,7 @@ Then user should see a message indicating that all available rules have been ins
|
|||
And user should see a CTA that leads to the Rule Management page
|
||||
```
|
||||
|
||||
#### **Scenario: User can preview a rule before installing**
|
||||
#### **Scenario: User can preview rules available for installation**
|
||||
|
||||
**Automation**: 1 e2e test
|
||||
|
||||
|
@ -519,15 +519,26 @@ When user opens the rule preview for the 1st rule
|
|||
Then the preview should open
|
||||
When user closes the preview
|
||||
Then it should disappear
|
||||
When user opens the rule preview for the 2nd rule
|
||||
```
|
||||
|
||||
#### **Scenario: User can install a rule using the rule preview**
|
||||
|
||||
**Automation**: 1 e2e test
|
||||
|
||||
```Gherkin
|
||||
Given no prebuilt rules are installed in Kibana
|
||||
And there are 2 rules available to install
|
||||
When user opens the Add Rules page
|
||||
Then all rules available for installation should be displayed in the table
|
||||
When user opens the rule preview for the rule
|
||||
Then the preview should open
|
||||
When user installs the rule using a CTA in the rule preview
|
||||
Then the 2nd rule should be installed
|
||||
Then the rule should be installed
|
||||
And a success message should be displayed after installation
|
||||
And the 2nd rule should be removed from the Add Rules table
|
||||
And the rule should be removed from the Add Rules table
|
||||
When user navigates back to the Rule Management page
|
||||
Then user should see a CTA to install prebuilt rules
|
||||
And user should see the number of rules available to install as 1
|
||||
And user should see the number of rules available to install as initial number minus 1
|
||||
```
|
||||
|
||||
#### **Scenario: User can see correct rule information in preview before installing**
|
||||
|
@ -594,7 +605,7 @@ Then the Rule Management page should be displayed
|
|||
|
||||
#### **Scenario: User can upgrade prebuilt rules one by one**
|
||||
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /upgrade/* endpoints in integration.
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /upgrade/\* endpoints in integration.
|
||||
|
||||
```Gherkin
|
||||
Given X prebuilt rules are installed in Kibana
|
||||
|
@ -610,7 +621,7 @@ And user should see the number of rules available to upgrade decreased by 1
|
|||
|
||||
#### **Scenario: User can upgrade multiple prebuilt rules selected on the page**
|
||||
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /upgrade/* endpoints in integration.
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /upgrade/\* endpoints in integration.
|
||||
|
||||
```Gherkin
|
||||
Given X prebuilt rules are installed in Kibana
|
||||
|
@ -633,7 +644,7 @@ Examples:
|
|||
|
||||
#### **Scenario: User can upgrade all available prebuilt rules at once**
|
||||
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /upgrade/* endpoints in integration.
|
||||
**Automation**: 1 e2e test with mock rules + integration tests with mock rules that would test /status and /upgrade/\* endpoints in integration.
|
||||
|
||||
```Gherkin
|
||||
Given X prebuilt rules are installed in Kibana
|
||||
|
@ -648,27 +659,37 @@ And user should NOT see a number of rules available to upgrade
|
|||
And user should NOT see the Rule Updates table
|
||||
```
|
||||
|
||||
#### **Scenario: User can preview a rule before upgrading**
|
||||
#### **Scenario: User can preview rules available for upgrade**
|
||||
|
||||
```Gherkin
|
||||
Given there is at least one prebuilt rule installed in Kibana
|
||||
And for this rule there is a new version available
|
||||
And user is on the Rule Management page
|
||||
When user opens the Rule Updates table
|
||||
Then this rule should be displayed in the table
|
||||
When user opens the rule preview for this rule
|
||||
Then the preview should open
|
||||
When user closes the preview
|
||||
Then it should disappear
|
||||
```
|
||||
|
||||
#### **Scenario: User can upgrade a rule using the rule preview**
|
||||
|
||||
**Automation**: 1 e2e test
|
||||
|
||||
```Gherkin
|
||||
Given 2 prebuilt rules are installed in Kibana
|
||||
And for these 2 installed rules there are new versions available
|
||||
Given there is at least one prebuilt rule installed in Kibana
|
||||
And for this rule there is a new version available
|
||||
And user is on the Rule Management page
|
||||
When user opens the Rule Updates table
|
||||
Then all rules available for upgrade should be displayed in the table
|
||||
When user opens the rule preview for the 1st rule
|
||||
Then the preview should open
|
||||
When user closes the preview
|
||||
Then it should disappear
|
||||
When user opens the rule preview for the 2nd rule
|
||||
Then this rule should be displayed in the table
|
||||
When user opens the rule preview for this rule
|
||||
Then the preview should open
|
||||
When user upgrades the rule using a CTA in the rule preview
|
||||
Then the 2nd rule should be upgraded to the latest version
|
||||
Then the rule should be upgraded to the latest version
|
||||
And a success message should be displayed after upgrade
|
||||
And the 2nd rule should be removed from the Rule Updates table
|
||||
And user should see the number of rules available to upgrade as 1
|
||||
And the rule should be removed from the Rule Updates table
|
||||
And user should see the number of rules available to upgrade as initial number minus 1
|
||||
```
|
||||
|
||||
#### **Scenario: User can see correct rule information in preview before upgrading**
|
||||
|
|
|
@ -17,12 +17,13 @@ const StyledEuiBadge = styled(EuiBadge)`
|
|||
|
||||
interface BadgeListProps {
|
||||
badges: string[];
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
export const BadgeList = ({ badges }: BadgeListProps) => (
|
||||
<EuiFlexGroup responsive={false} gutterSize="xs" wrap>
|
||||
export const BadgeList = ({ badges, 'data-test-subj': dataTestSubj }: BadgeListProps) => (
|
||||
<EuiFlexGroup responsive={false} gutterSize="xs" wrap data-test-subj={dataTestSubj}>
|
||||
{badges.map((badge: string) => (
|
||||
<EuiFlexItem grow={false} key={`badge-${badge}`}>
|
||||
<EuiFlexItem grow={false} key={`badge-${badge}`} data-test-subj={`${dataTestSubj}Item`}>
|
||||
<StyledEuiBadge color="hollow">{badge}</StyledEuiBadge>
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
|
|
|
@ -71,9 +71,15 @@ interface AuthorProps {
|
|||
author: string[];
|
||||
}
|
||||
|
||||
const Author = ({ author }: AuthorProps) => <BadgeList badges={author} />;
|
||||
const Author = ({ author }: AuthorProps) => (
|
||||
<BadgeList badges={author} data-test-subj="authorPropertyValue" />
|
||||
);
|
||||
|
||||
const BuildingBlock = () => <EuiText size="s">{i18n.BUILDING_BLOCK_FIELD_DESCRIPTION}</EuiText>;
|
||||
const BuildingBlock = () => (
|
||||
<EuiText size="s" data-test-subj="buildingBlockPropertyValue">
|
||||
{i18n.BUILDING_BLOCK_FIELD_DESCRIPTION}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface SeverityMappingItemProps {
|
||||
severityMappingItem: SeverityMappingItemType;
|
||||
|
@ -86,7 +92,7 @@ const SeverityMappingItem = ({ severityMappingItem }: SeverityMappingItemProps)
|
|||
content={severityMappingItem.field}
|
||||
data-test-subj={`severityOverrideField-${severityMappingItem.value}`}
|
||||
>
|
||||
<>{`${severityMappingItem.field}:`}</>
|
||||
<span data-test-subj="severityOverrideField">{`${severityMappingItem.field}:`}</span>
|
||||
</EuiToolTip>
|
||||
</OverrideColumn>
|
||||
<OverrideValueColumn>
|
||||
|
@ -94,7 +100,9 @@ const SeverityMappingItem = ({ severityMappingItem }: SeverityMappingItemProps)
|
|||
content={severityMappingItem.value}
|
||||
data-test-subj={`severityOverrideValue-${severityMappingItem.value}`}
|
||||
>
|
||||
{defaultToEmptyTag(severityMappingItem.value)}
|
||||
<span data-test-subj="severityOverrideValue">
|
||||
{defaultToEmptyTag(severityMappingItem.value)}
|
||||
</span>
|
||||
</EuiToolTip>
|
||||
</OverrideValueColumn>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -102,7 +110,7 @@ const SeverityMappingItem = ({ severityMappingItem }: SeverityMappingItemProps)
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<SeverityBadge
|
||||
data-test-subj={`severityOverrideSeverity-${severityMappingItem.value}`}
|
||||
data-test-subj="severityOverrideSeverity"
|
||||
value={severityMappingItem.severity}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
@ -113,7 +121,11 @@ interface RiskScoreProps {
|
|||
riskScore: number;
|
||||
}
|
||||
|
||||
const RiskScore = ({ riskScore }: RiskScoreProps) => <EuiText size="s">{riskScore}</EuiText>;
|
||||
const RiskScore = ({ riskScore }: RiskScoreProps) => (
|
||||
<EuiText size="s" data-test-subj="riskScorePropertyValue">
|
||||
{riskScore}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface RiskScoreMappingItemProps {
|
||||
riskScoreMappingItem: RiskScoreMappingItemType;
|
||||
|
@ -126,13 +138,15 @@ const RiskScoreMappingItem = ({ riskScoreMappingItem }: RiskScoreMappingItemProp
|
|||
content={riskScoreMappingItem.field}
|
||||
data-test-subj={`riskScoreOverrideField-${riskScoreMappingItem.value}`}
|
||||
>
|
||||
<>{riskScoreMappingItem.field}</>
|
||||
<span data-test-subj="riskScoreOverridePropertyFieldName">
|
||||
{riskScoreMappingItem.field}
|
||||
</span>
|
||||
</EuiToolTip>
|
||||
</OverrideColumn>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type={'sortRight'} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>{ALERT_RISK_SCORE}</EuiFlexItem>
|
||||
<EuiFlexItem data-test-subj="riskScoreOverridePropertyOverride">{ALERT_RISK_SCORE}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
|
@ -161,7 +175,7 @@ const FalsePositives = ({ falsePositives }: { falsePositives: string[] }) => (
|
|||
<ul>
|
||||
{falsePositives.map((falsePositivesItem) => (
|
||||
<li
|
||||
data-test-subj="unorderedListArrayDescriptionItem"
|
||||
data-test-subj="falsePositivesPropertyValueItem"
|
||||
key={`falsePositives-${falsePositivesItem}`}
|
||||
>
|
||||
{falsePositivesItem}
|
||||
|
@ -176,21 +190,27 @@ interface InvestigationFieldsProps {
|
|||
}
|
||||
|
||||
const InvestigationFields = ({ investigationFields }: InvestigationFieldsProps) => (
|
||||
<BadgeList badges={investigationFields} />
|
||||
<BadgeList badges={investigationFields} data-test-subj="investigationFieldsPropertyValue" />
|
||||
);
|
||||
|
||||
interface LicenseProps {
|
||||
license: string;
|
||||
}
|
||||
|
||||
const License = ({ license }: LicenseProps) => <EuiText size="s">{license}</EuiText>;
|
||||
const License = ({ license }: LicenseProps) => (
|
||||
<EuiText size="s" data-test-subj="licensePropertyValue">
|
||||
{license}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface RuleNameOverrideProps {
|
||||
ruleNameOverride: string;
|
||||
}
|
||||
|
||||
const RuleNameOverride = ({ ruleNameOverride }: RuleNameOverrideProps) => (
|
||||
<EuiText size="s">{ruleNameOverride}</EuiText>
|
||||
<EuiText size="s" data-test-subj="ruleNameOverridePropertyValue">
|
||||
{ruleNameOverride}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface ThreatProps {
|
||||
|
@ -198,7 +218,7 @@ interface ThreatProps {
|
|||
}
|
||||
|
||||
const Threat = ({ threat }: ThreatProps) => (
|
||||
<ThreatEuiFlexGroup threat={filterEmptyThreats(threat)} label="" />
|
||||
<ThreatEuiFlexGroup threat={filterEmptyThreats(threat)} data-test-subj="threatPropertyValue" />
|
||||
);
|
||||
|
||||
interface ThreatIndicatorPathProps {
|
||||
|
@ -214,14 +234,18 @@ interface TimestampOverrideProps {
|
|||
}
|
||||
|
||||
const TimestampOverride = ({ timestampOverride }: TimestampOverrideProps) => (
|
||||
<EuiText size="s">{timestampOverride}</EuiText>
|
||||
<EuiText size="s" data-test-subj="timestampOverridePropertyValue">
|
||||
{timestampOverride}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface TagsProps {
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
const Tags = ({ tags }: TagsProps) => <BadgeList badges={tags} />;
|
||||
const Tags = ({ tags }: TagsProps) => (
|
||||
<BadgeList badges={tags} data-test-subj="tagsPropertyValue" />
|
||||
);
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
const prepareAboutSectionListItems = (
|
||||
|
@ -247,22 +271,24 @@ const prepareAboutSectionListItems = (
|
|||
|
||||
if (rule.author && rule.author.length > 0) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.AUTHOR_FIELD_LABEL,
|
||||
title: <span data-test-subj="authorPropertyTitle">{i18n.AUTHOR_FIELD_LABEL}</span>,
|
||||
description: <Author author={rule.author} />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.building_block_type) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.BUILDING_BLOCK_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="buildingBlockPropertyTitle">{i18n.BUILDING_BLOCK_FIELD_LABEL}</span>
|
||||
),
|
||||
description: <BuildingBlock />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.severity) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.SEVERITY_FIELD_LABEL,
|
||||
description: <SeverityBadge value={rule.severity} />,
|
||||
title: <span data-test-subj="severityPropertyTitle">{i18n.SEVERITY_FIELD_LABEL}</span>,
|
||||
description: <SeverityBadge value={rule.severity} data-test-subj="severityPropertyValue" />,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -272,7 +298,14 @@ const prepareAboutSectionListItems = (
|
|||
.filter((severityMappingItem) => severityMappingItem.field !== '')
|
||||
.map((severityMappingItem, index) => {
|
||||
return {
|
||||
title: index === 0 ? i18n.SEVERITY_MAPPING_FIELD_LABEL : '',
|
||||
title:
|
||||
index === 0 ? (
|
||||
<span data-test-subj="severityOverridePropertyTitle">
|
||||
{i18n.SEVERITY_MAPPING_FIELD_LABEL}
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
),
|
||||
description: <SeverityMappingItem severityMappingItem={severityMappingItem} />,
|
||||
};
|
||||
})
|
||||
|
@ -281,7 +314,7 @@ const prepareAboutSectionListItems = (
|
|||
|
||||
if (rule.risk_score) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.RISK_SCORE_FIELD_LABEL,
|
||||
title: <span data-test-subj="riskScorePropertyTitle">{i18n.RISK_SCORE_FIELD_LABEL}</span>,
|
||||
description: <RiskScore riskScore={rule.risk_score} />,
|
||||
});
|
||||
}
|
||||
|
@ -292,7 +325,14 @@ const prepareAboutSectionListItems = (
|
|||
.filter((riskScoreMappingItem) => riskScoreMappingItem.field !== '')
|
||||
.map((riskScoreMappingItem, index) => {
|
||||
return {
|
||||
title: index === 0 ? i18n.RISK_SCORE_MAPPING_FIELD_LABEL : '',
|
||||
title:
|
||||
index === 0 ? (
|
||||
<span data-test-subj="riskScoreOverridePropertyTitle">
|
||||
{i18n.RISK_SCORE_MAPPING_FIELD_LABEL}
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
),
|
||||
description: <RiskScoreMappingItem riskScoreMappingItem={riskScoreMappingItem} />,
|
||||
};
|
||||
})
|
||||
|
@ -301,21 +341,27 @@ const prepareAboutSectionListItems = (
|
|||
|
||||
if (rule.references && rule.references.length > 0) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.REFERENCES_FIELD_LABEL,
|
||||
title: <span data-test-subj="referencesPropertyTitle">{i18n.REFERENCES_FIELD_LABEL}</span>,
|
||||
description: <References references={rule.references} />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.false_positives && rule.false_positives.length > 0) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.FALSE_POSITIVES_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="falsePositivesPropertyTitle">{i18n.FALSE_POSITIVES_FIELD_LABEL}</span>
|
||||
),
|
||||
description: <FalsePositives falsePositives={rule.false_positives} />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.investigation_fields && rule.investigation_fields.field_names.length > 0) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.INVESTIGATION_FIELDS_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="investigationFieldsPropertyTitle">
|
||||
{i18n.INVESTIGATION_FIELDS_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: (
|
||||
<InvestigationFields investigationFields={rule.investigation_fields.field_names} />
|
||||
),
|
||||
|
@ -324,21 +370,25 @@ const prepareAboutSectionListItems = (
|
|||
|
||||
if (rule.license) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.LICENSE_FIELD_LABEL,
|
||||
title: <span data-test-subj="licensePropertyTitle">{i18n.LICENSE_FIELD_LABEL}</span>,
|
||||
description: <License license={rule.license} />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.rule_name_override) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.RULE_NAME_OVERRIDE_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="ruleNameOverridePropertyTitle">
|
||||
{i18n.RULE_NAME_OVERRIDE_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <RuleNameOverride ruleNameOverride={rule.rule_name_override} />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.threat && rule.threat.length > 0) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.THREAT_FIELD_LABEL,
|
||||
title: <span data-test-subj="threatPropertyTitle">{i18n.THREAT_FIELD_LABEL}</span>,
|
||||
description: <Threat threat={rule.threat} />,
|
||||
});
|
||||
}
|
||||
|
@ -352,14 +402,18 @@ const prepareAboutSectionListItems = (
|
|||
|
||||
if (rule.timestamp_override) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.TIMESTAMP_OVERRIDE_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="timestampOverridePropertyTitle">
|
||||
{i18n.TIMESTAMP_OVERRIDE_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <TimestampOverride timestampOverride={rule.timestamp_override} />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.tags && rule.tags.length > 0) {
|
||||
aboutSectionListItems.push({
|
||||
title: i18n.TAGS_FIELD_LABEL,
|
||||
title: <span data-test-subj="tagsPropertyTitle">{i18n.TAGS_FIELD_LABEL}</span>,
|
||||
description: <Tags tags={rule.tags} />,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -61,7 +61,9 @@ interface SavedQueryNameProps {
|
|||
}
|
||||
|
||||
const SavedQueryName = ({ savedQueryName }: SavedQueryNameProps) => (
|
||||
<EuiText size="s">{savedQueryName}</EuiText>
|
||||
<EuiText size="s" data-test-subj="savedQueryNamePropertyValue">
|
||||
{savedQueryName}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
const EuiBadgeWrap = styled(EuiBadge)`
|
||||
|
@ -74,9 +76,10 @@ interface FiltersProps {
|
|||
filters: Filter[];
|
||||
dataViewId?: string;
|
||||
index?: string[];
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
const Filters = ({ filters, dataViewId, index }: FiltersProps) => {
|
||||
const Filters = ({ filters, dataViewId, index, 'data-test-subj': dataTestSubj }: FiltersProps) => {
|
||||
const { indexPattern } = useRuleIndexPattern({
|
||||
dataSourceType: dataViewId ? DataSourceType.DataView : DataSourceType.IndexPatterns,
|
||||
index: index ?? [],
|
||||
|
@ -86,9 +89,14 @@ const Filters = ({ filters, dataViewId, index }: FiltersProps) => {
|
|||
const flattenedFilters = mapAndFlattenFilters(filters);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup wrap responsive={false} gutterSize="xs">
|
||||
<EuiFlexGroup wrap responsive={false} gutterSize="xs" data-test-subj={dataTestSubj}>
|
||||
{flattenedFilters.map((filter, idx) => (
|
||||
<EuiFlexItem grow={false} key={`filter-${idx}`} css={{ width: '100%' }}>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
key={`filter-${idx}`}
|
||||
css={{ width: '100%' }}
|
||||
data-test-subj={`filterItem-${filter.meta.key}`}
|
||||
>
|
||||
<EuiBadgeWrap color="hollow">
|
||||
{indexPattern != null ? (
|
||||
<FilterBadgeGroup filters={[filter]} dataViews={[indexPattern]} />
|
||||
|
@ -108,21 +116,30 @@ const QueryContent = styled.div`
|
|||
|
||||
interface QueryProps {
|
||||
query: string;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
const Query = ({ query }: QueryProps) => <QueryContent>{query}</QueryContent>;
|
||||
const Query = ({ query, 'data-test-subj': dataTestSubj = 'query' }: QueryProps) => (
|
||||
<QueryContent data-test-subj={dataTestSubj}>{query}</QueryContent>
|
||||
);
|
||||
|
||||
interface IndexProps {
|
||||
index: string[];
|
||||
}
|
||||
|
||||
const Index = ({ index }: IndexProps) => <BadgeList badges={index} />;
|
||||
const Index = ({ index }: IndexProps) => (
|
||||
<BadgeList badges={index} data-test-subj="indexPropertyValue" />
|
||||
);
|
||||
|
||||
interface DataViewIdProps {
|
||||
dataViewId: string;
|
||||
}
|
||||
|
||||
const DataViewId = ({ dataViewId }: DataViewIdProps) => <EuiText size="s">{dataViewId}</EuiText>;
|
||||
const DataViewId = ({ dataViewId }: DataViewIdProps) => (
|
||||
<EuiText size="s" data-test-subj="dataViewIdPropertyValue">
|
||||
{dataViewId}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface DataViewIndexPatternProps {
|
||||
dataViewId: string;
|
||||
|
@ -152,7 +169,11 @@ const DataViewIndexPattern = ({ dataViewId }: DataViewIndexPatternProps) => {
|
|||
return <EuiLoadingSpinner size="m" />;
|
||||
}
|
||||
|
||||
return <EuiText size="s">{indexPattern}</EuiText>;
|
||||
return (
|
||||
<EuiText size="s" data-test-subj="dataViewIndexPatternPropertyValue">
|
||||
{indexPattern}
|
||||
</EuiText>
|
||||
);
|
||||
};
|
||||
|
||||
interface ThresholdProps {
|
||||
|
@ -160,13 +181,13 @@ interface ThresholdProps {
|
|||
}
|
||||
|
||||
const Threshold = ({ threshold }: ThresholdProps) => (
|
||||
<>
|
||||
<div data-test-subj="thresholdPropertyValue">
|
||||
{isEmpty(threshold.field[0])
|
||||
? `${descriptionStepI18n.THRESHOLD_RESULTS_ALL} >= ${threshold.value}`
|
||||
: `${descriptionStepI18n.THRESHOLD_RESULTS_AGGREGATED_BY} ${
|
||||
Array.isArray(threshold.field) ? threshold.field.join(',') : threshold.field
|
||||
} >= ${threshold.value}`}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
|
||||
interface AnomalyThresholdProps {
|
||||
|
@ -174,7 +195,9 @@ interface AnomalyThresholdProps {
|
|||
}
|
||||
|
||||
const AnomalyThreshold = ({ anomalyThreshold }: AnomalyThresholdProps) => (
|
||||
<EuiText size="s">{anomalyThreshold}</EuiText>
|
||||
<EuiText size="s" data-test-subj="anomalyThresholdPropertyValue">
|
||||
{anomalyThreshold}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface MachineLearningJobListProps {
|
||||
|
@ -245,7 +268,7 @@ interface RequiredFieldsProps {
|
|||
}
|
||||
|
||||
const RequiredFields = ({ requiredFields }: RequiredFieldsProps) => (
|
||||
<EuiFlexGrid gutterSize={'s'}>
|
||||
<EuiFlexGrid gutterSize={'s'} data-test-subj="requiredFieldsPropertyValue">
|
||||
{requiredFields.map((rF, index) => (
|
||||
<EuiFlexItem grow={false} key={rF.name}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize={'xs'}>
|
||||
|
@ -257,7 +280,11 @@ const RequiredFields = ({ requiredFields }: RequiredFieldsProps) => (
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<StyledFieldTypeText grow={false} size={'s'}>
|
||||
<StyledFieldTypeText
|
||||
grow={false}
|
||||
size={'s'}
|
||||
data-test-subj="requiredFieldsPropertyValueItem"
|
||||
>
|
||||
{` ${rF.name}${index + 1 !== requiredFields.length ? ', ' : ''}`}
|
||||
</StyledFieldTypeText>
|
||||
</EuiFlexItem>
|
||||
|
@ -272,14 +299,18 @@ interface TimelineTitleProps {
|
|||
}
|
||||
|
||||
const TimelineTitle = ({ timelineTitle }: TimelineTitleProps) => (
|
||||
<EuiText size="s">{timelineTitle}</EuiText>
|
||||
<EuiText size="s" data-test-subj="timelineTemplatePropertyValue">
|
||||
{timelineTitle}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface ThreatIndexProps {
|
||||
threatIndex: string[];
|
||||
}
|
||||
|
||||
const ThreatIndex = ({ threatIndex }: ThreatIndexProps) => <BadgeList badges={threatIndex} />;
|
||||
const ThreatIndex = ({ threatIndex }: ThreatIndexProps) => (
|
||||
<BadgeList badges={threatIndex} data-test-subj="threatIndexPropertyValue" />
|
||||
);
|
||||
|
||||
interface ThreatMappingProps {
|
||||
threatMapping: ThreatMappingType;
|
||||
|
@ -312,7 +343,11 @@ const ThreatMapping = ({ threatMapping }: ThreatMappingProps) => {
|
|||
''
|
||||
);
|
||||
|
||||
return <EuiText size="s">{description}</EuiText>;
|
||||
return (
|
||||
<EuiText size="s" data-test-subj="threatMappingPropertyValue">
|
||||
{description}
|
||||
</EuiText>
|
||||
);
|
||||
};
|
||||
|
||||
interface AlertSuppressionTitleProps {
|
||||
|
@ -330,7 +365,7 @@ interface SuppressAlertsByFieldProps {
|
|||
}
|
||||
|
||||
const SuppressAlertsByField = ({ fields }: SuppressAlertsByFieldProps) => (
|
||||
<BadgeList badges={fields} />
|
||||
<BadgeList badges={fields} data-test-subj="alertSuppressionGroupByPropertyValue" />
|
||||
);
|
||||
|
||||
interface SuppressAlertsDurationProps {
|
||||
|
@ -342,7 +377,11 @@ const SuppressAlertsDuration = ({ duration }: SuppressAlertsDurationProps) => {
|
|||
? `${duration.value}${duration.unit}`
|
||||
: descriptionStepI18n.ALERT_SUPPRESSION_PER_RULE_EXECUTION;
|
||||
|
||||
return <EuiText size="s">{durationDescription}</EuiText>;
|
||||
return (
|
||||
<EuiText size="s" data-test-subj="alertSuppressionDurationPropertyValue">
|
||||
{durationDescription}
|
||||
</EuiText>
|
||||
);
|
||||
};
|
||||
|
||||
interface MissingFieldsStrategyProps {
|
||||
|
@ -355,7 +394,11 @@ const MissingFieldsStrategy = ({ missingFieldsStrategy }: MissingFieldsStrategyP
|
|||
? descriptionStepI18n.ALERT_SUPPRESSION_SUPPRESS_ON_MISSING_FIELDS
|
||||
: descriptionStepI18n.ALERT_SUPPRESSION_DO_NOT_SUPPRESS_ON_MISSING_FIELDS;
|
||||
|
||||
return <EuiText size="s">{missingFieldsDescription}</EuiText>;
|
||||
return (
|
||||
<EuiText size="s" data-test-subj="alertSuppressionSuppressionFieldPropertyValue">
|
||||
{missingFieldsDescription}
|
||||
</EuiText>
|
||||
);
|
||||
};
|
||||
|
||||
interface NewTermsFieldsProps {
|
||||
|
@ -363,7 +406,7 @@ interface NewTermsFieldsProps {
|
|||
}
|
||||
|
||||
const NewTermsFields = ({ newTermsFields }: NewTermsFieldsProps) => (
|
||||
<BadgeList badges={newTermsFields} />
|
||||
<BadgeList badges={newTermsFields} data-test-subj="newTermsFieldsPropertyValue" />
|
||||
);
|
||||
|
||||
interface HistoryWindowSizeProps {
|
||||
|
@ -373,7 +416,11 @@ interface HistoryWindowSizeProps {
|
|||
const HistoryWindowSize = ({ historyWindowStart }: HistoryWindowSizeProps) => {
|
||||
const size = historyWindowStart ? convertHistoryStartToSize(historyWindowStart) : '7d';
|
||||
|
||||
return <EuiText size="s">{size}</EuiText>;
|
||||
return (
|
||||
<EuiText size="s" data-test-subj={`newTermsWindowSizePropertyValue-${historyWindowStart}`}>
|
||||
{size}
|
||||
</EuiText>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
|
@ -386,7 +433,7 @@ const prepareDefinitionSectionListItems = (
|
|||
|
||||
if ('index' in rule && rule.index && rule.index.length > 0) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.INDEX_FIELD_LABEL,
|
||||
title: <span data-test-subj="indexPropertyTitle">{i18n.INDEX_FIELD_LABEL}</span>,
|
||||
description: <Index index={rule.index} />,
|
||||
});
|
||||
}
|
||||
|
@ -394,11 +441,17 @@ const prepareDefinitionSectionListItems = (
|
|||
if ('data_view_id' in rule && rule.data_view_id) {
|
||||
definitionSectionListItems.push(
|
||||
{
|
||||
title: i18n.DATA_VIEW_ID_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="dataViewIdPropertyTitle">{i18n.DATA_VIEW_ID_FIELD_LABEL}</span>
|
||||
),
|
||||
description: <DataViewId dataViewId={rule.data_view_id} />,
|
||||
},
|
||||
{
|
||||
title: i18n.DATA_VIEW_INDEX_PATTERN_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="dataViewIndexPatternPropertyTitle">
|
||||
{i18n.DATA_VIEW_INDEX_PATTERN_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <DataViewIndexPattern dataViewId={rule.data_view_id} />,
|
||||
}
|
||||
);
|
||||
|
@ -406,52 +459,86 @@ const prepareDefinitionSectionListItems = (
|
|||
|
||||
if (savedQuery) {
|
||||
definitionSectionListItems.push({
|
||||
title: descriptionStepI18n.SAVED_QUERY_NAME_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="savedQueryNamePropertyTitle">
|
||||
{descriptionStepI18n.SAVED_QUERY_NAME_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <SavedQueryName savedQueryName={savedQuery.attributes.title} />,
|
||||
});
|
||||
|
||||
if (savedQuery.attributes.filters) {
|
||||
definitionSectionListItems.push({
|
||||
title: descriptionStepI18n.SAVED_QUERY_FILTERS_LABEL,
|
||||
description: <Filters filters={savedQuery.attributes.filters as Filter[]} />,
|
||||
title: (
|
||||
<span data-test-subj="savedQueryFiltersPropertyTitle">
|
||||
{descriptionStepI18n.SAVED_QUERY_FILTERS_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: (
|
||||
<Filters
|
||||
filters={savedQuery.attributes.filters as Filter[]}
|
||||
data-test-subj="savedQueryFiltersPropertyValue"
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof savedQuery.attributes.query.query === 'string') {
|
||||
definitionSectionListItems.push({
|
||||
title: descriptionStepI18n.SAVED_QUERY_LABEL,
|
||||
description: <Query query={savedQuery.attributes.query.query} />,
|
||||
title: (
|
||||
<span data-test-subj="savedQueryContentPropertyTitle">
|
||||
{descriptionStepI18n.SAVED_QUERY_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: (
|
||||
<Query
|
||||
query={savedQuery.attributes.query.query}
|
||||
data-test-subj="savedQueryContentPropertyValue"
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ('filters' in rule && rule.filters?.length) {
|
||||
definitionSectionListItems.push({
|
||||
title: descriptionStepI18n.FILTERS_LABEL,
|
||||
title: <span data-test-subj="filtersPropertyTitle">{descriptionStepI18n.FILTERS_LABEL}</span>,
|
||||
description: (
|
||||
<Filters
|
||||
filters={rule.filters as Filter[]}
|
||||
dataViewId={rule.data_view_id}
|
||||
index={rule.index}
|
||||
data-test-subj="filtersPropertyValue"
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if ('query' in rule && rule.query) {
|
||||
let title = descriptionStepI18n.QUERY_LABEL;
|
||||
if (rule.type === 'saved_query') {
|
||||
title = descriptionStepI18n.SAVED_QUERY_LABEL;
|
||||
} else if (rule.type === 'eql') {
|
||||
title = descriptionStepI18n.EQL_QUERY_LABEL;
|
||||
if (rule.type === 'eql') {
|
||||
definitionSectionListItems.push({
|
||||
title: (
|
||||
<span data-test-subj="eqlQueryPropertyTitle">{descriptionStepI18n.EQL_QUERY_LABEL}</span>
|
||||
),
|
||||
description: <Query query={rule.query} data-test-subj="eqlQueryPropertyValue" />,
|
||||
});
|
||||
} else if (rule.type === 'esql') {
|
||||
title = descriptionStepI18n.ESQL_QUERY_LABEL;
|
||||
definitionSectionListItems.push({
|
||||
title: (
|
||||
<span data-test-subj="esqlQueryPropertyTitle">
|
||||
{descriptionStepI18n.ESQL_QUERY_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <Query query={rule.query} data-test-subj="esqlQueryPropertyValue" />,
|
||||
});
|
||||
} else {
|
||||
definitionSectionListItems.push({
|
||||
title: (
|
||||
<span data-test-subj="customQueryPropertyTitle">{descriptionStepI18n.QUERY_LABEL}</span>
|
||||
),
|
||||
description: <Query query={rule.query} data-test-subj="customQueryPropertyValue" />,
|
||||
});
|
||||
}
|
||||
|
||||
definitionSectionListItems.push({
|
||||
title,
|
||||
description: <Query query={rule.query} />,
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.type) {
|
||||
|
@ -463,14 +550,20 @@ const prepareDefinitionSectionListItems = (
|
|||
|
||||
if ('anomaly_threshold' in rule && rule.anomaly_threshold) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.ANOMALY_THRESHOLD_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="anomalyThresholdPropertyTitle">
|
||||
{i18n.ANOMALY_THRESHOLD_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <AnomalyThreshold anomalyThreshold={rule.anomaly_threshold} />,
|
||||
});
|
||||
}
|
||||
|
||||
if ('machine_learning_job_id' in rule) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.MACHINE_LEARNING_JOB_ID_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="mlJobPropertyTitle">{i18n.MACHINE_LEARNING_JOB_ID_FIELD_LABEL}</span>
|
||||
),
|
||||
description: (
|
||||
<MachineLearningJobList
|
||||
jobIds={rule.machine_learning_job_id as string[]}
|
||||
|
@ -482,22 +575,33 @@ const prepareDefinitionSectionListItems = (
|
|||
|
||||
if (rule.related_integrations && rule.related_integrations.length > 0) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.RELATED_INTEGRATIONS_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="relatedIntegrationsPropertyTitle">
|
||||
{i18n.RELATED_INTEGRATIONS_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: (
|
||||
<RelatedIntegrationsDescription relatedIntegrations={rule.related_integrations} />
|
||||
<RelatedIntegrationsDescription
|
||||
relatedIntegrations={rule.related_integrations}
|
||||
dataTestSubj="relatedIntegrationsPropertyValue"
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.required_fields && rule.required_fields.length > 0) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.REQUIRED_FIELDS_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="requiredFieldsPropertyTitle">{i18n.REQUIRED_FIELDS_FIELD_LABEL}</span>
|
||||
),
|
||||
description: <RequiredFields requiredFields={rule.required_fields} />,
|
||||
});
|
||||
}
|
||||
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.TIMELINE_TITLE_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="timelineTemplatePropertyTitle">{i18n.TIMELINE_TITLE_FIELD_LABEL}</span>
|
||||
),
|
||||
description: (
|
||||
<TimelineTitle timelineTitle={rule.timeline_title || timelinesI18n.DEFAULT_TIMELINE_TITLE} />
|
||||
),
|
||||
|
@ -505,33 +609,38 @@ const prepareDefinitionSectionListItems = (
|
|||
|
||||
if ('threshold' in rule && rule.threshold) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.THRESHOLD_FIELD_LABEL,
|
||||
title: <span data-test-subj="thresholdPropertyTitle">{i18n.THRESHOLD_FIELD_LABEL}</span>,
|
||||
description: <Threshold threshold={rule.threshold} />,
|
||||
});
|
||||
}
|
||||
|
||||
if ('threat_index' in rule && rule.threat_index) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.THREAT_INDEX_FIELD_LABEL,
|
||||
title: <span data-test-subj="threatIndexPropertyTitle">{i18n.THREAT_INDEX_FIELD_LABEL}</span>,
|
||||
description: <ThreatIndex threatIndex={rule.threat_index} />,
|
||||
});
|
||||
}
|
||||
|
||||
if ('threat_mapping' in rule && rule.threat_mapping) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.THREAT_MAPPING_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="threatMappingPropertyTitle">{i18n.THREAT_MAPPING_FIELD_LABEL}</span>
|
||||
),
|
||||
description: <ThreatMapping threatMapping={rule.threat_mapping} />,
|
||||
});
|
||||
}
|
||||
|
||||
if ('threat_filters' in rule && rule.threat_filters && rule.threat_filters.length > 0) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.THREAT_FILTERS_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="threatFiltersPropertyTitle">{i18n.THREAT_FILTERS_FIELD_LABEL}</span>
|
||||
),
|
||||
description: (
|
||||
<Filters
|
||||
filters={rule.threat_filters as Filter[]}
|
||||
dataViewId={rule.data_view_id}
|
||||
index={rule.index}
|
||||
data-test-subj="threatFiltersPropertyValue"
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
@ -539,24 +648,40 @@ const prepareDefinitionSectionListItems = (
|
|||
|
||||
if ('threat_query' in rule && rule.threat_query) {
|
||||
definitionSectionListItems.push({
|
||||
title: descriptionStepI18n.THREAT_QUERY_LABEL,
|
||||
description: <Query query={rule.threat_query} />,
|
||||
title: (
|
||||
<span data-test-subj="threatQueryPropertyTitle">
|
||||
{descriptionStepI18n.THREAT_QUERY_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <Query query={rule.threat_query} data-test-subj="threatQueryPropertyValue" />,
|
||||
});
|
||||
}
|
||||
|
||||
if ('alert_suppression' in rule && rule.alert_suppression) {
|
||||
definitionSectionListItems.push({
|
||||
title: <AlertSuppressionTitle title={i18n.SUPPRESS_ALERTS_BY_FIELD_LABEL} />,
|
||||
title: (
|
||||
<span data-test-subj="alertSuppressionGroupByPropertyTitle">
|
||||
<AlertSuppressionTitle title={i18n.SUPPRESS_ALERTS_BY_FIELD_LABEL} />
|
||||
</span>
|
||||
),
|
||||
description: <SuppressAlertsByField fields={rule.alert_suppression.group_by} />,
|
||||
});
|
||||
|
||||
definitionSectionListItems.push({
|
||||
title: <AlertSuppressionTitle title={i18n.SUPPRESS_ALERTS_DURATION_FIELD_LABEL} />,
|
||||
title: (
|
||||
<span data-test-subj="alertSuppressionDurationPropertyTitle">
|
||||
<AlertSuppressionTitle title={i18n.SUPPRESS_ALERTS_DURATION_FIELD_LABEL} />
|
||||
</span>
|
||||
),
|
||||
description: <SuppressAlertsDuration duration={rule.alert_suppression.duration} />,
|
||||
});
|
||||
|
||||
definitionSectionListItems.push({
|
||||
title: <AlertSuppressionTitle title={i18n.SUPPRESSION_FIELD_MISSING_FIELD_LABEL} />,
|
||||
title: (
|
||||
<span data-test-subj="alertSuppressionSuppressionFieldPropertyTitle">
|
||||
<AlertSuppressionTitle title={i18n.SUPPRESSION_FIELD_MISSING_FIELD_LABEL} />
|
||||
</span>
|
||||
),
|
||||
description: (
|
||||
<MissingFieldsStrategy
|
||||
missingFieldsStrategy={rule.alert_suppression.missing_fields_strategy}
|
||||
|
@ -567,14 +692,22 @@ const prepareDefinitionSectionListItems = (
|
|||
|
||||
if ('new_terms_fields' in rule && rule.new_terms_fields && rule.new_terms_fields.length > 0) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.NEW_TERMS_FIELDS_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="newTermsFieldsPropertyTitle">
|
||||
{i18n.NEW_TERMS_FIELDS_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <NewTermsFields newTermsFields={rule.new_terms_fields} />,
|
||||
});
|
||||
}
|
||||
|
||||
if ('history_window_start' in rule) {
|
||||
definitionSectionListItems.push({
|
||||
title: i18n.HISTORY_WINDOW_SIZE_FIELD_LABEL,
|
||||
title: (
|
||||
<span data-test-subj="newTermsWindowSizePropertyTitle">
|
||||
{i18n.HISTORY_WINDOW_SIZE_FIELD_LABEL}
|
||||
</span>
|
||||
),
|
||||
description: <HistoryWindowSize historyWindowStart={rule.history_window_start} />,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import styled from 'styled-components';
|
|||
import { css } from '@emotion/css';
|
||||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiTitle,
|
||||
EuiFlyout,
|
||||
|
@ -102,17 +101,15 @@ const TabContentPadding: React.FC = ({ children }) => (
|
|||
|
||||
interface RuleDetailsFlyoutProps {
|
||||
rule: RuleResponse;
|
||||
actionButtonLabel: string;
|
||||
isActionButtonDisabled: boolean;
|
||||
onActionButtonClick: (ruleId: string) => void;
|
||||
ruleActions?: React.ReactNode;
|
||||
dataTestSubj?: string;
|
||||
closeFlyout: () => void;
|
||||
}
|
||||
|
||||
export const RuleDetailsFlyout = ({
|
||||
rule,
|
||||
actionButtonLabel,
|
||||
isActionButtonDisabled,
|
||||
onActionButtonClick,
|
||||
ruleActions,
|
||||
dataTestSubj,
|
||||
closeFlyout,
|
||||
}: RuleDetailsFlyoutProps) => {
|
||||
const { expandedOverviewSections, toggleOverviewSection } = useOverviewTabSections();
|
||||
|
@ -176,6 +173,7 @@ export const RuleDetailsFlyout = ({
|
|||
ownFocus={false}
|
||||
key="prebuilt-rules-flyout"
|
||||
paddingSize="l"
|
||||
data-test-subj={dataTestSubj}
|
||||
>
|
||||
<EuiFlyoutHeader>
|
||||
<EuiTitle size="m">
|
||||
|
@ -197,18 +195,7 @@ export const RuleDetailsFlyout = ({
|
|||
{i18n.DISMISS_BUTTON_LABEL}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
disabled={isActionButtonDisabled}
|
||||
onClick={() => {
|
||||
onActionButtonClick(rule.rule_id ?? '');
|
||||
closeFlyout();
|
||||
}}
|
||||
fill
|
||||
>
|
||||
{actionButtonLabel}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>{ruleActions}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutFooter>
|
||||
</EuiFlyout>
|
||||
|
|
|
@ -16,7 +16,11 @@ interface IntervalProps {
|
|||
interval: string;
|
||||
}
|
||||
|
||||
const Interval = ({ interval }: IntervalProps) => <EuiText size="s">{interval}</EuiText>;
|
||||
const Interval = ({ interval }: IntervalProps) => (
|
||||
<EuiText size="s" data-test-subj="intervalPropertyValue">
|
||||
{interval}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
interface FromProps {
|
||||
from: string;
|
||||
|
@ -24,7 +28,9 @@ interface FromProps {
|
|||
}
|
||||
|
||||
const From = ({ from, interval }: FromProps) => (
|
||||
<EuiText size="s">{getHumanizedDuration(from, interval)}</EuiText>
|
||||
<EuiText size="s" data-test-subj={`fromPropertyValue-${from}`}>
|
||||
{getHumanizedDuration(from, interval)}
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
export interface RuleScheduleSectionProps extends React.ComponentProps<typeof EuiDescriptionList> {
|
||||
|
@ -43,11 +49,11 @@ export const RuleScheduleSection = ({
|
|||
|
||||
ruleSectionListItems.push(
|
||||
{
|
||||
title: i18n.INTERVAL_FIELD_LABEL,
|
||||
title: <span data-test-subj="intervalPropertyTitle">{i18n.INTERVAL_FIELD_LABEL}</span>,
|
||||
description: <Interval interval={rule.interval} />,
|
||||
},
|
||||
{
|
||||
title: i18n.FROM_FIELD_LABEL,
|
||||
title: <span data-test-subj="fromPropertyTitle">{i18n.FROM_FIELD_LABEL}</span>,
|
||||
description: <From from={rule.from} interval={rule.interval} />,
|
||||
}
|
||||
);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import { useFetchPrebuiltRulesStatusQuery } from '../../../../rule_management/api/hooks/prebuilt_rules/use_fetch_prebuilt_rules_status_query';
|
||||
import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages';
|
||||
import type { RuleSignatureId } from '../../../../../../common/api/detection_engine';
|
||||
|
@ -232,10 +233,21 @@ export const AddPrebuiltRulesTableContextProvider = ({
|
|||
{previewedRule && (
|
||||
<RuleDetailsFlyout
|
||||
rule={previewedRule}
|
||||
actionButtonLabel={i18n.INSTALL_BUTTON_LABEL}
|
||||
isActionButtonDisabled={canPreviewedRuleBeInstalled}
|
||||
onActionButtonClick={installOneRule}
|
||||
dataTestSubj="installPrebuiltRulePreview"
|
||||
closeFlyout={closeRulePreview}
|
||||
ruleActions={
|
||||
<EuiButton
|
||||
disabled={canPreviewedRuleBeInstalled}
|
||||
onClick={() => {
|
||||
installOneRule(previewedRule.rule_id ?? '');
|
||||
closeRulePreview();
|
||||
}}
|
||||
fill
|
||||
data-test-subj="installPrebuiltRuleFromFlyoutButton"
|
||||
>
|
||||
{i18n.INSTALL_BUTTON_LABEL}
|
||||
</EuiButton>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages';
|
||||
import { useInstalledSecurityJobs } from '../../../../../common/components/ml/hooks/use_installed_security_jobs';
|
||||
import { useBoolState } from '../../../../../common/hooks/use_bool_state';
|
||||
|
@ -270,10 +271,21 @@ export const UpgradePrebuiltRulesTableContextProvider = ({
|
|||
{previewedRule && (
|
||||
<RuleDetailsFlyout
|
||||
rule={previewedRule}
|
||||
actionButtonLabel={i18n.UPDATE_BUTTON_LABEL}
|
||||
isActionButtonDisabled={canPreviewedRuleBeUpgraded}
|
||||
onActionButtonClick={upgradeOneRule}
|
||||
dataTestSubj="updatePrebuiltRulePreview"
|
||||
closeFlyout={closeRulePreview}
|
||||
ruleActions={
|
||||
<EuiButton
|
||||
disabled={canPreviewedRuleBeUpgraded}
|
||||
onClick={() => {
|
||||
upgradeOneRule(previewedRule.rule_id ?? '');
|
||||
closeRulePreview();
|
||||
}}
|
||||
fill
|
||||
data-test-subj="updatePrebuiltRuleFromFlyoutButton"
|
||||
>
|
||||
{i18n.UPDATE_BUTTON_LABEL}
|
||||
</EuiButton>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -25,7 +25,7 @@ import React from 'react';
|
|||
import styled from 'styled-components';
|
||||
import { FieldIcon } from '@kbn/react-field';
|
||||
|
||||
import type { ThreatMapping, Type } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import type { ThreatMapping, Type, Threats } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import { FilterBadgeGroup } from '@kbn/unified-search-plugin/public';
|
||||
import type {
|
||||
RequiredFieldArray,
|
||||
|
@ -40,7 +40,7 @@ import * as i18nSeverity from '../severity_mapping/translations';
|
|||
import * as i18nRiskScore from '../risk_score_mapping/translations';
|
||||
|
||||
import * as i18n from './translations';
|
||||
import type { BuildQueryBarDescription, BuildThreatDescription, ListItems } from './types';
|
||||
import type { BuildQueryBarDescription, ListItems } from './types';
|
||||
import { SeverityBadge } from '../severity_badge';
|
||||
import type {
|
||||
AboutStepRiskScore,
|
||||
|
@ -163,12 +163,20 @@ export const buildEqlOptionsDescription = (eqlOptions: EqlOptionsSelected): List
|
|||
return items;
|
||||
};
|
||||
|
||||
export const buildThreatDescription = ({ label, threat }: BuildThreatDescription): ListItems[] => {
|
||||
interface BuildThreatDescriptionProps {
|
||||
label: string;
|
||||
threat: Threats;
|
||||
}
|
||||
|
||||
export const buildThreatDescription = ({
|
||||
threat,
|
||||
label,
|
||||
}: BuildThreatDescriptionProps): ListItems[] => {
|
||||
if (threat.length > 0) {
|
||||
return [
|
||||
{
|
||||
title: label,
|
||||
description: <ThreatEuiFlexGroup label={label} threat={threat} />,
|
||||
description: <ThreatEuiFlexGroup threat={threat} />,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -40,7 +40,10 @@ const TechniqueLinkItem = styled(EuiButtonEmpty)`
|
|||
align-self: flex-start;
|
||||
`;
|
||||
|
||||
export const ThreatEuiFlexGroup = ({ label, threat }: BuildThreatDescription) => {
|
||||
export const ThreatEuiFlexGroup = ({
|
||||
threat,
|
||||
'data-test-subj': dataTestSubj = 'threat',
|
||||
}: BuildThreatDescription) => {
|
||||
const [techniquesOptions, setTechniquesOptions] = useState<MitreTechnique[]>([]);
|
||||
const [tacticsOptions, setTacticsOptions] = useState<MitreTactic[]>([]);
|
||||
const [subtechniquesOptions, setSubtechniquesOptions] = useState<MitreSubTechnique[]>([]);
|
||||
|
@ -54,8 +57,9 @@ export const ThreatEuiFlexGroup = ({ label, threat }: BuildThreatDescription) =>
|
|||
}
|
||||
getMitre();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ThreatEuiFlexGroupStyles direction="column">
|
||||
<ThreatEuiFlexGroupStyles direction="column" data-test-subj={dataTestSubj}>
|
||||
{threat.map((singleThreat, index) => {
|
||||
const tactic = tacticsOptions.find((t) => t.id === singleThreat.tactic.id);
|
||||
return (
|
||||
|
|
|
@ -27,6 +27,6 @@ export interface BuildQueryBarDescription {
|
|||
}
|
||||
|
||||
export interface BuildThreatDescription {
|
||||
label: string;
|
||||
threat: Threats;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
|
|
@ -21,11 +21,12 @@ const Wrapper = styled.div`
|
|||
overflow: hidden;
|
||||
`;
|
||||
|
||||
export const IntegrationDescriptionComponent: React.FC<{ integration: IntegrationDetails }> = ({
|
||||
integration,
|
||||
}) => {
|
||||
export const IntegrationDescriptionComponent: React.FC<{
|
||||
integration: IntegrationDetails;
|
||||
dataTestSubj?: string;
|
||||
}> = ({ integration, dataTestSubj = 'integrationDescription' }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Wrapper data-test-subj={`${dataTestSubj}-${integration.packageName}`}>
|
||||
<IntegrationLink integration={integration} />{' '}
|
||||
<IntegrationStatusBadge integration={integration} />
|
||||
<IntegrationVersionMismatchIcon integration={integration} />
|
||||
|
@ -37,7 +38,8 @@ export const IntegrationDescription = React.memo(IntegrationDescriptionComponent
|
|||
|
||||
export const RelatedIntegrationsDescription: React.FC<{
|
||||
relatedIntegrations: RelatedIntegrationArray;
|
||||
}> = ({ relatedIntegrations }) => {
|
||||
dataTestSubj?: string;
|
||||
}> = ({ relatedIntegrations, dataTestSubj = 'relatedIntegrationsDescription' }) => {
|
||||
const { integrations } = useRelatedIntegrations(relatedIntegrations);
|
||||
|
||||
return (
|
||||
|
@ -46,6 +48,7 @@ export const RelatedIntegrationsDescription: React.FC<{
|
|||
<IntegrationDescription
|
||||
key={`${integration.packageName}-${index}`}
|
||||
integration={integration}
|
||||
dataTestSubj={dataTestSubj}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
|
|
|
@ -22,14 +22,22 @@ const severityToColorMap: Record<Severity, string> = {
|
|||
|
||||
interface Props {
|
||||
value: Severity;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
const SeverityBadgeComponent: React.FC<Props> = ({ value }) => {
|
||||
const SeverityBadgeComponent: React.FC<Props> = ({
|
||||
value,
|
||||
'data-test-subj': dataTestSubj = 'severity',
|
||||
}) => {
|
||||
const displayValue = upperFirst(value);
|
||||
const color = severityToColorMap[value] ?? 'subdued';
|
||||
|
||||
return (
|
||||
<HealthTruncateText healthColor={color} tooltipContent={displayValue} dataTestSubj="severity">
|
||||
<HealthTruncateText
|
||||
healthColor={color}
|
||||
tooltipContent={displayValue}
|
||||
dataTestSubj={dataTestSubj}
|
||||
>
|
||||
{displayValue}
|
||||
</HealthTruncateText>
|
||||
);
|
||||
|
|
|
@ -205,7 +205,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
);
|
||||
expect(await rulePageDescription.getVisibleText()).to.be(data[0].rule.rationale);
|
||||
|
||||
const severity = await testSubjects.find('severity');
|
||||
const severity = await testSubjects.find('severityPropertyValue');
|
||||
expect(await severity.getVisibleText()).to.be('Low');
|
||||
|
||||
const referenceUrls = await testSubjects.find('urlsDescriptionReferenceLinkItem');
|
||||
|
|
|
@ -24,14 +24,16 @@ import {
|
|||
import { cleanKibana } from '../../../tasks/common';
|
||||
import { login } from '../../../tasks/login';
|
||||
import {
|
||||
addElasticRulesButtonClick,
|
||||
clickAddElasticRulesButton,
|
||||
assertInstallationRequestIsComplete,
|
||||
interceptInstallationRequestToFail,
|
||||
interceptUpgradeRequestToFail,
|
||||
assertUpgradeFailure,
|
||||
ruleUpdatesTabClick,
|
||||
assertInstallationFailure,
|
||||
clickRuleUpdatesTab,
|
||||
assertUpgradeRequestIsComplete,
|
||||
assertRuleInstallationFailureToastShown,
|
||||
assertRulesPresentInAddPrebuiltRulesTable,
|
||||
assertRuleUpgradeFailureToastShown,
|
||||
assertRulesPresentInRuleUpdatesTable,
|
||||
} from '../../../tasks/prebuilt_rules';
|
||||
import { visitRulesManagementTable } from '../../../tasks/rules_management';
|
||||
|
||||
|
@ -64,7 +66,7 @@ describe(
|
|||
|
||||
it('installing prebuilt rules one by one', () => {
|
||||
// Navigate to install Elastic rules page
|
||||
addElasticRulesButtonClick();
|
||||
clickAddElasticRulesButton();
|
||||
|
||||
// Intercept and force the installation request to fail
|
||||
interceptInstallationRequestToFail([RULE_1]);
|
||||
|
@ -74,34 +76,38 @@ describe(
|
|||
// Wait for request to complete
|
||||
assertInstallationRequestIsComplete([RULE_1]);
|
||||
|
||||
assertInstallationFailure([RULE_1]);
|
||||
assertRuleInstallationFailureToastShown([RULE_1]);
|
||||
assertRulesPresentInAddPrebuiltRulesTable([RULE_1]);
|
||||
});
|
||||
|
||||
it('installing multiple selected prebuilt rules by selecting them individually', () => {
|
||||
addElasticRulesButtonClick();
|
||||
clickAddElasticRulesButton();
|
||||
|
||||
interceptInstallationRequestToFail([RULE_1, RULE_2]);
|
||||
selectRulesByName([RULE_1['security-rule'].name, RULE_2['security-rule'].name]);
|
||||
cy.get(INSTALL_SELECTED_RULES_BUTTON).click();
|
||||
assertInstallationRequestIsComplete([RULE_1, RULE_2]);
|
||||
assertInstallationFailure([RULE_1, RULE_2]);
|
||||
assertRuleInstallationFailureToastShown([RULE_1, RULE_2]);
|
||||
assertRulesPresentInAddPrebuiltRulesTable([RULE_1, RULE_2]);
|
||||
});
|
||||
|
||||
it('installing multiple selected prebuilt rules by selecting all in page', () => {
|
||||
addElasticRulesButtonClick();
|
||||
clickAddElasticRulesButton();
|
||||
interceptInstallationRequestToFail([RULE_1, RULE_2]);
|
||||
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click();
|
||||
cy.get(INSTALL_SELECTED_RULES_BUTTON).click();
|
||||
assertInstallationRequestIsComplete([RULE_1, RULE_2]);
|
||||
assertInstallationFailure([RULE_1, RULE_2]);
|
||||
assertRuleInstallationFailureToastShown([RULE_1, RULE_2]);
|
||||
assertRulesPresentInAddPrebuiltRulesTable([RULE_1, RULE_2]);
|
||||
});
|
||||
|
||||
it('installing all available rules at once', () => {
|
||||
addElasticRulesButtonClick();
|
||||
clickAddElasticRulesButton();
|
||||
interceptInstallationRequestToFail([RULE_1, RULE_2]);
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).click();
|
||||
assertInstallationRequestIsComplete([RULE_1, RULE_2]);
|
||||
assertInstallationFailure([RULE_1, RULE_2]);
|
||||
assertRuleInstallationFailureToastShown([RULE_1, RULE_2]);
|
||||
assertRulesPresentInAddPrebuiltRulesTable([RULE_1, RULE_2]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -141,7 +147,7 @@ describe(
|
|||
interceptUpgradeRequestToFail([OUTDATED_RULE_1]);
|
||||
|
||||
// Navigate to Rule Upgrade table
|
||||
ruleUpdatesTabClick();
|
||||
clickRuleUpdatesTab();
|
||||
|
||||
// Attempt to upgrade rule
|
||||
cy.get(
|
||||
|
@ -150,14 +156,15 @@ describe(
|
|||
// Wait for request to complete
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1]);
|
||||
|
||||
assertUpgradeFailure([OUTDATED_RULE_1]);
|
||||
assertRuleUpgradeFailureToastShown([OUTDATED_RULE_1]);
|
||||
assertRulesPresentInRuleUpdatesTable([OUTDATED_RULE_1]);
|
||||
});
|
||||
|
||||
it('upgrading multiple selected prebuilt rules by selecting them individually', () => {
|
||||
interceptUpgradeRequestToFail([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
|
||||
// Navigate to Rule Upgrade table
|
||||
ruleUpdatesTabClick();
|
||||
clickRuleUpdatesTab();
|
||||
|
||||
selectRulesByName([
|
||||
OUTDATED_RULE_1['security-rule'].name,
|
||||
|
@ -165,29 +172,32 @@ describe(
|
|||
]);
|
||||
cy.get(UPGRADE_SELECTED_RULES_BUTTON).click();
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertUpgradeFailure([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRuleUpgradeFailureToastShown([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRulesPresentInRuleUpdatesTable([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
});
|
||||
|
||||
it('upgrading multiple selected prebuilt rules by selecting all in page', () => {
|
||||
interceptUpgradeRequestToFail([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
|
||||
// Navigate to Rule Upgrade table
|
||||
ruleUpdatesTabClick();
|
||||
clickRuleUpdatesTab();
|
||||
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click();
|
||||
cy.get(UPGRADE_SELECTED_RULES_BUTTON).click();
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertUpgradeFailure([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRuleUpgradeFailureToastShown([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRulesPresentInRuleUpdatesTable([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
});
|
||||
|
||||
it('upgrading all rules with available upgrades at once', () => {
|
||||
interceptUpgradeRequestToFail([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
|
||||
// Navigate to Rule Upgrade table
|
||||
ruleUpdatesTabClick();
|
||||
clickRuleUpdatesTab();
|
||||
|
||||
cy.get(UPGRADE_ALL_RULES_BUTTON).click();
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertUpgradeFailure([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRuleUpgradeFailureToastShown([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRulesPresentInRuleUpdatesTable([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/commo
|
|||
import { INSTALL_ALL_RULES_BUTTON, TOASTER } from '../../../screens/alerts_detection_rules';
|
||||
import { getRuleAssets } from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { addElasticRulesButtonClick } from '../../../tasks/prebuilt_rules';
|
||||
import { clickAddElasticRulesButton } from '../../../tasks/prebuilt_rules';
|
||||
import { visitRulesManagementTable } from '../../../tasks/rules_management';
|
||||
|
||||
describe(
|
||||
|
@ -86,7 +86,7 @@ describe(
|
|||
);
|
||||
|
||||
const numberOfRulesToInstall = new Set(ruleIds).size;
|
||||
addElasticRulesButtonClick();
|
||||
clickAddElasticRulesButton();
|
||||
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).should('be.enabled').click();
|
||||
cy.wait('@installPrebuiltRules', {
|
||||
|
|
|
@ -18,12 +18,14 @@ import {
|
|||
TOASTER,
|
||||
} from '../../../screens/alerts_detection_rules';
|
||||
import { selectRulesByName } from '../../../tasks/alerts_detection_rules';
|
||||
import { RULE_MANAGEMENT_PAGE_BREADCRUMB } from '../../../screens/breadcrumbs';
|
||||
import { installPrebuiltRuleAssets } from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { login } from '../../../tasks/login';
|
||||
import {
|
||||
addElasticRulesButtonClick,
|
||||
assertInstallationSuccess,
|
||||
assertInstallationRequestIsComplete,
|
||||
assertRuleInstallationSuccessToastShown,
|
||||
assertRulesPresentInInstalledRulesTable,
|
||||
clickAddElasticRulesButton,
|
||||
} from '../../../tasks/prebuilt_rules';
|
||||
import { visitRulesManagementTable } from '../../../tasks/rules_management';
|
||||
|
||||
|
@ -49,7 +51,7 @@ describe(
|
|||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform').as(
|
||||
'installPrebuiltRules'
|
||||
);
|
||||
addElasticRulesButtonClick();
|
||||
clickAddElasticRulesButton();
|
||||
});
|
||||
|
||||
it('should install prebuilt rules one by one', () => {
|
||||
|
@ -58,27 +60,39 @@ describe(
|
|||
// Wait for request to complete
|
||||
assertInstallationRequestIsComplete([RULE_1]);
|
||||
// Assert installation succeeded
|
||||
assertInstallationSuccess([RULE_1]);
|
||||
assertRuleInstallationSuccessToastShown([RULE_1]);
|
||||
// Go back to rules table and assert that the rules are installed
|
||||
cy.get(RULE_MANAGEMENT_PAGE_BREADCRUMB).click();
|
||||
assertRulesPresentInInstalledRulesTable([RULE_1]);
|
||||
});
|
||||
|
||||
it('should install multiple selected prebuilt rules by selecting them individually', () => {
|
||||
selectRulesByName([RULE_1['security-rule'].name, RULE_2['security-rule'].name]);
|
||||
cy.get(INSTALL_SELECTED_RULES_BUTTON).click();
|
||||
assertInstallationRequestIsComplete([RULE_1, RULE_2]);
|
||||
assertInstallationSuccess([RULE_1, RULE_2]);
|
||||
assertRuleInstallationSuccessToastShown([RULE_1, RULE_2]);
|
||||
// Go back to rules table and assert that the rules are installed
|
||||
cy.get(RULE_MANAGEMENT_PAGE_BREADCRUMB).click();
|
||||
assertRulesPresentInInstalledRulesTable([RULE_1, RULE_2]);
|
||||
});
|
||||
|
||||
it('should install multiple selected prebuilt rules by selecting all in page', () => {
|
||||
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click();
|
||||
cy.get(INSTALL_SELECTED_RULES_BUTTON).click();
|
||||
assertInstallationRequestIsComplete([RULE_1, RULE_2]);
|
||||
assertInstallationSuccess([RULE_1, RULE_2]);
|
||||
assertRuleInstallationSuccessToastShown([RULE_1, RULE_2]);
|
||||
// Go back to rules table and assert that the rules are installed
|
||||
cy.get(RULE_MANAGEMENT_PAGE_BREADCRUMB).click();
|
||||
assertRulesPresentInInstalledRulesTable([RULE_1, RULE_2]);
|
||||
});
|
||||
|
||||
it('should install all available rules at once', () => {
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).click();
|
||||
assertInstallationRequestIsComplete([RULE_1, RULE_2]);
|
||||
assertInstallationSuccess([RULE_1, RULE_2]);
|
||||
assertRuleInstallationSuccessToastShown([RULE_1, RULE_2]);
|
||||
// Go back to rules table and assert that the rules are installed
|
||||
cy.get(RULE_MANAGEMENT_PAGE_BREADCRUMB).click();
|
||||
assertRulesPresentInInstalledRulesTable([RULE_1, RULE_2]);
|
||||
});
|
||||
|
||||
it('should display an empty screen when all available prebuilt rules have been installed', () => {
|
File diff suppressed because it is too large
Load diff
|
@ -22,9 +22,10 @@ import {
|
|||
import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import { login } from '../../../tasks/login';
|
||||
import {
|
||||
ruleUpdatesTabClick,
|
||||
assertRulesNotPresentInRuleUpdatesTable,
|
||||
assertRuleUpgradeSuccessToastShown,
|
||||
assertUpgradeRequestIsComplete,
|
||||
assertUpgradeSuccess,
|
||||
clickRuleUpdatesTab,
|
||||
} from '../../../tasks/prebuilt_rules';
|
||||
import { visitRulesManagementTable } from '../../../tasks/rules_management';
|
||||
|
||||
|
@ -68,7 +69,7 @@ describe(
|
|||
installPrebuiltRuleAssets([UPDATED_RULE_1, UPDATED_RULE_2]);
|
||||
|
||||
visitRulesManagementTable();
|
||||
ruleUpdatesTabClick();
|
||||
clickRuleUpdatesTab();
|
||||
});
|
||||
|
||||
it('should upgrade prebuilt rules one by one', () => {
|
||||
|
@ -79,7 +80,8 @@ describe(
|
|||
// Wait for request to complete
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1]);
|
||||
|
||||
assertUpgradeSuccess([OUTDATED_RULE_1]);
|
||||
assertRuleUpgradeSuccessToastShown([OUTDATED_RULE_1]);
|
||||
assertRulesNotPresentInRuleUpdatesTable([OUTDATED_RULE_1]);
|
||||
});
|
||||
|
||||
it('should upgrade multiple selected prebuilt rules by selecting them individually', () => {
|
||||
|
@ -89,20 +91,23 @@ describe(
|
|||
]);
|
||||
cy.get(UPGRADE_SELECTED_RULES_BUTTON).click();
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertUpgradeSuccess([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRuleUpgradeSuccessToastShown([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRulesNotPresentInRuleUpdatesTable([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
});
|
||||
|
||||
it('should upgrade multiple selected prebuilt rules by selecting all in page', () => {
|
||||
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click();
|
||||
cy.get(UPGRADE_SELECTED_RULES_BUTTON).click();
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertUpgradeSuccess([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRuleUpgradeSuccessToastShown([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRulesNotPresentInRuleUpdatesTable([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
});
|
||||
|
||||
it('should upgrade all rules with available upgrades at once', () => {
|
||||
cy.get(UPGRADE_ALL_RULES_BUTTON).click();
|
||||
assertUpgradeRequestIsComplete([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertUpgradeSuccess([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRuleUpgradeSuccessToastShown([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
assertRulesNotPresentInRuleUpdatesTable([OUTDATED_RULE_1, OUTDATED_RULE_2]);
|
||||
});
|
||||
|
||||
it('should display an empty screen when all rules with available updates have been upgraded', () => {
|
|
@ -191,3 +191,151 @@ export const NO_RULES_AVAILABLE_FOR_INSTALL_MESSAGE =
|
|||
'[data-test-subj="noPrebuiltRulesAvailableForInstall"]';
|
||||
export const NO_RULES_AVAILABLE_FOR_UPGRADE_MESSAGE =
|
||||
'[data-test-subj="noPrebuiltRulesAvailableForUpgrade"]';
|
||||
|
||||
export const INSTALL_PREBUILT_RULE_PREVIEW = '[data-test-subj="installPrebuiltRulePreview"]';
|
||||
export const INSTALL_PREBUILT_RULE_BUTTON =
|
||||
'[data-test-subj="installPrebuiltRuleFromFlyoutButton"]';
|
||||
|
||||
export const UPDATE_PREBUILT_RULE_PREVIEW = '[data-test-subj="updatePrebuiltRulePreview"]';
|
||||
export const UPDATE_PREBUILT_RULE_BUTTON = '[data-test-subj="updatePrebuiltRuleFromFlyoutButton"]';
|
||||
|
||||
export const FLYOUT_CLOSE_BTN = '[data-test-subj="euiFlyoutCloseButton"]';
|
||||
|
||||
export const AUTHOR_PROPERTY_TITLE = '[data-test-subj="authorPropertyTitle"]';
|
||||
export const AUTHOR_PROPERTY_VALUE_ITEM = '[data-test-subj="authorPropertyValueItem"]';
|
||||
|
||||
export const BUILDING_BLOCK_TITLE = '[data-test-subj="buildingBlockPropertyTitle"]';
|
||||
export const BUILDING_BLOCK_VALUE = '[data-test-subj="buildingBlockPropertyValue"]';
|
||||
|
||||
export const SEVERITY_TITLE = '[data-test-subj="severityPropertyTitle"]';
|
||||
export const SEVERITY_VALUE = '[data-test-subj="severityPropertyValue"]';
|
||||
|
||||
export const SEVERITY_MAPPING_TITLE = '[data-test-subj="severityOverridePropertyTitle"]';
|
||||
export const SEVERITY_MAPPING_VALUE_FIELD = '[data-test-subj="severityOverrideField"]';
|
||||
export const SEVERITY_MAPPING_VALUE_VALUE = '[data-test-subj="severityOverrideValue"]';
|
||||
export const SEVERITY_MAPPING_VALUE_SEVERITY = '[data-test-subj="severityOverrideSeverity"]';
|
||||
|
||||
export const RISK_SCORE_TITLE = '[data-test-subj="riskScorePropertyTitle"]';
|
||||
export const RISK_SCORE_VALUE = '[data-test-subj="riskScorePropertyValue"]';
|
||||
|
||||
export const RISK_SCORE_MAPPING_TITLE = '[data-test-subj="riskScoreOverridePropertyTitle"]';
|
||||
export const RISK_SCORE_MAPPING_VALUE_FIELD_NAME =
|
||||
'[data-test-subj="riskScoreOverridePropertyFieldName"]';
|
||||
export const RISK_SCORE_MAPPING_VALUE_OVERRIDE_NAME =
|
||||
'[data-test-subj="riskScoreOverridePropertyOverride"]';
|
||||
|
||||
export const REFERENCES_TITLE = '[data-test-subj="referencesPropertyTitle"]';
|
||||
export const REFERENCES_VALUE_ITEM = '[data-test-subj="urlsDescriptionReferenceLinkItem"]';
|
||||
|
||||
export const FALSE_POSITIVES_TITLE = '[data-test-subj="falsePositivesPropertyTitle"]';
|
||||
export const FALSE_POSITIVES_VALUE_ITEM = '[data-test-subj="falsePositivesPropertyValueItem"]';
|
||||
|
||||
export const INVESTIGATION_FIELDS_TITLE = '[data-test-subj="investigationFieldsPropertyTitle"]';
|
||||
export const INVESTIGATION_FIELDS_VALUE_ITEM =
|
||||
'[data-test-subj="investigationFieldsPropertyValueItem"]';
|
||||
|
||||
export const LICENSE_TITLE = '[data-test-subj="licensePropertyTitle"]';
|
||||
export const LICENSE_VALUE = '[data-test-subj="licensePropertyValue"]';
|
||||
|
||||
export const RULE_NAME_OVERRIDE_TITLE = '[data-test-subj="ruleNameOverridePropertyTitle"]';
|
||||
export const RULE_NAME_OVERRIDE_VALUE = '[data-test-subj="ruleNameOverridePropertyValue"]';
|
||||
|
||||
export const THREAT_TITLE = '[data-test-subj="threatPropertyTitle"]';
|
||||
export const THREAT_TACTIC = '[data-test-subj="threatTacticLink"]';
|
||||
|
||||
export const TIMESTAMP_OVERRIDE_TITLE = '[data-test-subj="timestampOverridePropertyTitle"]';
|
||||
export const TIMESTAMP_OVERRIDE_VALUE = '[data-test-subj="timestampOverridePropertyValue"]';
|
||||
|
||||
export const TAGS_PROPERTY_TITLE = '[data-test-subj="tagsPropertyTitle"]';
|
||||
export const TAGS_PROPERTY_VALUE_ITEM = '[data-test-subj="tagsPropertyValueItem"]';
|
||||
|
||||
export const RELATED_INTEGRATIONS_TITLE = '[data-test-subj="relatedIntegrationsPropertyTitle"]';
|
||||
export const RELATED_INTEGRATIONS_VALUE = '[data-test-subj^="relatedIntegrationsPropertyValue"]';
|
||||
|
||||
export const REQUIRED_FIELDS_PROPERTY_TITLE = '[data-test-subj="requiredFieldsPropertyTitle"]';
|
||||
export const REQUIRED_FIELDS_PROPERTY_VALUE_ITEM =
|
||||
'[data-test-subj="requiredFieldsPropertyValueItem"]';
|
||||
|
||||
export const TIMELINE_TEMPLATE_TITLE = '[data-test-subj="timelineTemplatePropertyTitle"]';
|
||||
export const TIMELINE_TEMPLATE_VALUE = '[data-test-subj="timelineTemplatePropertyValue"]';
|
||||
|
||||
export const INTERVAL_TITLE = '[data-test-subj="intervalPropertyTitle"]';
|
||||
export const INTERVAL_VALUE = '[data-test-subj="intervalPropertyValue"]';
|
||||
|
||||
export const FROM_TITLE = '[data-test-subj="fromPropertyTitle"]';
|
||||
export const FROM_VALUE = '[data-test-subj^="fromPropertyValue"]';
|
||||
|
||||
export const INDEX_TITLE = '[data-test-subj="indexPropertyTitle"]';
|
||||
export const INDEX_VALUE_ITEM = '[data-test-subj="indexPropertyValueItem"]';
|
||||
|
||||
export const CUSTOM_QUERY_TITLE = '[data-test-subj="customQueryPropertyTitle"]';
|
||||
export const CUSTOM_QUERY_VALUE = '[data-test-subj="customQueryPropertyValue"]';
|
||||
|
||||
export const FILTERS_TITLE = '[data-test-subj="filtersPropertyTitle"]';
|
||||
export const FILTERS_VALUE_ITEM =
|
||||
'[data-test-subj="filtersPropertyValue"] [data-test-subj^="filterItem-"]';
|
||||
|
||||
export const ALERT_SUPPRESSION_GROUP_BY_TITLE =
|
||||
'[data-test-subj="alertSuppressionGroupByPropertyTitle"]';
|
||||
export const ALERT_SUPPRESSION_GROUP_BY_VALUE_ITEM =
|
||||
'[data-test-subj="alertSuppressionGroupByPropertyValueItem"]';
|
||||
|
||||
export const ALERT_SUPPRESSION_DURATION_TITLE =
|
||||
'[data-test-subj="alertSuppressionDurationPropertyTitle"]';
|
||||
export const ALERT_SUPPRESSION_DURATION_VALUE =
|
||||
'[data-test-subj="alertSuppressionDurationPropertyValue"]';
|
||||
|
||||
export const ALERT_SUPPRESSION_FIELD_TITLE =
|
||||
'[data-test-subj="alertSuppressionSuppressionFieldPropertyTitle"]';
|
||||
export const ALERT_SUPPRESSION_FIELD_VALUE =
|
||||
'[data-test-subj="alertSuppressionSuppressionFieldPropertyValue"]';
|
||||
|
||||
export const DATA_VIEW_ID_TITLE = '[data-test-subj="dataViewIdPropertyTitle"]';
|
||||
export const DATA_VIEW_ID_VALUE = '[data-test-subj="dataViewIdPropertyValue"]';
|
||||
|
||||
export const DATA_VIEW_INDEX_PATTERN_TITLE = '[data-test-subj="dataViewIndexPatternPropertyTitle"]';
|
||||
export const DATA_VIEW_INDEX_PATTERN_VALUE = '[data-test-subj="dataViewIndexPatternPropertyValue"]';
|
||||
|
||||
export const SAVED_QUERY_CONTENT_TITLE = '[data-test-subj="savedQueryContentPropertyTitle"]';
|
||||
export const SAVED_QUERY_CONTENT_VALUE = '[data-test-subj="savedQueryContentPropertyValue"]';
|
||||
|
||||
export const SAVED_QUERY_FILTERS_TITLE = '[data-test-subj="savedQueryFiltersPropertyTitle"]';
|
||||
export const SAVED_QUERY_FILTERS_VALUE =
|
||||
'[data-test-subj="savedQueryFiltersPropertyValue"] [data-test-subj^="filterItem-"]';
|
||||
|
||||
export const SAVED_QUERY_NAME_TITLE = '[data-test-subj="savedQueryNamePropertyTitle"]';
|
||||
export const SAVED_QUERY_NAME_VALUE = '[data-test-subj="savedQueryNamePropertyValue"]';
|
||||
|
||||
export const ANOMALY_THRESHOLD_TITLE = '[data-test-subj="anomalyThresholdPropertyTitle"]';
|
||||
export const ANOMALY_THRESHOLD_VALUE = '[data-test-subj="anomalyThresholdPropertyValue"]';
|
||||
|
||||
export const MACHINE_LEARNING_JOB_TITLE = '[data-test-subj="mlJobPropertyTitle"]';
|
||||
export const MACHINE_LEARNING_JOB_VALUE = '[data-test-subj="machineLearningJob"]';
|
||||
|
||||
export const THRESHOLD_TITLE = '[data-test-subj="thresholdPropertyTitle"]';
|
||||
export const THRESHOLD_VALUE = '[data-test-subj="thresholdPropertyValue"]';
|
||||
|
||||
export const EQL_QUERY_TITLE = '[data-test-subj="eqlQueryPropertyTitle"]';
|
||||
export const EQL_QUERY_VALUE = '[data-test-subj="eqlQueryPropertyValue"]';
|
||||
|
||||
export const THREAT_INDEX_TITLE = '[data-test-subj="threatIndexPropertyTitle"]';
|
||||
export const THREAT_INDEX_VALUE_ITEM = '[data-test-subj="threatIndexPropertyValueItem"]';
|
||||
|
||||
export const THREAT_MAPPING_TITLE = '[data-test-subj="threatMappingPropertyTitle"]';
|
||||
export const THREAT_MAPPING_VALUE = '[data-test-subj="threatMappingPropertyValue"]';
|
||||
|
||||
export const THREAT_FILTERS_TITLE = '[data-test-subj="threatFiltersPropertyTitle"]';
|
||||
export const THREAT_FILTERS_VALUE_ITEM =
|
||||
'[data-test-subj="threatFiltersPropertyValue"] [data-test-subj^="filterItem-"]';
|
||||
|
||||
export const THREAT_QUERY_TITLE = '[data-test-subj="threatQueryPropertyTitle"]';
|
||||
export const THREAT_QUERY_VALUE = '[data-test-subj="threatQueryPropertyValue"]';
|
||||
|
||||
export const NEW_TERMS_FIELDS_TITLE = '[data-test-subj="newTermsFieldsPropertyTitle"]';
|
||||
export const NEW_TERMS_FIELDS_VALUE_ITEM = '[data-test-subj="newTermsFieldsPropertyValueItem"]';
|
||||
|
||||
export const NEW_TERMS_WINDOW_SIZE_TITLE = '[data-test-subj="newTermsWindowSizePropertyTitle"]';
|
||||
export const NEW_TERMS_WINDOW_SIZE_VALUE = '[data-test-subj^="newTermsWindowSizePropertyValue"]';
|
||||
|
||||
export const ESQL_QUERY_TITLE = '[data-test-subj="esqlQueryPropertyTitle"]';
|
||||
export const ESQL_QUERY_VALUE = '[data-test-subj="esqlQueryPropertyValue"]';
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 { ML_INTERNAL_BASE_PATH } from '@kbn/ml-plugin/common/constants/app';
|
||||
import type { Module } from '@kbn/ml-plugin/common/types/modules';
|
||||
import { rootRequest } from '../common';
|
||||
|
||||
export const fetchMachineLearningModules = () => {
|
||||
return rootRequest<Module[]>({
|
||||
method: 'GET',
|
||||
url: `${ML_INTERNAL_BASE_PATH}/modules/get_module`,
|
||||
headers: {
|
||||
'kbn-xsrf': 'cypress-creds',
|
||||
'x-elastic-internal-origin': 'security-solution',
|
||||
'elastic-api-version': 1,
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
};
|
|
@ -36,7 +36,11 @@ export const createSavedQuery = (
|
|||
},
|
||||
],
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds', [ELASTIC_HTTP_VERSION_HEADER]: '1' },
|
||||
headers: {
|
||||
'kbn-xsrf': 'cypress-creds',
|
||||
[ELASTIC_HTTP_VERSION_HEADER]: '1',
|
||||
'x-elastic-internal-origin': 'security-solution',
|
||||
},
|
||||
});
|
||||
|
||||
export const deleteSavedQueries = () => {
|
||||
|
|
|
@ -305,16 +305,16 @@ export const deletePrebuiltRulesAssets = () => {
|
|||
});
|
||||
};
|
||||
|
||||
export const postDataView = (dataSource: string) => {
|
||||
export const postDataView = (indexPattern: string, name?: string, id?: string) => {
|
||||
rootRequest({
|
||||
method: 'POST',
|
||||
url: DATA_VIEW_PATH,
|
||||
body: {
|
||||
data_view: {
|
||||
id: dataSource,
|
||||
name: dataSource,
|
||||
id: id || indexPattern,
|
||||
name: name || indexPattern,
|
||||
fieldAttrs: '{}',
|
||||
title: dataSource,
|
||||
title: indexPattern,
|
||||
timeFieldName: '@timestamp',
|
||||
},
|
||||
},
|
||||
|
@ -327,11 +327,17 @@ export const postDataView = (dataSource: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
export const deleteDataView = (dataSource: string) => {
|
||||
export const deleteDataView = (dataViewId: string) => {
|
||||
rootRequest({
|
||||
method: 'DELETE',
|
||||
url: `api/data_views/data_view/${dataSource}`,
|
||||
method: 'POST',
|
||||
url: 'api/content_management/rpc/delete',
|
||||
headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' },
|
||||
body: {
|
||||
contentTypeId: 'index-pattern',
|
||||
id: dataViewId,
|
||||
options: { force: true },
|
||||
version: 1,
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -16,15 +16,14 @@ import {
|
|||
RULES_UPDATES_TABLE,
|
||||
TOASTER,
|
||||
} from '../screens/alerts_detection_rules';
|
||||
import { RULE_MANAGEMENT_PAGE_BREADCRUMB } from '../screens/breadcrumbs';
|
||||
import type { SAMPLE_PREBUILT_RULE } from './api_calls/prebuilt_rules';
|
||||
|
||||
export const addElasticRulesButtonClick = () => {
|
||||
export const clickAddElasticRulesButton = () => {
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).click();
|
||||
cy.location('pathname').should('include', RULES_ADD_PATH);
|
||||
};
|
||||
|
||||
export const ruleUpdatesTabClick = () => {
|
||||
export const clickRuleUpdatesTab = () => {
|
||||
cy.get(RULES_UPDATES_TAB).click();
|
||||
cy.location('pathname').should('include', RULES_UPDATES);
|
||||
};
|
||||
|
@ -55,39 +54,6 @@ export const assertUpgradeRequestIsComplete = (rules: Array<typeof SAMPLE_PREBUI
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert that when the rule installation succeeds, the toast is shown with the right message
|
||||
* -confirming the succesful install- and subsequently check that the rules available for installation
|
||||
* are not present in the Add Elastic Rules table anymore
|
||||
*/
|
||||
export const assertInstallationSuccess = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
const toastMessage = `${rules.length} ${rulesString} installed successfully.`;
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', toastMessage);
|
||||
|
||||
// Go back to rules table and assert that the rules are installed
|
||||
cy.get(RULE_MANAGEMENT_PAGE_BREADCRUMB).click();
|
||||
for (const rule of rules) {
|
||||
cy.get(RULES_MANAGEMENT_TABLE).contains(rule['security-rule'].name);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert that when the rule installation fails, the toast is shown with the right message
|
||||
* -notifying that the installation failed- and subsequently check that the rules available for installation
|
||||
* are still present in the Rule Update table
|
||||
*/
|
||||
export const assertInstallationFailure = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
const toastMessage = `${rules.length} ${rulesString} failed to install.`;
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', toastMessage);
|
||||
|
||||
// Check rules are still available for install
|
||||
for (const rule of rules) {
|
||||
cy.get(ADD_ELASTIC_RULES_TABLE).contains(rule['security-rule'].name);
|
||||
}
|
||||
};
|
||||
|
||||
export const interceptInstallationRequestToFail = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform', {
|
||||
body: {
|
||||
|
@ -101,35 +67,6 @@ export const interceptInstallationRequestToFail = (rules: Array<typeof SAMPLE_PR
|
|||
}).as('installPrebuiltRules');
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert that when the rule version upgrade succeeds, the toast is shown with the right message
|
||||
* -confirming the succesful upgrade- and subsequently check that the rules available for upgrade
|
||||
* are not present in the Rule Update table anymore
|
||||
*/
|
||||
export const assertUpgradeSuccess = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
const toastMessage = `${rules.length} ${rulesString} updated successfully.`;
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', toastMessage);
|
||||
for (const rule of rules) {
|
||||
cy.get(rule['security-rule'].name).should('not.exist');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert that when the rule version upgrade fails, the toast is shown with the right message
|
||||
* -notifying that the upgrade failed- and subsequently check that the rules available for upgrade
|
||||
* are still present in the Rule Update table
|
||||
*/
|
||||
export const assertUpgradeFailure = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
const toastMessage = `${rules.length} ${rulesString} failed to update.`;
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', toastMessage);
|
||||
|
||||
for (const rule of rules) {
|
||||
cy.get(RULES_UPDATES_TABLE).contains(rule['security-rule'].name);
|
||||
}
|
||||
};
|
||||
|
||||
export const interceptUpgradeRequestToFail = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/upgrade/_perform', {
|
||||
body: {
|
||||
|
@ -142,3 +79,74 @@ export const interceptUpgradeRequestToFail = (rules: Array<typeof SAMPLE_PREBUIL
|
|||
delay: 500, // Add delay to give Cypress time to find the loading spinner
|
||||
}).as('updatePrebuiltRules');
|
||||
};
|
||||
|
||||
export const assertRuleInstallationSuccessToastShown = (
|
||||
rules: Array<typeof SAMPLE_PREBUILT_RULE>
|
||||
) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
cy.get(TOASTER)
|
||||
.should('be.visible')
|
||||
.should('have.text', `${rules.length} ${rulesString} installed successfully.`);
|
||||
};
|
||||
|
||||
export const assertRuleInstallationFailureToastShown = (
|
||||
rules: Array<typeof SAMPLE_PREBUILT_RULE>
|
||||
) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
cy.get(TOASTER)
|
||||
.should('be.visible')
|
||||
.should('have.text', `${rules.length} ${rulesString} failed to install.`);
|
||||
};
|
||||
|
||||
export const assertRuleUpgradeSuccessToastShown = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
cy.get(TOASTER)
|
||||
.should('be.visible')
|
||||
.should('have.text', `${rules.length} ${rulesString} updated successfully.`);
|
||||
};
|
||||
|
||||
export const assertRuleUpgradeFailureToastShown = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
const rulesString = rules.length > 1 ? 'rules' : 'rule';
|
||||
cy.get(TOASTER)
|
||||
.should('be.visible')
|
||||
.should('have.text', `${rules.length} ${rulesString} failed to update.`);
|
||||
};
|
||||
|
||||
export const assertRulesPresentInInstalledRulesTable = (
|
||||
rules: Array<typeof SAMPLE_PREBUILT_RULE>
|
||||
) => {
|
||||
for (const rule of rules) {
|
||||
cy.get(RULES_MANAGEMENT_TABLE).contains(rule['security-rule'].name);
|
||||
}
|
||||
};
|
||||
|
||||
export const assertRulesPresentInAddPrebuiltRulesTable = (
|
||||
rules: Array<typeof SAMPLE_PREBUILT_RULE>
|
||||
) => {
|
||||
for (const rule of rules) {
|
||||
cy.get(ADD_ELASTIC_RULES_TABLE).contains(rule['security-rule'].name);
|
||||
}
|
||||
};
|
||||
|
||||
export const assertRulesNotPresentInAddPrebuiltRulesTable = (
|
||||
rules: Array<typeof SAMPLE_PREBUILT_RULE>
|
||||
) => {
|
||||
for (const rule of rules) {
|
||||
cy.get(ADD_ELASTIC_RULES_TABLE).contains(rule['security-rule'].name).should('not.exist');
|
||||
}
|
||||
};
|
||||
|
||||
export const assertRulesPresentInRuleUpdatesTable = (rules: Array<typeof SAMPLE_PREBUILT_RULE>) => {
|
||||
for (const rule of rules) {
|
||||
cy.get(RULES_UPDATES_TABLE).contains(rule['security-rule'].name);
|
||||
}
|
||||
};
|
||||
|
||||
export const assertRulesNotPresentInRuleUpdatesTable = (
|
||||
rules: Array<typeof SAMPLE_PREBUILT_RULE>
|
||||
) => {
|
||||
cy.url().should('include', RULES_UPDATES);
|
||||
for (const rule of rules) {
|
||||
cy.get(rule['security-rule'].name).should('not.exist');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* 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 { capitalize } from 'lodash';
|
||||
import type { ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import type { Module } from '@kbn/ml-plugin/common/types/modules';
|
||||
import { AlertSuppression } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema';
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
import type { PrebuiltRuleAsset } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules';
|
||||
import {
|
||||
ALERT_SUPPRESSION_DURATION_TITLE,
|
||||
ALERT_SUPPRESSION_DURATION_VALUE,
|
||||
ALERT_SUPPRESSION_FIELD_TITLE,
|
||||
ALERT_SUPPRESSION_FIELD_VALUE,
|
||||
ALERT_SUPPRESSION_GROUP_BY_TITLE,
|
||||
ALERT_SUPPRESSION_GROUP_BY_VALUE_ITEM,
|
||||
ANOMALY_THRESHOLD_TITLE,
|
||||
ANOMALY_THRESHOLD_VALUE,
|
||||
AUTHOR_PROPERTY_TITLE,
|
||||
AUTHOR_PROPERTY_VALUE_ITEM,
|
||||
BUILDING_BLOCK_TITLE,
|
||||
BUILDING_BLOCK_VALUE,
|
||||
CUSTOM_QUERY_TITLE,
|
||||
CUSTOM_QUERY_VALUE,
|
||||
DATA_VIEW_ID_TITLE,
|
||||
DATA_VIEW_ID_VALUE,
|
||||
DATA_VIEW_INDEX_PATTERN_TITLE,
|
||||
DATA_VIEW_INDEX_PATTERN_VALUE,
|
||||
EQL_QUERY_TITLE,
|
||||
EQL_QUERY_VALUE,
|
||||
ESQL_QUERY_TITLE,
|
||||
ESQL_QUERY_VALUE,
|
||||
FALSE_POSITIVES_TITLE,
|
||||
FALSE_POSITIVES_VALUE_ITEM,
|
||||
FILTERS_TITLE,
|
||||
FILTERS_VALUE_ITEM,
|
||||
FLYOUT_CLOSE_BTN,
|
||||
FROM_TITLE,
|
||||
FROM_VALUE,
|
||||
INDEX_TITLE,
|
||||
INDEX_VALUE_ITEM,
|
||||
INSTALL_PREBUILT_RULE_PREVIEW,
|
||||
INTERVAL_TITLE,
|
||||
INTERVAL_VALUE,
|
||||
INVESTIGATION_FIELDS_TITLE,
|
||||
INVESTIGATION_FIELDS_VALUE_ITEM,
|
||||
LICENSE_TITLE,
|
||||
LICENSE_VALUE,
|
||||
MACHINE_LEARNING_JOB_TITLE,
|
||||
MACHINE_LEARNING_JOB_VALUE,
|
||||
NEW_TERMS_FIELDS_TITLE,
|
||||
NEW_TERMS_FIELDS_VALUE_ITEM,
|
||||
NEW_TERMS_WINDOW_SIZE_TITLE,
|
||||
NEW_TERMS_WINDOW_SIZE_VALUE,
|
||||
REFERENCES_TITLE,
|
||||
REFERENCES_VALUE_ITEM,
|
||||
RELATED_INTEGRATIONS_TITLE,
|
||||
RELATED_INTEGRATIONS_VALUE,
|
||||
REQUIRED_FIELDS_PROPERTY_TITLE,
|
||||
REQUIRED_FIELDS_PROPERTY_VALUE_ITEM,
|
||||
RISK_SCORE_MAPPING_TITLE,
|
||||
RISK_SCORE_MAPPING_VALUE_FIELD_NAME,
|
||||
RISK_SCORE_MAPPING_VALUE_OVERRIDE_NAME,
|
||||
RISK_SCORE_TITLE,
|
||||
RISK_SCORE_VALUE,
|
||||
RULE_NAME_OVERRIDE_TITLE,
|
||||
RULE_NAME_OVERRIDE_VALUE,
|
||||
SAVED_QUERY_CONTENT_TITLE,
|
||||
SAVED_QUERY_CONTENT_VALUE,
|
||||
SAVED_QUERY_FILTERS_TITLE,
|
||||
SAVED_QUERY_FILTERS_VALUE,
|
||||
SAVED_QUERY_NAME_TITLE,
|
||||
SAVED_QUERY_NAME_VALUE,
|
||||
SEVERITY_MAPPING_TITLE,
|
||||
SEVERITY_MAPPING_VALUE_FIELD,
|
||||
SEVERITY_MAPPING_VALUE_SEVERITY,
|
||||
SEVERITY_MAPPING_VALUE_VALUE,
|
||||
SEVERITY_TITLE,
|
||||
SEVERITY_VALUE,
|
||||
TAGS_PROPERTY_TITLE,
|
||||
TAGS_PROPERTY_VALUE_ITEM,
|
||||
THREAT_FILTERS_TITLE,
|
||||
THREAT_FILTERS_VALUE_ITEM,
|
||||
THREAT_INDEX_TITLE,
|
||||
THREAT_INDEX_VALUE_ITEM,
|
||||
THREAT_MAPPING_TITLE,
|
||||
THREAT_MAPPING_VALUE,
|
||||
THREAT_QUERY_TITLE,
|
||||
THREAT_QUERY_VALUE,
|
||||
THREAT_TACTIC,
|
||||
THREAT_TITLE,
|
||||
THRESHOLD_TITLE,
|
||||
THRESHOLD_VALUE,
|
||||
TIMELINE_TEMPLATE_TITLE,
|
||||
TIMELINE_TEMPLATE_VALUE,
|
||||
TIMESTAMP_OVERRIDE_TITLE,
|
||||
TIMESTAMP_OVERRIDE_VALUE,
|
||||
UPDATE_PREBUILT_RULE_PREVIEW,
|
||||
} from '../screens/alerts_detection_rules';
|
||||
|
||||
export const openRuleInstallPreview = (ruleName: string) => {
|
||||
cy.contains(ruleName).click();
|
||||
cy.get(INSTALL_PREBUILT_RULE_PREVIEW).should('be.visible');
|
||||
};
|
||||
|
||||
export const openRuleUpdatePreview = (ruleName: string) => {
|
||||
cy.contains(ruleName).click();
|
||||
cy.get(UPDATE_PREBUILT_RULE_PREVIEW).should('be.visible');
|
||||
};
|
||||
|
||||
export const closeRulePreview = () => {
|
||||
cy.get(FLYOUT_CLOSE_BTN).click();
|
||||
cy.get(INSTALL_PREBUILT_RULE_PREVIEW).should('not.exist');
|
||||
};
|
||||
|
||||
export const assertCommonPropertiesShown = (properties: Partial<PrebuiltRuleAsset>) => {
|
||||
cy.get(AUTHOR_PROPERTY_TITLE).should('have.text', 'Author');
|
||||
cy.get(AUTHOR_PROPERTY_VALUE_ITEM).then((items) => {
|
||||
const authorItems = items.map((index, item) => item.textContent).toArray();
|
||||
cy.wrap(authorItems).should('deep.equal', properties.author);
|
||||
});
|
||||
|
||||
cy.get(BUILDING_BLOCK_TITLE).should('have.text', 'Building block');
|
||||
cy.get(BUILDING_BLOCK_VALUE).should(
|
||||
'have.text',
|
||||
'All generated alerts will be marked as "building block" alerts'
|
||||
);
|
||||
|
||||
cy.get(SEVERITY_TITLE).should('have.text', 'Severity');
|
||||
cy.get(SEVERITY_VALUE).should('have.text', capitalize(properties.severity));
|
||||
|
||||
cy.get(SEVERITY_MAPPING_TITLE).should('have.text', 'Severity override');
|
||||
properties.severity_mapping?.forEach((severityMapping, index) => {
|
||||
cy.get(SEVERITY_MAPPING_VALUE_FIELD).eq(index).should('have.text', `${severityMapping.field}:`);
|
||||
cy.get(SEVERITY_MAPPING_VALUE_VALUE).eq(index).should('have.text', severityMapping.value);
|
||||
cy.get(SEVERITY_MAPPING_VALUE_SEVERITY)
|
||||
.eq(index)
|
||||
.should('have.text', capitalize(severityMapping.severity));
|
||||
});
|
||||
|
||||
cy.get(RISK_SCORE_TITLE).should('have.text', 'Risk score');
|
||||
cy.get(RISK_SCORE_VALUE).should('have.text', properties.risk_score);
|
||||
|
||||
cy.get(RISK_SCORE_MAPPING_TITLE).should('have.text', 'Risk score override');
|
||||
properties.risk_score_mapping?.forEach((riskScoreMapping, index) => {
|
||||
cy.get(RISK_SCORE_MAPPING_VALUE_FIELD_NAME)
|
||||
.eq(index)
|
||||
.should('have.text', riskScoreMapping.field);
|
||||
cy.get(RISK_SCORE_MAPPING_VALUE_OVERRIDE_NAME)
|
||||
.eq(index)
|
||||
.should('have.text', 'kibana.alert.risk_score');
|
||||
});
|
||||
|
||||
cy.get(REFERENCES_TITLE).should('have.text', 'Reference URLs');
|
||||
cy.get(`${REFERENCES_VALUE_ITEM} a`).then((items) => {
|
||||
const referenceUrls = (items as JQuery<HTMLLinkElement>)
|
||||
.map((index, item) => item.href)
|
||||
.toArray();
|
||||
cy.wrap(referenceUrls).should('deep.equal', properties.references);
|
||||
});
|
||||
|
||||
cy.get(FALSE_POSITIVES_TITLE).should('have.text', 'False positive examples');
|
||||
cy.get(FALSE_POSITIVES_VALUE_ITEM).then((items) => {
|
||||
const falsePositives = items.map((index, item) => item.textContent).toArray();
|
||||
cy.wrap(falsePositives).should('deep.equal', properties.false_positives);
|
||||
});
|
||||
|
||||
cy.get(INVESTIGATION_FIELDS_TITLE).should('have.text', 'Custom highlighted fields');
|
||||
cy.get(INVESTIGATION_FIELDS_VALUE_ITEM).then((items) => {
|
||||
const investigationFields = items.map((index, item) => item.textContent).toArray();
|
||||
cy.wrap(investigationFields).should('deep.equal', properties.investigation_fields?.field_names);
|
||||
});
|
||||
|
||||
cy.get(LICENSE_TITLE).should('have.text', 'License');
|
||||
cy.get(LICENSE_VALUE).should('have.text', properties.license);
|
||||
|
||||
cy.get(RULE_NAME_OVERRIDE_TITLE).should('have.text', 'Rule name override');
|
||||
cy.get(RULE_NAME_OVERRIDE_VALUE).should('have.text', properties.rule_name_override);
|
||||
|
||||
cy.get(THREAT_TITLE).should('have.text', 'MITRE ATT&CK™');
|
||||
properties.threat?.forEach((threatItem, index) => {
|
||||
cy.get(THREAT_TACTIC).eq(index).should('contain', threatItem.tactic.id);
|
||||
});
|
||||
|
||||
cy.get(TIMESTAMP_OVERRIDE_TITLE).should('have.text', 'Timestamp override');
|
||||
cy.get(TIMESTAMP_OVERRIDE_VALUE).should('have.text', properties.timestamp_override);
|
||||
|
||||
cy.get(TAGS_PROPERTY_TITLE).should('have.text', 'Tags');
|
||||
cy.get(TAGS_PROPERTY_VALUE_ITEM).then((items) => {
|
||||
const tags = items.map((index, item) => item.textContent).toArray();
|
||||
cy.wrap(tags).should('deep.equal', properties.tags);
|
||||
});
|
||||
|
||||
cy.get(RELATED_INTEGRATIONS_TITLE).should('have.text', 'Related integrations');
|
||||
properties.related_integrations?.forEach((relatedIntegration, index) => {
|
||||
cy.get(RELATED_INTEGRATIONS_VALUE)
|
||||
.eq(index)
|
||||
.invoke('attr', 'data-test-subj')
|
||||
.should('contain', relatedIntegration.package);
|
||||
});
|
||||
|
||||
cy.get(REQUIRED_FIELDS_PROPERTY_TITLE).should('have.text', 'Required fields');
|
||||
properties.required_fields?.forEach((requiredField, index) => {
|
||||
cy.get(REQUIRED_FIELDS_PROPERTY_VALUE_ITEM).eq(index).should('contain', requiredField.name);
|
||||
});
|
||||
|
||||
cy.get(TIMELINE_TEMPLATE_TITLE).should('have.text', 'Timeline template');
|
||||
cy.get(TIMELINE_TEMPLATE_VALUE).should('have.text', properties.timeline_title);
|
||||
|
||||
cy.get(INTERVAL_TITLE).should('have.text', 'Runs every');
|
||||
cy.get(INTERVAL_VALUE).should('have.text', properties.interval);
|
||||
|
||||
cy.get(FROM_TITLE).should('have.text', 'Additional look-back time');
|
||||
cy.get(FROM_VALUE).invoke('attr', 'data-test-subj').should('contain', properties.from);
|
||||
};
|
||||
|
||||
export const assertIndexPropertyShown = (index: string[]) => {
|
||||
cy.get(INDEX_TITLE).should('have.text', 'Index patterns');
|
||||
cy.get(INDEX_VALUE_ITEM).then((items) => {
|
||||
const indexPatternItems = items.map((itemIndex, item) => item.textContent).toArray();
|
||||
cy.wrap(indexPatternItems).should('deep.equal', index);
|
||||
});
|
||||
};
|
||||
|
||||
export const assertCustomQueryPropertyShown = (query: string) => {
|
||||
cy.get(CUSTOM_QUERY_TITLE).should('have.text', 'Custom query');
|
||||
cy.get(CUSTOM_QUERY_VALUE).should('have.text', query);
|
||||
};
|
||||
|
||||
export const assertFiltersPropertyShown = (queryFilters: Filter[]) => {
|
||||
cy.get(FILTERS_TITLE).should('have.text', 'Filters');
|
||||
queryFilters.forEach((filter, filterIndex) => {
|
||||
cy.get(FILTERS_VALUE_ITEM)
|
||||
.eq(filterIndex)
|
||||
.invoke('attr', 'data-test-subj')
|
||||
.should('contain', filter.meta.key);
|
||||
});
|
||||
};
|
||||
|
||||
export const assertAlertSuppressionPropertiesShown = (alertSuppression: AlertSuppression) => {
|
||||
cy.get(ALERT_SUPPRESSION_GROUP_BY_TITLE).should('contain', 'Suppress alerts by');
|
||||
cy.get(ALERT_SUPPRESSION_GROUP_BY_VALUE_ITEM).then((items) => {
|
||||
const groupByItems = items.map((itemIndex, item) => item.textContent).toArray();
|
||||
cy.wrap(groupByItems).should('deep.equal', alertSuppression.group_by);
|
||||
});
|
||||
|
||||
const { duration } = alertSuppression as { duration: { value: number; unit: string } };
|
||||
cy.get(ALERT_SUPPRESSION_DURATION_TITLE).should('contain', 'Suppress alerts for');
|
||||
cy.get(ALERT_SUPPRESSION_DURATION_VALUE).should('contain', `${duration.value}${duration.unit}`);
|
||||
|
||||
cy.get(ALERT_SUPPRESSION_FIELD_TITLE).should('contain', 'If a suppression field is missing');
|
||||
cy.get(ALERT_SUPPRESSION_FIELD_VALUE).should(
|
||||
'contain',
|
||||
'Suppress and group alerts for events with missing fields'
|
||||
);
|
||||
};
|
||||
|
||||
export const assertDataViewPropertiesShown = (dataViewId: string, dataViewIndexPattern: string) => {
|
||||
cy.get(DATA_VIEW_ID_TITLE).should('have.text', 'Data view ID');
|
||||
cy.get(DATA_VIEW_ID_VALUE).should('have.text', dataViewId);
|
||||
cy.get(DATA_VIEW_INDEX_PATTERN_TITLE).should('have.text', 'Data view index pattern');
|
||||
cy.get(DATA_VIEW_INDEX_PATTERN_VALUE).should('have.text', dataViewIndexPattern);
|
||||
};
|
||||
|
||||
export const assertSavedQueryPropertiesShown = (query: string, filterKey: string, name: string) => {
|
||||
cy.get(SAVED_QUERY_CONTENT_TITLE).should('have.text', 'Saved query');
|
||||
cy.get(SAVED_QUERY_CONTENT_VALUE).should('have.text', query);
|
||||
|
||||
cy.get(SAVED_QUERY_FILTERS_TITLE).should('have.text', 'Saved query filters');
|
||||
cy.get(SAVED_QUERY_FILTERS_VALUE).should('contain', filterKey);
|
||||
|
||||
cy.get(SAVED_QUERY_NAME_TITLE).should('have.text', 'Saved query name');
|
||||
cy.get(SAVED_QUERY_NAME_VALUE).should('have.text', name);
|
||||
};
|
||||
|
||||
export const assertMachineLearningPropertiesShown = (
|
||||
anomalyThreshold: number,
|
||||
machineLearningJobIds: string[],
|
||||
mlModules: Module[]
|
||||
) => {
|
||||
const mlJobs = mlModules.map((mlModule: Module) => mlModule.jobs).flat();
|
||||
const mlJobNameById: Record<string, string> = mlJobs.reduce((nameById, job) => {
|
||||
return {
|
||||
...nameById,
|
||||
[job.id]: job.config?.custom_settings?.security_app_display_name || '',
|
||||
};
|
||||
}, {});
|
||||
|
||||
cy.get(ANOMALY_THRESHOLD_TITLE).should('have.text', 'Anomaly score threshold');
|
||||
cy.get(ANOMALY_THRESHOLD_VALUE).should('have.text', anomalyThreshold);
|
||||
|
||||
cy.get(MACHINE_LEARNING_JOB_TITLE).should('have.text', 'Machine Learning job');
|
||||
machineLearningJobIds.forEach((jobId, jobIndex) => {
|
||||
cy.get(MACHINE_LEARNING_JOB_VALUE).eq(jobIndex).should('contain', mlJobNameById[jobId]);
|
||||
});
|
||||
};
|
||||
|
||||
export const assertThresholdPropertyShown = (thresholdValue: number) => {
|
||||
cy.get(THRESHOLD_TITLE).should('have.text', 'Threshold');
|
||||
cy.get(THRESHOLD_VALUE).should('contain', thresholdValue);
|
||||
};
|
||||
|
||||
export const assertEqlQueryPropertyShown = (query: string) => {
|
||||
cy.get(EQL_QUERY_TITLE).should('have.text', 'EQL query');
|
||||
cy.get(EQL_QUERY_VALUE).should('have.text', query);
|
||||
};
|
||||
|
||||
interface ThreatMatchQueryProperties {
|
||||
threatIndex: string[];
|
||||
threatMapping: ThreatMapping;
|
||||
threatFilters: Filter[];
|
||||
threatQuery: string;
|
||||
}
|
||||
|
||||
export const assertThreatMatchQueryPropertiesShown = ({
|
||||
threatIndex,
|
||||
threatMapping,
|
||||
threatFilters,
|
||||
threatQuery,
|
||||
}: ThreatMatchQueryProperties) => {
|
||||
cy.get(THREAT_INDEX_TITLE).should('have.text', 'Indicator index patterns');
|
||||
cy.get(THREAT_INDEX_VALUE_ITEM).then((items) => {
|
||||
const indexItems = items.map((index, item) => item.textContent).toArray();
|
||||
cy.wrap(indexItems).should('deep.equal', threatIndex);
|
||||
});
|
||||
|
||||
cy.get(THREAT_MAPPING_TITLE).should('have.text', 'Indicator mapping');
|
||||
threatMapping.forEach((threatMappingItem) => {
|
||||
threatMappingItem.entries.forEach((entry) => {
|
||||
cy.get(THREAT_MAPPING_VALUE).should('contain', entry.value);
|
||||
});
|
||||
});
|
||||
|
||||
cy.get(THREAT_FILTERS_TITLE).should('have.text', 'Indicator filters');
|
||||
threatFilters.forEach((filter, filterIndex) => {
|
||||
cy.get(THREAT_FILTERS_VALUE_ITEM)
|
||||
.eq(filterIndex)
|
||||
.invoke('attr', 'data-test-subj')
|
||||
.should('contain', filter.meta.key);
|
||||
});
|
||||
|
||||
cy.get(THREAT_QUERY_TITLE).should('have.text', 'Indicator index query');
|
||||
cy.get(THREAT_QUERY_VALUE).should('have.text', threatQuery);
|
||||
};
|
||||
|
||||
export const assertNewTermsFieldsPropertyShown = (newTermsFields: string[]) => {
|
||||
cy.get(NEW_TERMS_FIELDS_TITLE).should('have.text', 'Fields');
|
||||
cy.get(NEW_TERMS_FIELDS_VALUE_ITEM).then((items) => {
|
||||
const fieldItems = items.map((index, item) => item.textContent).toArray();
|
||||
cy.wrap(fieldItems).should('deep.equal', newTermsFields);
|
||||
});
|
||||
};
|
||||
|
||||
export const assertWindowSizePropertyShown = (historyWindowStart: string) => {
|
||||
cy.get(NEW_TERMS_WINDOW_SIZE_TITLE).should('have.text', 'History Window Size');
|
||||
cy.get(NEW_TERMS_WINDOW_SIZE_VALUE)
|
||||
.invoke('attr', 'data-test-subj')
|
||||
.should('contain', historyWindowStart);
|
||||
};
|
||||
|
||||
export const assertEsqlQueryPropertyShown = (query: string) => {
|
||||
cy.get(ESQL_QUERY_TITLE).should('have.text', 'ES|QL query');
|
||||
cy.get(ESQL_QUERY_VALUE).should('have.text', query);
|
||||
};
|
|
@ -39,5 +39,7 @@
|
|||
"@kbn/securitysolution-list-constants",
|
||||
"@kbn/security-plugin",
|
||||
"@kbn/management-settings-ids",
|
||||
"@kbn/es-query",
|
||||
"@kbn/ml-plugin"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue