Skip to content

Commit

Permalink
[Custom log types] Support custom log types in detection rule creatio…
Browse files Browse the repository at this point in the history
…n and detector creation (#676)

* log types table; details page with basic editing

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* implemented create, delete of log type

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* detection rules; delete modals added

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* updated snapshots

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* addressed PR comments

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* updated cypress workflow

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* use log types from API

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* updated detector cypress test

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* using api provided log types in rule creation

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* addressed PR comments

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* updated cypress test

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* updated nav panel

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* fixed log type labels; cypress tests

Signed-off-by: Amardeepsingh Siglani <[email protected]>

---------

Signed-off-by: Amardeepsingh Siglani <[email protected]>
(cherry picked from commit 5388596)
  • Loading branch information
amsiglan authored and github-actions[bot] committed Aug 1, 2023
1 parent 878ba33 commit 4dde47b
Show file tree
Hide file tree
Showing 32 changed files with 566 additions and 1,222 deletions.
10 changes: 7 additions & 3 deletions cypress/integration/1_detectors.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { getMappingFields } from '../../public/pages/Detectors/utils/helpers';
const cypressIndexDns = 'cypress-index-dns';
const cypressIndexWindows = 'cypress-index-windows';
const detectorName = 'test detector';
const cypressLogTypeDns = 'dns';

const cypressDNSRule = dns_name_rule_data.title;

Expand All @@ -24,8 +25,6 @@ const getNextButton = () => cy.getButtonByText('Next');

const getCreateDetectorButton = () => cy.getButtonByText('Create detector');

const selectDnsLogType = () => cy.getRadioButtonById('dns').click({ force: true });

const validateAlertPanel = (alertName) =>
cy
.getElementByText('.euiTitle', 'Alert triggers')
Expand All @@ -38,6 +37,10 @@ const dataSourceLabel = 'Select or input source indexes or index patterns';

const getDataSourceField = () => cy.getFieldByLabel(dataSourceLabel);

const logTypeLabel = 'Select a log type you would like to detect';

const getLogTypeField = () => cy.getFieldByLabel(logTypeLabel);

const openDetectorDetails = (detectorName) => {
cy.getInputByPlaceholder('Search threat detectors').type(`${detectorName}`).pressEnterKey();
cy.getElementByText('.euiTableCellContent button', detectorName).click();
Expand Down Expand Up @@ -112,7 +115,8 @@ const validatePendingFieldMappingsPanel = (mappings) => {
const fillDetailsForm = (detectorName, dataSource) => {
getNameField().type(detectorName);
getDataSourceField().selectComboboxItem(dataSource);
selectDnsLogType();
getLogTypeField().selectComboboxItem(cypressLogTypeDns);
getLogTypeField().blur();
};

const createDetector = (detectorName, dataSource, expectFailure) => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/3_alerts.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('Alerts', () => {
expect($tr, `timestamp`).to.contain(date);
expect($tr, `rule name`).to.contain('Cypress USB Rule');
expect($tr, `detector name`).to.contain(testDetector.name);
expect($tr, `log type`).to.contain('Windows');
expect($tr, `log type`).to.contain('windows');
});

// Close the flyout
Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/4_findings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('Findings', () => {
cy.contains('No items found').should('not.exist');

// Check for expected findings
cy.contains('Windows');
cy.contains('windows');
cy.contains('High');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CorrelationFinding, CorrelationGraphData, DateTimeFilter } from '../../
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import {
defaultLogTypeFilterItemOptions,
getDefaultLogTypeFilterItemOptions,
defaultSeverityFilterItemOptions,
emptyGraphData,
getAbbrFromLogType,
Expand Down Expand Up @@ -85,7 +85,7 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
this.state = {
recentlyUsedRanges: [DEFAULT_DATE_RANGE],
graphData: { ...emptyGraphData },
logTypeFilterOptions: [...defaultLogTypeFilterItemOptions],
logTypeFilterOptions: [...getDefaultLogTypeFilterItemOptions()],
severityFilterOptions: [...defaultSeverityFilterItemOptions],
specificFindingInfo: undefined,
loadingGraphData: false,
Expand Down
18 changes: 16 additions & 2 deletions public/pages/Correlations/containers/CreateCorrelationRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,10 @@ export const CreateCorrelationRule: React.FC<CreateCorrelationRuleProps> = (
isInvalid={isInvalidInputForQuery('logType')}
placeholder="Select a log type"
data-test-subj={'rule_type_dropdown'}
options={ruleTypes.map(({ value, label }) => ({ value, label }))}
options={ruleTypes.map(({ label }) => ({
value: label.toLowerCase(),
label,
}))}
singleSelection={{ asPlainText: true }}
onChange={(e) => {
props.handleChange(`queries[${queryIdx}].logType`)(
Expand All @@ -283,7 +286,18 @@ export const CreateCorrelationRule: React.FC<CreateCorrelationRuleProps> = (
}}
onBlur={props.handleBlur(`queries[${queryIdx}].logType`)}
selectedOptions={
query.logType ? [{ value: query.logType, label: query.logType }] : []
query.logType
? [
{
value: query.logType,
label:
ruleTypes.find(
(logType) =>
logType.label.toLowerCase() === query.logType.toLowerCase()
)?.label || query.logType,
},
]
: []
}
isClearable={true}
onCreateOption={(e) => {
Expand Down
15 changes: 6 additions & 9 deletions public/pages/Correlations/utils/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,12 @@ export const graphRenderOptions = {
},
};

export const defaultLogTypeFilterItemOptions: FilterItem[] = Object.values(ruleTypes).map(
(type) => {
return {
name: `${type.abbr}: ${type.label}`,
id: type.value,
checked: 'on',
};
}
);
export const getDefaultLogTypeFilterItemOptions: () => FilterItem[] = () =>
Object.values(ruleTypes).map((type) => ({
name: `${type.label}`,
id: type.label.toLowerCase(),
checked: 'on',
}));

export const defaultSeverityFilterItemOptions: FilterItem[] = Object.values(ruleSeverity).map(
(sev) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@

import React, { Component } from 'react';
import { ContentPanel } from '../../../../../../components/ContentPanel';
import { EuiFormRow, EuiFlexGrid, EuiFlexItem, EuiRadio, EuiSpacer } from '@elastic/eui';
import { EuiFormRow, EuiSpacer, EuiComboBox } from '@elastic/eui';
import { FormFieldHeader } from '../../../../../../components/FormFieldHeader/FormFieldHeader';
import { DETECTOR_TYPES } from '../../../../../Detectors/utils/constants';
import { DetectorTypeOption } from '../../../../../Detectors/models/interfaces';
import { CreateDetectorRulesState, DetectionRules } from '../DetectionRules/DetectionRules';
import { RuleItem } from '../DetectionRules/types/interfaces';
import { ruleTypes } from '../../../../../Rules/utils/constants';

interface DetectorTypeProps {
detectorType: string;
Expand All @@ -24,19 +23,18 @@ interface DetectorTypeProps {

interface DetectorTypeState {
fieldTouched: boolean;
detectorTypeOptions: DetectorTypeOption[];
detectorTypeIds: string[];
}

export default class DetectorType extends Component<DetectorTypeProps, DetectorTypeState> {
private detectorTypeOptions: { value: string; label: string }[];
constructor(props: DetectorTypeProps) {
super(props);

const detectorTypeOptions = Object.values(DETECTOR_TYPES);
const detectorTypeIds = detectorTypeOptions.map((option) => option.id);
this.detectorTypeOptions = ruleTypes.map(({ label }) => ({ value: label, label }));
const detectorTypeIds = this.detectorTypeOptions.map((option) => option.value);
this.state = {
fieldTouched: false,
detectorTypeOptions,
detectorTypeIds,
};
}
Expand All @@ -63,17 +61,6 @@ export default class DetectorType extends Component<DetectorTypeProps, DetectorT

render() {
const { detectorType } = this.props;
const { detectorTypeOptions } = this.state;
const radioButtons = detectorTypeOptions.map((type) => (
<EuiFlexItem key={type.id}>
<EuiRadio
id={type.id}
label={type.label}
checked={type.id === detectorType}
onChange={() => this.onChange(type.id)}
/>
</EuiFlexItem>
));

return (
<ContentPanel
Expand All @@ -84,15 +71,25 @@ export default class DetectorType extends Component<DetectorTypeProps, DetectorT
<EuiFormRow
label={
<div>
<FormFieldHeader headerTitle={'Select a category type you would like to detect'} />
<FormFieldHeader headerTitle={'Select a log type you would like to detect'} />
<EuiSpacer size={'s'} />
</div>
}
fullWidth={true}
isInvalid={this.isInvalid()}
error={this.getErrorMessage()}
>
<EuiFlexGrid columns={4}>{radioButtons}</EuiFlexGrid>
<EuiComboBox
isInvalid={this.isInvalid()}
placeholder="Select log type"
data-test-subj={'log_type_dropdown'}
options={this.detectorTypeOptions}
singleSelection={{ asPlainText: true }}
onChange={(e) => {
this.onChange(e[0]?.label || '');
}}
selectedOptions={detectorType ? [{ value: detectorType, label: detectorType }] : []}
/>
</EuiFormRow>

<EuiFormRow fullWidth={true}>
Expand Down
Loading

0 comments on commit 4dde47b

Please sign in to comment.