foreman_openscap 4.3.0 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/foreman_openscap/version.rb +1 -1
  3. data/package.json +48 -0
  4. data/webpack/components/EmptyState.js +67 -0
  5. data/webpack/components/IndexLayout.js +35 -0
  6. data/webpack/components/IndexLayout.scss +3 -0
  7. data/webpack/components/IndexTable/IndexTableHelper.js +9 -0
  8. data/webpack/components/IndexTable/index.js +66 -0
  9. data/webpack/components/RuleSeverity/RuleSeverity.scss +3 -0
  10. data/webpack/components/RuleSeverity/RuleSeverity.test.js +13 -0
  11. data/webpack/components/RuleSeverity/__snapshots__/RuleSeverity.test.js.snap +41 -0
  12. data/webpack/components/RuleSeverity/i_severity-critical.svg +61 -0
  13. data/webpack/components/RuleSeverity/i_severity-high.svg +61 -0
  14. data/webpack/components/RuleSeverity/i_severity-low.svg +62 -0
  15. data/webpack/components/RuleSeverity/i_severity-med.svg +62 -0
  16. data/webpack/components/RuleSeverity/i_unknown.svg +33 -0
  17. data/webpack/components/RuleSeverity/index.js +33 -0
  18. data/webpack/components/withLoading.js +68 -0
  19. data/webpack/global_index.js +5 -0
  20. data/webpack/graphql/queries/cves.gql +18 -0
  21. data/webpack/graphql/queries/ovalContents.gql +11 -0
  22. data/webpack/graphql/queries/ovalPolicies.gql +12 -0
  23. data/webpack/graphql/queries/ovalPolicy.gql +21 -0
  24. data/webpack/helpers/commonHelper.js +1 -0
  25. data/webpack/helpers/globalIdHelper.js +13 -0
  26. data/webpack/helpers/pageParamsHelper.js +31 -0
  27. data/webpack/helpers/pathsHelper.js +22 -0
  28. data/webpack/helpers/tableHelper.js +9 -0
  29. data/webpack/index.js +8 -0
  30. data/webpack/routes/OvalContents/OvalContentsIndex/OvalContentsIndex.js +45 -0
  31. data/webpack/routes/OvalContents/OvalContentsIndex/OvalContentsTable.js +38 -0
  32. data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsIndex.fixtures.js +106 -0
  33. data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsIndex.test.js +75 -0
  34. data/webpack/routes/OvalContents/OvalContentsIndex/index.js +7 -0
  35. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/OvalPoliciesIndex.js +46 -0
  36. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/OvalPoliciesTable.js +44 -0
  37. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesIndex.fixtures.js +61 -0
  38. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesIndex.test.js +78 -0
  39. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/index.js +7 -0
  40. data/webpack/routes/OvalPolicies/OvalPoliciesShow/CvesTab.js +48 -0
  41. data/webpack/routes/OvalPolicies/OvalPoliciesShow/CvesTable.js +63 -0
  42. data/webpack/routes/OvalPolicies/OvalPoliciesShow/OvalPoliciesShow.js +79 -0
  43. data/webpack/routes/OvalPolicies/OvalPoliciesShow/OvalPoliciesShowHelper.js +39 -0
  44. data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesShow.fixtures.js +78 -0
  45. data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesShow.test.js +112 -0
  46. data/webpack/routes/OvalPolicies/OvalPoliciesShow/index.js +35 -0
  47. data/webpack/routes/routes.js +28 -0
  48. data/webpack/testHelper.js +64 -0
  49. metadata +48 -2
