Skip to content

Commit

Permalink
Rule YAML preview (#209)
Browse files Browse the repository at this point in the history
* remove unused service

Signed-off-by: Aleksandar Djindjic <[email protected]>

* refactor form state

Signed-off-by: Aleksandar Djindjic <[email protected]>

* extract model and mappers

Signed-off-by: Aleksandar Djindjic <[email protected]>

* Extract Visual Rule Editor Component

Signed-off-by: Aleksandar Djindjic <[email protected]>

* fix missing default id

Signed-off-by: Aleksandar Djindjic <[email protected]>

* yaml editor

Signed-off-by: Aleksandar Djindjic <[email protected]>

* yaml rule editor mappings

Signed-off-by: Aleksandar Djindjic <[email protected]>

* more mapping guards

Signed-off-by: Aleksandar Djindjic <[email protected]>

* remove console.log's

Signed-off-by: Aleksandar Djindjic <[email protected]>

* YAML editor - cypress test

Signed-off-by: Aleksandar Djindjic <[email protected]>

* yaml editor snapshot test

Signed-off-by: Aleksandar Djindjic <[email protected]>

* rename model

Signed-off-by: Aleksandar Djindjic <[email protected]>

* more validations on yaml editor

Signed-off-by: Aleksandar Djindjic <[email protected]>

* use eui form validation error box

Signed-off-by: Aleksandar Djindjic <[email protected]>

* re-generate snapshot

Signed-off-by: Aleksandar Djindjic <[email protected]>

* 153: rule yaml preview

Signed-off-by: Aleksandar Djindjic <[email protected]>

* cypress test for rule yaml preview

Signed-off-by: Aleksandar Djindjic <[email protected]>

* update snapshot test

Signed-off-by: Aleksandar Djindjic <[email protected]>

* propagate ruleId to rule viewers

Signed-off-by: Aleksandar Djindjic <[email protected]>

Signed-off-by: Aleksandar Djindjic <[email protected]>
  • Loading branch information
djindjic authored Dec 16, 2022
1 parent 34d3a57 commit abfa8b8
Show file tree
Hide file tree
Showing 9 changed files with 1,117 additions and 191 deletions.
13 changes: 13 additions & 0 deletions cypress/integration/2_rules.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,19 @@ describe('Rules', () => {
.contains(line, TWENTY_SECONDS_TIMEOUT)
);

cy.get(
'[data-test-subj="change-editor-type"] label:nth-child(2)',
TWENTY_SECONDS_TIMEOUT
).click({
force: true,
});

YAML_RULE_LINES.forEach((line) =>
cy
.get('[data-test-subj="rule_flyout_yaml_rule"]', TWENTY_SECONDS_TIMEOUT)
.contains(line, TWENTY_SECONDS_TIMEOUT)
);

// Close the flyout
cy.get('[data-test-subj="euiFlyoutCloseButton"]', TWENTY_SECONDS_TIMEOUT).click({
force: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { render } from '@testing-library/react';
import { RuleContentViewer } from './RuleContentViewer';

describe('<RuleContentViewer /> spec', () => {
it('renders the component', () => {
const { container } = render(
<RuleContentViewer
rule={
{
prePackaged: false,
_source: {
category: 'dns',
title: 'My Rule',
log_source: 'dns',
description: 'My Rule',
references: [],
tags: [],
level: 'high',
false_positives: [],
author: 'aleksandar',
status: 'stable',
last_update_time: '2022-11-22T23:00:00.000Z',
queries: [
{
value: 'EventID: 4800',
},
],
rule:
'id: 25b9c01c-350d-4b95-bed1-836d04a4f324\ntitle: My Rule\ndescription: My Rule\nstatus: stable\nauthor: aleksandar\ndate: 2022/11/23\nmodified: 2022/11/23\nlogsource:\n category: dns\nlevel: high\ndetection:\n selection:\n EventID: 4800\n condition: selection\n',
detection: 'selection:\n EventID: 4800\ncondition: selection\n',
},
} as any
}
></RuleContentViewer>
);
expect(container.firstChild).toMatchSnapshot();
});
});
283 changes: 161 additions & 122 deletions public/pages/Rules/components/RuleContentViewer/RuleContentViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,144 +14,183 @@ import {
EuiModalBody,
EuiSpacer,
EuiText,
EuiButtonGroup,
} from '@elastic/eui';
import { DEFAULT_EMPTY_DATA } from '../../../../utils/constants';
import React from 'react';
import React, { useState } from 'react';
import { RuleItemInfoBase } from '../../models/types';
import { RuleContentYamlViewer } from './RuleContentYamlViewer';

export interface RuleContentViewerProps {
rule: RuleItemInfoBase;
}

const editorTypes = [
{
id: 'visual',
label: 'Visual',
},
{
id: 'yaml',
label: 'YAML',
},
];

export const RuleContentViewer: React.FC<RuleContentViewerProps> = ({
rule: { prePackaged, _source: ruleData },
rule: { prePackaged, _source: ruleData, _id: ruleId },
}) => {
if (!ruleData.id) {
ruleData.id = ruleId;
}
const [selectedEditorType, setSelectedEditorType] = useState('visual');

const onEditorTypeChange = (optionId: string) => {
setSelectedEditorType(optionId);
};

return (
<EuiModalBody>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem>
<EuiFormLabel>Rule Name</EuiFormLabel>
<EuiText data-test-subj={'rule_flyout_rule_name'}>{ruleData.title}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormLabel>Log Type</EuiFormLabel>
<EuiText data-test-subj={'rule_flyout_rule_log_type'}>{ruleData.category}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer />

<EuiFormLabel>Description</EuiFormLabel>
<EuiText data-test-subj={'rule_flyout_rule_description'}>
{ruleData.description || DEFAULT_EMPTY_DATA}
</EuiText>
<EuiSpacer />

<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem>
<EuiFormLabel>Last Updated</EuiFormLabel>
{ruleData.last_update_time}
</EuiFlexItem>
<EuiFlexItem data-test-subj={'rule_flyout_rule_author'}>
<EuiFormLabel>Author</EuiFormLabel>
{ruleData.author}
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer />

<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem data-test-subj={'rule_flyout_rule_source'}>
<EuiFormLabel>Source</EuiFormLabel>
{prePackaged ? 'Sigma' : 'Custom'}
</EuiFlexItem>
{prePackaged ? (
<EuiFlexItem>
<EuiFormLabel>License</EuiFormLabel>
<EuiLink
target={'_blank'}
href={'https://github.com/SigmaHQ/sigma/blob/master/LICENSE.Detection.Rules.md'}
>
Detection Rule License (DLR)
</EuiLink>
</EuiFlexItem>
) : null}
</EuiFlexGroup>

<EuiSpacer />

<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem data-test-subj={'rule_flyout_rule_severity'}>
<EuiFormLabel>Rule level</EuiFormLabel>
{ruleData.level}
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer />

<EuiFormLabel>Tags</EuiFormLabel>
{ruleData.tags.length > 0 ? (
<EuiFlexGroup direction="row" data-test-subj={'rule_flyout_rule_tags'}>
{ruleData.tags.map((tag: any, i: number) => (
<EuiFlexItem grow={false} key={i}>
<EuiBadge color={'#DDD'}>{tag.value}</EuiBadge>
<EuiButtonGroup
data-test-subj="change-editor-type"
legend="This is editor type selector"
options={editorTypes}
idSelected={selectedEditorType}
onChange={(id) => onEditorTypeChange(id)}
/>
<EuiSpacer size="xl" />
{selectedEditorType === 'visual' && (
<>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem>
<EuiFormLabel>Rule Name</EuiFormLabel>
<EuiText data-test-subj={'rule_flyout_rule_name'}>{ruleData.title}</EuiText>
</EuiFlexItem>
))}
</EuiFlexGroup>
) : (
<div>{DEFAULT_EMPTY_DATA}</div>
)}
<EuiFlexItem>
<EuiFormLabel>Log Type</EuiFormLabel>
<EuiText data-test-subj={'rule_flyout_rule_log_type'}>{ruleData.category}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer />

<EuiFormLabel>Description</EuiFormLabel>
<EuiText data-test-subj={'rule_flyout_rule_description'}>
{ruleData.description || DEFAULT_EMPTY_DATA}
</EuiText>
<EuiSpacer />

<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem>
<EuiFormLabel>Last Updated</EuiFormLabel>
{ruleData.last_update_time}
</EuiFlexItem>
<EuiFlexItem data-test-subj={'rule_flyout_rule_author'}>
<EuiFormLabel>Author</EuiFormLabel>
{ruleData.author}
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer />
<EuiSpacer />

<EuiFormLabel>References</EuiFormLabel>
{ruleData.references.length > 0 ? (
ruleData.references.map((reference: any, i: number) => (
<div key={i}>
<EuiLink
href={reference.value}
target="_blank"
key={reference}
data-test-subj={'rule_flyout_rule_references'}
>
{reference.value}
</EuiLink>
<EuiSpacer />
<EuiSpacer />

<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem data-test-subj={'rule_flyout_rule_source'}>
<EuiFormLabel>Source</EuiFormLabel>
{prePackaged ? 'Sigma' : 'Custom'}
</EuiFlexItem>
{prePackaged ? (
<EuiFlexItem>
<EuiFormLabel>License</EuiFormLabel>
<EuiLink
target={'_blank'}
href={'https://github.com/SigmaHQ/sigma/blob/master/LICENSE.Detection.Rules.md'}
>
Detection Rule License (DLR)
</EuiLink>
</EuiFlexItem>
) : null}
</EuiFlexGroup>

<EuiSpacer />

<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem data-test-subj={'rule_flyout_rule_severity'}>
<EuiFormLabel>Rule level</EuiFormLabel>
{ruleData.level}
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer />

<EuiFormLabel>Tags</EuiFormLabel>
{ruleData.tags.length > 0 ? (
<EuiFlexGroup direction="row" data-test-subj={'rule_flyout_rule_tags'}>
{ruleData.tags.map((tag: any, i: number) => (
<EuiFlexItem grow={false} key={i}>
<EuiBadge color={'#DDD'}>{tag.value}</EuiBadge>
</EuiFlexItem>
))}
</EuiFlexGroup>
) : (
<div>{DEFAULT_EMPTY_DATA}</div>
)}

<EuiSpacer />
<EuiSpacer />

<EuiFormLabel>References</EuiFormLabel>
{ruleData.references.length > 0 ? (
ruleData.references.map((reference: any, i: number) => (
<div key={i}>
<EuiLink
href={reference.value}
target="_blank"
key={reference}
data-test-subj={'rule_flyout_rule_references'}
>
{reference.value}
</EuiLink>
<EuiSpacer />
</div>
))
) : (
<div>{DEFAULT_EMPTY_DATA}</div>
)}

<EuiSpacer />

<EuiFormLabel>False positive cases</EuiFormLabel>
<div data-test-subj={'rule_flyout_rule_false_positives'}>
{ruleData.false_positives.length > 0 ? (
ruleData.false_positives.map((falsepositive: any, i: number) => (
<div key={i}>
{falsepositive.value}
<EuiSpacer />
</div>
))
) : (
<div>{DEFAULT_EMPTY_DATA}</div>
)}
</div>
))
) : (
<div>{DEFAULT_EMPTY_DATA}</div>
)}

<EuiSpacer />

<EuiFormLabel>False positive cases</EuiFormLabel>
<div data-test-subj={'rule_flyout_rule_false_positives'}>
{ruleData.false_positives.length > 0 ? (
ruleData.false_positives.map((falsepositive: any, i: number) => (
<div key={i}>
{falsepositive.value}
<EuiSpacer />
</div>
))
) : (
<div>{DEFAULT_EMPTY_DATA}</div>
)}
</div>

<EuiSpacer />

<EuiFormLabel>Rule Status</EuiFormLabel>
<div data-test-subj={'rule_flyout_rule_status'}>{ruleData.status}</div>

<EuiSpacer />

<EuiFormRow label="Detection" fullWidth>
<EuiCodeBlock language="yaml" data-test-subj={'rule_flyout_rule_detection'}>
{ruleData.detection}
</EuiCodeBlock>
</EuiFormRow>
<EuiSpacer />

<EuiFormLabel>Rule Status</EuiFormLabel>
<div data-test-subj={'rule_flyout_rule_status'}>{ruleData.status}</div>

<EuiSpacer />

<EuiFormRow label="Detection" fullWidth>
<EuiCodeBlock language="yaml" data-test-subj={'rule_flyout_rule_detection'}>
{ruleData.detection}
</EuiCodeBlock>
</EuiFormRow>
</>
)}
{selectedEditorType === 'yaml' && (
<EuiFormRow label="Rule" fullWidth>
<RuleContentYamlViewer rule={ruleData} />
</EuiFormRow>
)}
</EuiModalBody>
);
};
Loading

0 comments on commit abfa8b8

Please sign in to comment.