@@ -0,0 +1,106 @@
1
+ import ovalContentsQuery from '../../../../graphql/queries/ovalContents.gql';
2
+ import { ovalContentsPath } from '../../../../helpers/pathsHelper';
3
+ import { mockFactory } from '../../../../testHelper';
4
+
5
+ const ovalContentMockFactory = mockFactory('ovalContents', ovalContentsQuery);
6
+
7
+ export const mocks = [
8
+ {
9
+ request: {
10
+ query: ovalContentsQuery,
11
+ variables: {
12
+ first: 20,
13
+ last: 20,
14
+ },
15
+ },
16
+ result: {
17
+ data: {
18
+ ovalContents: {
19
+ totalCount: 4,
20
+ nodes: [
21
+ {
22
+ id: 'abc',
23
+ name: 'ansible OVAL content',
24
+ url:
25
+ 'http://oval-content-source/security/data/oval/ansible-2-including-unpatched.oval.xml.bz2',
26
+ originalFilename: '',
27
+ },
28
+ {
29
+ id: 'bcd',
30
+ name: 'dotnet OVAL content',
31
+ url:
32
+ 'http://oval-content-source/security/data/oval/dotnet-2.2.oval.xml.bz2',
33
+ originalFilename: '',
34
+ },
35
+ {
36
+ id: 'cde',
37
+ name: 'jboss OVAL content',
38
+ url: '',
39
+ originalFilename: 'jboss.oval.xml.bz2',
40
+ },
41
+ {
42
+ id: 'def',
43
+ name: 'openshift OVAL content',
44
+ url: '',
45
+ originalFilename: 'openshift.oval.xml.bz2',
46
+ },
47
+ ],
48
+ },
49
+ },
50
+ },
51
+ },
52
+ ];
53
+
54
+ export const paginatedMocks = [
55
+ {
56
+ request: {
57
+ query: ovalContentsQuery,
58
+ variables: {
59
+ first: 10,
60
+ last: 5,
61
+ },
62
+ },
63
+ result: {
64
+ data: {
65
+ ovalContents: {
66
+ totalCount: 7,
67
+ nodes: [
68
+ {
69
+ id: 'bcd',
70
+ name: 'dotnet OVAL content',
71
+ url:
72
+ 'http://oval-content-source/security/data/oval/dotnet-2.2.oval.xml.bz2',
73
+ originalFilename: '',
74
+ },
75
+ {
76
+ id: 'def',
77
+ name: 'openshift OVAL content',
78
+ url: '',
79
+ originalFilename: 'openshift.oval.xml.bz2',
80
+ },
81
+ ],
82
+ },
83
+ },
84
+ },
85
+ },
86
+ ];
87
+
88
+ export const emptyMocks = ovalContentMockFactory(
89
+ { first: 20, last: 20 },
90
+ { totalCount: 0, nodes: [] }
91
+ );
92
+ export const errorMocks = ovalContentMockFactory(
93
+ { first: 20, last: 20 },
94
+ { totalCount: 0, nodes: [] },
95
+ [{ message: 'Something very bad happened.' }]
96
+ );
97
+
98
+ export const pushMock = jest.fn();
99
+
100
+ export const pagePaginationHistoryMock = {
101
+ location: {
102
+ search: '?page=2&perPage=5',
103
+ pathname: ovalContentsPath,
104
+ },
105
+ push: pushMock,
106
+ };
@@ -0,0 +1,75 @@
1
+ import React from 'react';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import { within } from '@testing-library/dom';
4
+ import userEvent from '@testing-library/user-event';
5
+ import '@testing-library/jest-dom';
6
+
7
+ import OvalContentsIndex from '../OvalContentsIndex';
8
+
9
+ import { withMockedProvider, tick, historyMock } from '../../../../testHelper';
10
+ import { ovalContentsPath } from '../../../../helpers/pathsHelper';
11
+
12
+ import {
13
+ mocks,
14
+ paginatedMocks,
15
+ pushMock,
16
+ pagePaginationHistoryMock,
17
+ emptyMocks,
18
+ errorMocks,
19
+ } from './OvalContentsIndex.fixtures';
20
+
21
+ const TestComponent = withMockedProvider(OvalContentsIndex);
22
+
23
+ describe('OvalContentsIndex', () => {
24
+ it('should load page', async () => {
25
+ const { container } = render(
26
+ <TestComponent history={historyMock} mocks={mocks} />
27
+ );
28
+ expect(screen.getByText('Loading')).toBeInTheDocument();
29
+ await waitFor(tick);
30
+ expect(screen.queryByText('Loading')).not.toBeInTheDocument();
31
+ expect(screen.getByText('ansible OVAL content')).toBeInTheDocument();
32
+ expect(screen.getByText('openshift OVAL content')).toBeInTheDocument();
33
+ const pageItems = container.querySelector('.pf-c-pagination__total-items');
34
+ expect(within(pageItems).getByText(/1 - 4/)).toBeInTheDocument();
35
+ expect(within(pageItems).getByText('of')).toBeInTheDocument();
36
+ expect(within(pageItems).getByText('4')).toBeInTheDocument();
37
+ });
38
+ it('should load page with pagination params', async () => {
39
+ const { container } = render(
40
+ <TestComponent
41
+ history={pagePaginationHistoryMock}
42
+ mocks={paginatedMocks}
43
+ />
44
+ );
45
+ await waitFor(tick);
46
+ const pageItems = container.querySelector('.pf-c-pagination__total-items');
47
+ expect(within(pageItems).getByText(/6 - 7/)).toBeInTheDocument();
48
+ expect(within(pageItems).getByText('of')).toBeInTheDocument();
49
+ expect(within(pageItems).getByText('7')).toBeInTheDocument();
50
+ userEvent.click(
51
+ screen.getByRole('button', { name: 'Go to previous page' })
52
+ );
53
+
54
+ expect(pushMock).toHaveBeenCalledWith(
55
+ `${ovalContentsPath}?page=1&perPage=5`
56
+ );
57
+ });
58
+ it('should show empty state', async () => {
59
+ render(<TestComponent history={historyMock} mocks={emptyMocks} />);
60
+ expect(screen.getByText('Loading')).toBeInTheDocument();
61
+ await waitFor(tick);
62
+ expect(screen.queryByText('Loading')).not.toBeInTheDocument();
63
+ expect(screen.getByText('No OVAL Contents found.')).toBeInTheDocument();
64
+ });
65
+ it('should show errors', async () => {
66
+ render(<TestComponent history={historyMock} mocks={errorMocks} />);
67
+ expect(screen.getByText('Loading')).toBeInTheDocument();
68
+ await waitFor(tick);
69
+ expect(screen.queryByText('Loading')).not.toBeInTheDocument();
70
+ expect(
71
+ screen.getByText('Something very bad happened.')
72
+ ).toBeInTheDocument();
73
+ expect(screen.getByText('Error!')).toBeInTheDocument();
74
+ });
75
+ });
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+
3
+ import OvalContentsIndex from './OvalContentsIndex';
4
+
5
+ const WrappedOvalContentsIndex = props => <OvalContentsIndex {...props} />;
6
+
7
+ export default WrappedOvalContentsIndex;
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useQuery } from '@apollo/client';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+
6
+ import OvalPoliciesTable from './OvalPoliciesTable';
7
+ import IndexLayout from '../../../components/IndexLayout';
8
+
9
+ import {
10
+ useParamsToVars,
11
+ useCurrentPagination,
12
+ } from '../../../helpers/pageParamsHelper';
13
+ import policiesQuery from '../../../graphql/queries/ovalPolicies.gql';
14
+
15
+ const OvalPoliciesIndex = props => {
16
+ const pagination = useCurrentPagination(props.history);
17
+
18
+ const useFetchFn = componentProps =>
19
+ useQuery(policiesQuery, {
20
+ variables: useParamsToVars(componentProps.history),
21
+ });
22
+
23
+ const renameData = data => ({
24
+ policies: data.ovalPolicies.nodes,
25
+ totalCount: data.ovalPolicies.totalCount,
26
+ });
27
+
28
+ return (
29
+ <IndexLayout pageTitle={__('OVAL Policies')}>
30
+ <OvalPoliciesTable
31
+ {...props}
32
+ fetchFn={useFetchFn}
33
+ renameData={renameData}
34
+ resultPath="ovalPolicies.nodes"
35
+ pagination={pagination}
36
+ emptyStateTitle={__('No OVAL Policies found')}
37
+ />
38
+ </IndexLayout>
39
+ );
40
+ };
41
+
42
+ OvalPoliciesIndex.propTypes = {
43
+ history: PropTypes.object.isRequired,
44
+ };
45
+
46
+ export default OvalPoliciesIndex;
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+
5
+ import IndexTable from '../../../components/IndexTable';
6
+ import withLoading from '../../../components/withLoading';
7
+
8
+ import { linkCell } from '../../../helpers/tableHelper';
9
+ import { ovalPoliciesPath, modelPath } from '../../../helpers/pathsHelper';
10
+
11
+ const OvalPoliciesTable = props => {
12
+ const columns = [{ title: __('Name') }, { title: __('OVAL Content') }];
13
+
14
+ const rows = props.policies.map(policy => ({
15
+ cells: [
16
+ { title: linkCell(modelPath(ovalPoliciesPath, policy), policy.name) },
17
+ { title: policy.ovalContent.name },
18
+ ],
19
+ policy,
20
+ }));
21
+
22
+ const actions = [];
23
+
24
+ return (
25
+ <IndexTable
26
+ columns={columns}
27
+ rows={rows}
28
+ actions={actions}
29
+ pagination={props.pagination}
30
+ totalCount={props.totalCount}
31
+ history={props.history}
32
+ ariaTableLabel={__('OVAL Policies Table')}
33
+ />
34
+ );
35
+ };
36
+
37
+ OvalPoliciesTable.propTypes = {
38
+ policies: PropTypes.array.isRequired,
39
+ pagination: PropTypes.object.isRequired,
40
+ totalCount: PropTypes.number.isRequired,
41
+ history: PropTypes.object.isRequired,
42
+ };
43
+
44
+ export default withLoading(OvalPoliciesTable);
@@ -0,0 +1,61 @@
1
+ import policiesQuery from '../../../../graphql/queries/ovalPolicies.gql';
2
+ import { ovalPoliciesPath } from '../../../../helpers/pathsHelper';
3
+ import { mockFactory } from '../../../../testHelper';
4
+
5
+ const policiesMockFactory = mockFactory('ovalPolicies', policiesQuery);
6
+
7
+ export const pushMock = jest.fn();
8
+
9
+ export const pageParamsHistoryMock = {
10
+ location: {
11
+ search: '?page=2&perPage=5',
12
+ pathname: ovalPoliciesPath,
13
+ },
14
+ push: pushMock,
15
+ };
16
+
17
+ export const mocks = policiesMockFactory(
18
+ { first: 20, last: 20 },
19
+ {
20
+ totalCount: 2,
21
+ nodes: [
22
+ {
23
+ id: 'abc',
24
+ name: 'first policy',
25
+ ovalContent: { name: 'first content' },
26
+ },
27
+ {
28
+ id: 'xyz',
29
+ name: 'second policy',
30
+ ovalContent: { name: 'second content' },
31
+ },
32
+ ],
33
+ }
34
+ );
35
+ export const pageParamsMocks = policiesMockFactory(
36
+ { first: 10, last: 5 },
37
+ {
38
+ totalCount: 7,
39
+ nodes: [
40
+ {
41
+ id: 'xyz',
42
+ name: 'sixth policy',
43
+ ovalContent: { name: 'sixth content' },
44
+ },
45
+ {
46
+ id: 'abc',
47
+ name: 'seventh policy',
48
+ ovalContent: { name: 'seventh content' },
49
+ },
50
+ ],
51
+ }
52
+ );
53
+ export const emptyMocks = policiesMockFactory(
54
+ { first: 20, last: 20 },
55
+ { totalCount: 0, nodes: [] }
56
+ );
57
+ export const errorMocks = policiesMockFactory(
58
+ { first: 20, last: 20 },
59
+ { totalCount: 0, nodes: [] },
60
+ [{ message: 'Something very bad happened.' }]
61
+ );
@@ -0,0 +1,78 @@
1
+ import React from 'react';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { within } from '@testing-library/dom';
5
+ import '@testing-library/jest-dom';
6
+
7
+ import {
8
+ withMockedProvider,
9
+ withRouter,
10
+ tick,
11
+ historyMock,
12
+ } from '../../../../testHelper';
13
+
14
+ import {
15
+ mocks,
16
+ pushMock,
17
+ pageParamsMocks,
18
+ pageParamsHistoryMock,
19
+ emptyMocks,
20
+ errorMocks,
21
+ } from './OvalPoliciesIndex.fixtures';
22
+
23
+ import OvalPoliciesIndex from '../OvalPoliciesIndex';
24
+ import { ovalPoliciesPath } from '../../../../helpers/pathsHelper';
25
+
26
+ const TestComponent = withRouter(withMockedProvider(OvalPoliciesIndex));
27
+
28
+ describe('OvalPoliciesIndex', () => {
29
+ it('should load page', async () => {
30
+ const { container } = render(
31
+ <TestComponent history={historyMock} mocks={mocks} />
32
+ );
33
+ expect(screen.getByText('Loading')).toBeInTheDocument();
34
+ await waitFor(tick);
35
+ expect(screen.getByText('first policy')).toBeInTheDocument();
36
+ expect(screen.getByText('second policy')).toBeInTheDocument();
37
+ expect(screen.getByText('first content')).toBeInTheDocument();
38
+ expect(screen.getByText('second content')).toBeInTheDocument();
39
+ const pageItems = container.querySelector('.pf-c-pagination__total-items');
40
+ expect(within(pageItems).getByText(/1 - 2/)).toBeInTheDocument();
41
+ expect(within(pageItems).getByText('of')).toBeInTheDocument();
42
+ expect(within(pageItems).getByText('2')).toBeInTheDocument();
43
+ });
44
+ it('should load page with page params', async () => {
45
+ const { container } = render(
46
+ <TestComponent history={pageParamsHistoryMock} mocks={pageParamsMocks} />
47
+ );
48
+ await waitFor(tick);
49
+ const pageItems = container.querySelector('.pf-c-pagination__total-items');
50
+ expect(within(pageItems).getByText(/6 - 7/)).toBeInTheDocument();
51
+ expect(within(pageItems).getByText('of')).toBeInTheDocument();
52
+ expect(within(pageItems).getByText('7')).toBeInTheDocument();
53
+ userEvent.click(
54
+ screen.getByRole('button', { name: 'Go to previous page' })
55
+ );
56
+
57
+ expect(pushMock).toHaveBeenCalledWith(
58
+ `${ovalPoliciesPath}?page=1&perPage=5`
59
+ );
60
+ });
61
+ it('should show empty state', async () => {
62
+ render(<TestComponent history={historyMock} mocks={emptyMocks} />);
63
+ expect(screen.getByText('Loading')).toBeInTheDocument();
64
+ await waitFor(tick);
65
+ expect(screen.queryByText('Loading')).not.toBeInTheDocument();
66
+ expect(screen.getByText('No OVAL Policies found')).toBeInTheDocument();
67
+ });
68
+ it('should show errors', async () => {
69
+ render(<TestComponent history={historyMock} mocks={errorMocks} />);
70
+ expect(screen.getByText('Loading')).toBeInTheDocument();
71
+ await waitFor(tick);
72
+ expect(screen.queryByText('Loading')).not.toBeInTheDocument();
73
+ expect(
74
+ screen.getByText('Something very bad happened.')
75
+ ).toBeInTheDocument();
76
+ expect(screen.getByText('Error!')).toBeInTheDocument();
77
+ });
78
+ });
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+
3
+ import OvalPoliciesIndex from './OvalPoliciesIndex';
4
+
5
+ const WrappedOvalPoliciesIndex = props => <OvalPoliciesIndex {...props} />;
6
+
7
+ export default WrappedOvalPoliciesIndex;
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+
5
+ import { useQuery } from '@apollo/client';
6
+
7
+ import CvesTable from './CvesTable';
8
+
9
+ import cves from '../../../graphql/queries/cves.gql';
10
+ import {
11
+ useParamsToVars,
12
+ useCurrentPagination,
13
+ } from '../../../helpers/pageParamsHelper';
14
+
15
+ const CvesTab = props => {
16
+ const useFetchFn = componentProps =>
17
+ useQuery(cves, {
18
+ variables: {
19
+ search: `oval_policy_id = ${componentProps.match.params.id}`,
20
+ ...useParamsToVars(componentProps.history),
21
+ },
22
+ });
23
+
24
+ const renameData = data => ({
25
+ cves: data.cves.nodes,
26
+ totalCount: data.cves.totalCount,
27
+ });
28
+
29
+ const pagination = useCurrentPagination(props.history);
30
+
31
+ return (
32
+ <CvesTable
33
+ {...props}
34
+ fetchFn={useFetchFn}
35
+ renameData={renameData}
36
+ resultPath="cves.nodes"
37
+ pagination={pagination}
38
+ emptyStateTitle={__('No CVEs found.')}
39
+ />
40
+ );
41
+ };
42
+
43
+ CvesTab.propTypes = {
44
+ match: PropTypes.object.isRequired,
45
+ history: PropTypes.object.isRequired,
46
+ };
47
+
48
+ export default CvesTab;