foreman_openscap 7.1.1 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_openscap/locale/cs_CZ/foreman_openscap.js +517 -421
  3. data/app/assets/javascripts/foreman_openscap/locale/de/foreman_openscap.js +907 -814
  4. data/app/assets/javascripts/foreman_openscap/locale/en/foreman_openscap.js +517 -421
  5. data/app/assets/javascripts/foreman_openscap/locale/en_GB/foreman_openscap.js +549 -453
  6. data/app/assets/javascripts/foreman_openscap/locale/es/foreman_openscap.js +911 -818
  7. data/app/assets/javascripts/foreman_openscap/locale/fr/foreman_openscap.js +911 -818
  8. data/app/assets/javascripts/foreman_openscap/locale/gl/foreman_openscap.js +556 -460
  9. data/app/assets/javascripts/foreman_openscap/locale/it/foreman_openscap.js +601 -505
  10. data/app/assets/javascripts/foreman_openscap/locale/ja/foreman_openscap.js +909 -816
  11. data/app/assets/javascripts/foreman_openscap/locale/ka/foreman_openscap.js +96 -0
  12. data/app/assets/javascripts/foreman_openscap/locale/ko/foreman_openscap.js +704 -611
  13. data/app/assets/javascripts/foreman_openscap/locale/pt_BR/foreman_openscap.js +911 -818
  14. data/app/assets/javascripts/foreman_openscap/locale/ru/foreman_openscap.js +706 -613
  15. data/app/assets/javascripts/foreman_openscap/locale/sv_SE/foreman_openscap.js +556 -460
  16. data/app/assets/javascripts/foreman_openscap/locale/zh_CN/foreman_openscap.js +909 -816
  17. data/app/assets/javascripts/foreman_openscap/locale/zh_TW/foreman_openscap.js +704 -611
  18. data/app/assets/javascripts/foreman_openscap/reports.js +5 -0
  19. data/app/controllers/arf_reports_controller.rb +23 -2
  20. data/app/helpers/arf_reports_helper.rb +17 -4
  21. data/app/models/foreman_openscap/arf_report.rb +11 -2
  22. data/app/views/arf_reports/_output.html.erb +5 -1
  23. data/app/views/job_templates/run_openscap_remediation_-_ansible_default.erb +27 -0
  24. data/app/views/job_templates/run_openscap_remediation_-_script_default.erb +24 -0
  25. data/config/routes.rb +1 -0
  26. data/db/migrate/20230912122310_add_fixes_to_message.rb +5 -0
  27. data/lib/foreman_openscap/engine.rb +18 -2
  28. data/lib/foreman_openscap/version.rb +1 -1
  29. data/lib/tasks/foreman_openscap_tasks.rake +5 -16
  30. data/locale/cs_CZ/foreman_openscap.edit.po +145 -17
  31. data/locale/cs_CZ/foreman_openscap.po +96 -0
  32. data/locale/de/foreman_openscap.edit.po +248 -282
  33. data/locale/de/foreman_openscap.po +96 -0
  34. data/locale/en/foreman_openscap.edit.po +145 -17
  35. data/locale/en/foreman_openscap.po +96 -0
  36. data/locale/en_GB/foreman_openscap.edit.po +145 -17
  37. data/locale/en_GB/foreman_openscap.po +96 -0
  38. data/locale/es/foreman_openscap.edit.po +241 -279
  39. data/locale/es/foreman_openscap.po +96 -0
  40. data/locale/foreman_openscap.pot +164 -12
  41. data/locale/fr/foreman_openscap.edit.po +330 -363
  42. data/locale/fr/foreman_openscap.po +96 -0
  43. data/locale/gl/foreman_openscap.edit.po +145 -17
  44. data/locale/gl/foreman_openscap.po +96 -0
  45. data/locale/it/foreman_openscap.edit.po +145 -17
  46. data/locale/it/foreman_openscap.po +96 -0
  47. data/locale/ja/foreman_openscap.edit.po +314 -347
  48. data/locale/ja/foreman_openscap.po +96 -0
  49. data/locale/ka/foreman_openscap.edit.po +289 -328
  50. data/locale/ka/foreman_openscap.po +96 -0
  51. data/locale/ka/foreman_openscap.po.time_stamp +0 -0
  52. data/locale/ko/foreman_openscap.edit.po +146 -18
  53. data/locale/ko/foreman_openscap.po +96 -0
  54. data/locale/pt_BR/foreman_openscap.edit.po +247 -279
  55. data/locale/pt_BR/foreman_openscap.po +96 -0
  56. data/locale/ru/foreman_openscap.edit.po +146 -18
  57. data/locale/ru/foreman_openscap.po +96 -0
  58. data/locale/sv_SE/foreman_openscap.edit.po +145 -17
  59. data/locale/sv_SE/foreman_openscap.po +96 -0
  60. data/locale/zh_CN/foreman_openscap.edit.po +314 -347
  61. data/locale/zh_CN/foreman_openscap.po +96 -0
  62. data/locale/zh_TW/foreman_openscap.edit.po +146 -18
  63. data/locale/zh_TW/foreman_openscap.po +96 -0
  64. data/webpack/components/EmptyState.js +6 -2
  65. data/webpack/components/OpenscapRemediationWizard/OpenscapRemediationSelectors.js +16 -0
  66. data/webpack/components/OpenscapRemediationWizard/OpenscapRemediationWizardContext.js +4 -0
  67. data/webpack/components/OpenscapRemediationWizard/ViewSelectedHostsLink.js +38 -0
  68. data/webpack/components/OpenscapRemediationWizard/WizardHeader.js +43 -0
  69. data/webpack/components/OpenscapRemediationWizard/constants.js +14 -0
  70. data/webpack/components/OpenscapRemediationWizard/helpers.js +33 -0
  71. data/webpack/components/OpenscapRemediationWizard/index.js +160 -0
  72. data/webpack/components/OpenscapRemediationWizard/steps/Finish.js +131 -0
  73. data/webpack/components/OpenscapRemediationWizard/steps/ReviewHosts.js +217 -0
  74. data/webpack/components/OpenscapRemediationWizard/steps/ReviewRemediation.js +176 -0
  75. data/webpack/components/OpenscapRemediationWizard/steps/ReviewRemediation.scss +4 -0
  76. data/webpack/components/OpenscapRemediationWizard/steps/SnippetSelect.js +160 -0
  77. data/webpack/components/OpenscapRemediationWizard/steps/index.js +4 -0
  78. data/webpack/index.js +8 -3
  79. data/webpack/testHelper.js +6 -5
  80. metadata +20 -3
@@ -0,0 +1,217 @@
1
+ import React, { useContext, useState, useEffect } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import {
4
+ Spinner,
5
+ Toolbar,
6
+ ToolbarContent,
7
+ ToolbarGroup,
8
+ ToolbarItem,
9
+ } from '@patternfly/react-core';
10
+ import { Td } from '@patternfly/react-table';
11
+ import { toArray } from 'lodash';
12
+
13
+ import { foremanUrl } from 'foremanReact/common/helpers';
14
+ import { translate as __ } from 'foremanReact/common/I18n';
15
+ import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
16
+ import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table';
17
+ import { useBulkSelect } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHooks';
18
+ import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
19
+ import { STATUS } from 'foremanReact/constants';
20
+ import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
21
+
22
+ import OpenscapRemediationWizardContext from '../OpenscapRemediationWizardContext';
23
+ import WizardHeader from '../WizardHeader';
24
+ import { HOSTS_API_PATH, HOSTS_API_REQUEST_KEY } from '../constants';
25
+
26
+ const ReviewHosts = () => {
27
+ const {
28
+ hostId,
29
+ setHostIdsParam,
30
+ defaultFailedHostsSearch,
31
+ setIsAllHostsSelected,
32
+ savedHostSelectionsRef,
33
+ } = useContext(OpenscapRemediationWizardContext);
34
+
35
+ const defaultParams = {
36
+ search: defaultFailedHostsSearch,
37
+ };
38
+ const defaultHostsArry = [hostId];
39
+
40
+ const [params, setParams] = useState(defaultParams);
41
+
42
+ const response = useAPI('get', `${HOSTS_API_PATH}?include_permissions=true`, {
43
+ key: HOSTS_API_REQUEST_KEY,
44
+ params: defaultParams,
45
+ });
46
+ const {
47
+ response: {
48
+ search: apiSearchQuery,
49
+ results,
50
+ per_page: perPage,
51
+ page,
52
+ subtotal,
53
+ message: errorMessage,
54
+ },
55
+ status = STATUS.PENDING,
56
+ setAPIOptions,
57
+ } = response;
58
+
59
+ const subtotalCount = Number(subtotal ?? 0);
60
+
61
+ const setParamsAndAPI = newParams => {
62
+ setParams(newParams);
63
+ setAPIOptions({ key: HOSTS_API_REQUEST_KEY, params: newParams });
64
+ };
65
+
66
+ const { pageRowCount } = getPageStats({
67
+ total: subtotalCount,
68
+ page,
69
+ perPage,
70
+ });
71
+ const { fetchBulkParams, ...selectAllOptions } = useBulkSelect({
72
+ results,
73
+ metadata: { total: subtotalCount, page },
74
+ initialSearchQuery: apiSearchQuery || defaultFailedHostsSearch,
75
+ isSelectable: () => true,
76
+ defaultArry: defaultHostsArry,
77
+ initialArry: toArray(
78
+ savedHostSelectionsRef.current.inclusionSet || defaultHostsArry
79
+ ),
80
+ initialExclusionArry: toArray(
81
+ savedHostSelectionsRef.current.exclusionSet || []
82
+ ),
83
+ initialSelectAllMode: savedHostSelectionsRef.current.selectAllMode || false,
84
+ });
85
+ const {
86
+ selectPage,
87
+ selectedCount,
88
+ selectOne,
89
+ selectNone,
90
+ selectDefault,
91
+ selectAll,
92
+ areAllRowsOnPageSelected,
93
+ areAllRowsSelected,
94
+ isSelected,
95
+ inclusionSet,
96
+ exclusionSet,
97
+ selectAllMode,
98
+ } = selectAllOptions;
99
+
100
+ useEffect(() => {
101
+ if (selectedCount) {
102
+ setHostIdsParam(fetchBulkParams());
103
+ savedHostSelectionsRef.current = {
104
+ inclusionSet,
105
+ exclusionSet,
106
+ selectAllMode,
107
+ };
108
+ }
109
+ }, [selectedCount, fetchBulkParams, setHostIdsParam]);
110
+
111
+ const selectionToolbar = (
112
+ <ToolbarItem key="selectAll">
113
+ <SelectAllCheckbox
114
+ {...{
115
+ selectAll: () => {
116
+ selectAll(true);
117
+ setIsAllHostsSelected(true);
118
+ },
119
+ selectPage: () => {
120
+ selectPage();
121
+ setIsAllHostsSelected(false);
122
+ },
123
+ selectDefault: () => {
124
+ selectDefault();
125
+ setIsAllHostsSelected(false);
126
+ },
127
+ selectNone: () => {
128
+ selectNone();
129
+ setIsAllHostsSelected(false);
130
+ },
131
+ selectedCount,
132
+ pageRowCount,
133
+ }}
134
+ totalCount={subtotalCount}
135
+ selectedDefaultCount={1} // The default host (hostId) is always selected
136
+ areAllRowsOnPageSelected={areAllRowsOnPageSelected()}
137
+ areAllRowsSelected={areAllRowsSelected()}
138
+ />
139
+ </ToolbarItem>
140
+ );
141
+
142
+ const RowSelectTd = ({ rowData }) => (
143
+ <Td
144
+ select={{
145
+ rowIndex: rowData.id,
146
+ onSelect: (_event, isSelecting) => {
147
+ selectOne(isSelecting, rowData.id, rowData);
148
+ // If at least one was unselected, then it's not all selected
149
+ if (!isSelecting) setIsAllHostsSelected(false);
150
+ },
151
+ isSelected: rowData.id === hostId || isSelected(rowData.id),
152
+ disable: rowData.id === hostId || false,
153
+ }}
154
+ />
155
+ );
156
+ RowSelectTd.propTypes = {
157
+ rowData: PropTypes.object.isRequired,
158
+ };
159
+
160
+ const columns = {
161
+ name: {
162
+ title: __('Name'),
163
+ wrapper: ({ id, name }) => <a href={foremanUrl(`hosts/${id}`)}>{name}</a>,
164
+ isSorted: true,
165
+ },
166
+ operatingsystem_name: {
167
+ title: __('OS'),
168
+ },
169
+ };
170
+
171
+ return (
172
+ <>
173
+ <WizardHeader
174
+ title={__('Review hosts')}
175
+ description={__(
176
+ 'By default, remediation is applied to the current host. Optionally, remediate any additional hosts that fail the rule.'
177
+ )}
178
+ />
179
+ <Toolbar ouiaId="table-toolbar" className="table-toolbar">
180
+ <ToolbarContent>
181
+ <ToolbarGroup>
182
+ {selectionToolbar}
183
+ {status === STATUS.PENDING && (
184
+ <ToolbarItem>
185
+ <Spinner size="sm" />
186
+ </ToolbarItem>
187
+ )}
188
+ </ToolbarGroup>
189
+ </ToolbarContent>
190
+ </Toolbar>
191
+ <Table
192
+ ouiaId="hosts-review-table"
193
+ isEmbedded
194
+ params={params}
195
+ setParams={setParamsAndAPI}
196
+ itemCount={subtotalCount}
197
+ results={results}
198
+ url={HOSTS_API_PATH}
199
+ refreshData={() =>
200
+ setAPIOptions({
201
+ key: HOSTS_API_REQUEST_KEY,
202
+ params: { defaultFailedHostsSearch },
203
+ })
204
+ }
205
+ columns={columns}
206
+ errorMessage={
207
+ status === STATUS.ERROR && errorMessage ? errorMessage : null
208
+ }
209
+ isPending={status === STATUS.PENDING}
210
+ showCheckboxes
211
+ rowSelectTd={RowSelectTd}
212
+ />
213
+ </>
214
+ );
215
+ };
216
+
217
+ export default ReviewHosts;
@@ -0,0 +1,176 @@
1
+ /* eslint-disable camelcase */
2
+ import React, { useContext, useState } from 'react';
3
+ import { some } from 'lodash';
4
+ import {
5
+ CodeBlock,
6
+ CodeBlockAction,
7
+ CodeBlockCode,
8
+ ClipboardCopyButton,
9
+ Button,
10
+ Grid,
11
+ GridItem,
12
+ Alert,
13
+ Checkbox,
14
+ } from '@patternfly/react-core';
15
+ import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';
16
+
17
+ import { translate as __ } from 'foremanReact/common/I18n';
18
+ import { foremanUrl } from 'foremanReact/common/helpers';
19
+ import { getHostsPageUrl } from 'foremanReact/Root/Context/ForemanContext';
20
+
21
+ import OpenscapRemediationWizardContext from '../OpenscapRemediationWizardContext';
22
+ import WizardHeader from '../WizardHeader';
23
+ import ViewSelectedHostsLink from '../ViewSelectedHostsLink';
24
+ import { HOSTS_PATH, FAIL_RULE_SEARCH } from '../constants';
25
+ import { findFixBySnippet } from '../helpers';
26
+
27
+ import './ReviewRemediation.scss';
28
+
29
+ const ReviewRemediation = () => {
30
+ const {
31
+ fixes,
32
+ snippet,
33
+ method,
34
+ hostName,
35
+ source,
36
+ isRebootSelected,
37
+ setIsRebootSelected,
38
+ isAllHostsSelected,
39
+ hostIdsParam,
40
+ defaultFailedHostsSearch,
41
+ } = useContext(OpenscapRemediationWizardContext);
42
+ const [copied, setCopied] = useState(false);
43
+ const selectedFix = findFixBySnippet(fixes, snippet);
44
+ const snippetText = selectedFix?.full_text;
45
+ // can be one of null, "true", "false"
46
+ // if null, it may indicate that reboot might be needed
47
+ const checkForReboot = () => !some(fixes, { reboot: 'false' });
48
+ const isRebootRequired = () => some(fixes, { reboot: 'true' });
49
+
50
+ const copyToClipboard = (e, text) => {
51
+ navigator.clipboard.writeText(text.toString());
52
+ };
53
+
54
+ const onCopyClick = (e, text) => {
55
+ copyToClipboard(e, text);
56
+ setCopied(true);
57
+ };
58
+
59
+ const description =
60
+ method === 'manual'
61
+ ? __('Review the remediation snippet and apply it to the host manually.')
62
+ : __(
63
+ 'Review the remediation snippet that will be applied to selected host(s).'
64
+ );
65
+
66
+ const rebootAlertTitle = isRebootRequired()
67
+ ? __('A reboot is required after applying remediation.')
68
+ : __('A reboot might be required after applying remediation.');
69
+
70
+ const actions = (
71
+ <React.Fragment>
72
+ <CodeBlockAction>
73
+ <ClipboardCopyButton
74
+ id="basic-copy-button"
75
+ textId="code-content"
76
+ aria-label="Copy to clipboard"
77
+ onClick={e => onCopyClick(e, snippetText)}
78
+ exitDelay={copied ? 1500 : 600}
79
+ maxWidth="110px"
80
+ variant="plain"
81
+ onTooltipHidden={() => setCopied(false)}
82
+ >
83
+ {copied
84
+ ? __('Successfully copied to clipboard!')
85
+ : __('Copy to clipboard')}
86
+ </ClipboardCopyButton>
87
+ </CodeBlockAction>
88
+ </React.Fragment>
89
+ );
90
+
91
+ return (
92
+ <>
93
+ <WizardHeader
94
+ title={__('Review remediation')}
95
+ description={description}
96
+ />
97
+ <Grid hasGutter>
98
+ <br />
99
+ <GridItem>
100
+ <Alert
101
+ ouiaId="review-alert"
102
+ variant="danger"
103
+ title={`${__(
104
+ 'Do not implement any of the recommended remedial actions or scripts without first testing them in a non-production environment.'
105
+ )}
106
+ ${__('Remediation might render the system non-functional.')}`}
107
+ />
108
+ </GridItem>
109
+ <GridItem md={12} span={4} rowSpan={1}>
110
+ <ViewSelectedHostsLink
111
+ isAllHostsSelected={isAllHostsSelected}
112
+ hostIdsParam={hostIdsParam}
113
+ defaultFailedHostsSearch={defaultFailedHostsSearch}
114
+ />
115
+ </GridItem>
116
+ <GridItem md={12} span={4} rowSpan={1}>
117
+ <Button
118
+ variant="link"
119
+ icon={<ExternalLinkSquareAltIcon />}
120
+ iconPosition="right"
121
+ target="_blank"
122
+ component="a"
123
+ href={foremanUrl(`${getHostsPageUrl(true)}/${hostName}`)}
124
+ >
125
+ {hostName}
126
+ </Button>{' '}
127
+ </GridItem>
128
+ <GridItem md={12} span={8} rowSpan={1}>
129
+ <Button
130
+ variant="link"
131
+ icon={<ExternalLinkSquareAltIcon />}
132
+ iconPosition="right"
133
+ target="_blank"
134
+ component="a"
135
+ href={foremanUrl(
136
+ `${HOSTS_PATH}/?search=${FAIL_RULE_SEARCH} = ${source}`
137
+ )}
138
+ >
139
+ {__('Other hosts failing this rule')}
140
+ </Button>
141
+ </GridItem>
142
+ {checkForReboot() ? (
143
+ <>
144
+ <GridItem span={12} rowSpan={1}>
145
+ <Alert
146
+ ouiaId="reboot-alert"
147
+ variant={isRebootRequired() ? 'warning' : 'info'}
148
+ title={rebootAlertTitle}
149
+ />
150
+ </GridItem>
151
+ {method === 'manual' ? null : (
152
+ <GridItem span={4} rowSpan={1}>
153
+ <Checkbox
154
+ id="reboot-checkbox"
155
+ label={__('Reboot the system(s)')}
156
+ name="reboot-checkbox"
157
+ isChecked={isRebootSelected}
158
+ onChange={selected => setIsRebootSelected(selected)}
159
+ />
160
+ </GridItem>
161
+ )}
162
+ </>
163
+ ) : null}
164
+ <GridItem>
165
+ <CodeBlock actions={actions}>
166
+ <CodeBlockCode id="code-content" className="remediation-code">
167
+ {snippetText}
168
+ </CodeBlockCode>
169
+ </CodeBlock>
170
+ </GridItem>
171
+ </Grid>
172
+ </>
173
+ );
174
+ };
175
+
176
+ export default ReviewRemediation;
@@ -0,0 +1,4 @@
1
+ pre.remediation-code {
2
+ border: none;
3
+ border-radius: none;
4
+ }
@@ -0,0 +1,160 @@
1
+ import React, { useContext } from 'react';
2
+ import { map, split, capitalize, join, slice, isEmpty } from 'lodash';
3
+ import {
4
+ Form,
5
+ FormGroup,
6
+ FormSelect,
7
+ FormSelectOption,
8
+ Radio,
9
+ Alert,
10
+ } from '@patternfly/react-core';
11
+
12
+ import { translate as __ } from 'foremanReact/common/I18n';
13
+ import { STATUS } from 'foremanReact/constants';
14
+ import Loading from 'foremanReact/components/Loading';
15
+
16
+ import OpenscapRemediationWizardContext from '../OpenscapRemediationWizardContext';
17
+ import WizardHeader from '../WizardHeader';
18
+ import EmptyState from '../../EmptyState';
19
+ import { errorMsg, supportedRemediationSnippets } from '../helpers';
20
+
21
+ const SnippetSelect = () => {
22
+ const {
23
+ fixes,
24
+ snippet,
25
+ setSnippet,
26
+ method,
27
+ setMethod,
28
+ logStatus,
29
+ logError,
30
+ supportedJobSnippets,
31
+ } = useContext(OpenscapRemediationWizardContext);
32
+
33
+ const snippetNameMap = {
34
+ 'urn:xccdf:fix:script:ansible': 'Ansible',
35
+ 'urn:xccdf:fix:script:puppet': 'Puppet',
36
+ 'urn:xccdf:fix:script:sh': 'Shell',
37
+ 'urn:xccdf:fix:script:kubernetes': 'Kubernetes',
38
+ 'urn:redhat:anaconda:pre': 'Anaconda',
39
+ 'urn:redhat:osbuild:blueprint': 'OSBuild Blueprint',
40
+ };
41
+
42
+ const snippetName = system => {
43
+ const mapped = snippetNameMap[system];
44
+ if (mapped) return mapped;
45
+
46
+ return join(
47
+ map(slice(split(system, ':'), -2), n => capitalize(n)),
48
+ ' '
49
+ );
50
+ };
51
+
52
+ const resetSnippet = meth => {
53
+ const snip = supportedRemediationSnippets(
54
+ fixes,
55
+ meth,
56
+ supportedJobSnippets
57
+ )[0];
58
+ setSnippet(snip);
59
+ return snip;
60
+ };
61
+
62
+ const setMethodResetSnippet = meth => {
63
+ setMethod(meth);
64
+ resetSnippet(meth);
65
+ };
66
+
67
+ const body =
68
+ logStatus === STATUS.RESOLVED ? (
69
+ <Form>
70
+ <FormGroup
71
+ label={__('Method')}
72
+ type="string"
73
+ fieldId="method"
74
+ isRequired={false}
75
+ >
76
+ <Radio
77
+ label={__('Remote job')}
78
+ id="job"
79
+ name="job"
80
+ ouiaId="job"
81
+ aria-label="job"
82
+ isChecked={method === 'job'}
83
+ onChange={() => setMethodResetSnippet('job')}
84
+ />
85
+ <Radio
86
+ label={__('Manual')}
87
+ id="manual"
88
+ name="manual"
89
+ ouiaId="manual"
90
+ aria-label="manual"
91
+ isChecked={method === 'manual'}
92
+ onChange={() => setMethodResetSnippet('manual')}
93
+ />
94
+ </FormGroup>
95
+ {isEmpty(
96
+ supportedRemediationSnippets(fixes, method, supportedJobSnippets)
97
+ ) ? (
98
+ <Alert
99
+ ouiaId="snippet-alert"
100
+ variant="info"
101
+ title={__(
102
+ 'There is no job to remediate with. Please remediate manually.'
103
+ )}
104
+ />
105
+ ) : (
106
+ <FormGroup
107
+ label={__('Snippet')}
108
+ type="string"
109
+ fieldId="snippet"
110
+ isRequired
111
+ >
112
+ <FormSelect
113
+ ouiaId="snippet-select"
114
+ isRequired
115
+ value={snippet}
116
+ onChange={value => setSnippet(value)}
117
+ aria-label="FormSelect Input"
118
+ >
119
+ <FormSelectOption
120
+ isDisabled
121
+ key={0}
122
+ value=""
123
+ label={__('Select snippet')}
124
+ />
125
+ {map(
126
+ supportedRemediationSnippets(
127
+ fixes,
128
+ method,
129
+ supportedJobSnippets
130
+ ),
131
+ fix => (
132
+ <FormSelectOption
133
+ key={fix}
134
+ value={fix}
135
+ label={snippetName(fix)}
136
+ />
137
+ )
138
+ )}
139
+ </FormSelect>
140
+ </FormGroup>
141
+ )}
142
+ </Form>
143
+ ) : (
144
+ <EmptyState error title={__('Error!')} body={errorMsg(logError)} />
145
+ );
146
+
147
+ return (
148
+ <>
149
+ <WizardHeader
150
+ title={__('Select remediation method')}
151
+ description={__(
152
+ 'You can remediate by running a remote job or you can display a snippet for manual remediation.'
153
+ )}
154
+ />
155
+ {logStatus === STATUS.PENDING ? <Loading /> : body}
156
+ </>
157
+ );
158
+ };
159
+
160
+ export default SnippetSelect;
@@ -0,0 +1,4 @@
1
+ export { default as SnippetSelect } from './SnippetSelect';
2
+ export { default as ReviewHosts } from './ReviewHosts';
3
+ export { default as ReviewRemediation } from './ReviewRemediation';
4
+ export { default as Finish } from './Finish';
data/webpack/index.js CHANGED
@@ -1,8 +1,13 @@
1
1
  import componentRegistry from 'foremanReact/components/componentRegistry';
2
2
 
3
3
  import RuleSeverity from './components/RuleSeverity';
4
+ import OpenscapRemediationWizard from './components/OpenscapRemediationWizard';
4
5
 
5
- componentRegistry.register({
6
- name: 'RuleSeverity',
7
- type: RuleSeverity,
6
+ const components = [
7
+ { name: 'RuleSeverity', type: RuleSeverity },
8
+ { name: 'OpenscapRemediationWizard', type: OpenscapRemediationWizard },
9
+ ];
10
+
11
+ components.forEach(component => {
12
+ componentRegistry.register(component);
8
13
  });
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import { Provider } from 'react-redux';
3
3
  import store from 'foremanReact/redux';
4
4
  import { MockedProvider } from '@apollo/react-testing';
@@ -19,20 +19,21 @@ export const withRouter = Component => props => (
19
19
  );
20
20
 
21
21
  export const withMockedProvider = Component => props => {
22
- const ForemanContext = getForemanContext(ctx);
23
22
  // eslint-disable-next-line react/prop-types
24
23
  const { mocks, ...rest } = props;
25
24
 
26
- const ctx = {
25
+ const [context, setContext] = useState({
27
26
  metadata: {
28
27
  UISettings: {
29
28
  perPage: 20,
30
29
  },
31
30
  },
32
- };
31
+ });
33
32
 
33
+ const contextData = { context, setContext };
34
+ const ForemanContext = getForemanContext(contextData);
34
35
  return (
35
- <ForemanContext.Provider value={ctx}>
36
+ <ForemanContext.Provider value={contextData}>
36
37
  <MockedProvider mocks={mocks}>
37
38
  <Component {...rest} />
38
39
  </MockedProvider>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_openscap
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.1
4
+ version: 8.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - slukasik@redhat.com
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-10 00:00:00.000000000 Z
11
+ date: 2024-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -224,6 +224,8 @@ files:
224
224
  - app/views/foreman_openscap/policy_mailer/_policy.erb
225
225
  - app/views/foreman_openscap/policy_mailer/policy_summary.erb
226
226
  - app/views/hosts/select_multiple_openscap_proxy.html.erb
227
+ - app/views/job_templates/run_openscap_remediation_-_ansible_default.erb
228
+ - app/views/job_templates/run_openscap_remediation_-_script_default.erb
227
229
  - app/views/job_templates/run_openscap_scans.erb
228
230
  - app/views/job_templates/run_oval_scans.erb
229
231
  - app/views/policies/_form.html.erb
@@ -323,6 +325,7 @@ files:
323
325
  - db/migrate/20201217161511_add_url_to_oval_content.rb
324
326
  - db/migrate/20210409095625_add_oval_policy_reference_to_cve.rb
325
327
  - db/migrate/20210819143316_drop_unused_tables.rb
328
+ - db/migrate/20230912122310_add_fixes_to_message.rb
326
329
  - db/seeds.d/75-job_templates.rb
327
330
  - db/seeds.d/openscap_feature.rb
328
331
  - db/seeds.d/openscap_policy_notification.rb
@@ -376,6 +379,7 @@ files:
376
379
  - locale/ka/LC_MESSAGES/foreman_openscap.mo
377
380
  - locale/ka/foreman_openscap.edit.po
378
381
  - locale/ka/foreman_openscap.po
382
+ - locale/ka/foreman_openscap.po.time_stamp
379
383
  - locale/ko/LC_MESSAGES/foreman_openscap.mo
380
384
  - locale/ko/foreman_openscap.edit.po
381
385
  - locale/ko/foreman_openscap.po
@@ -474,6 +478,19 @@ files:
474
478
  - webpack/components/IndexTable/IndexTableHelper.js
475
479
  - webpack/components/IndexTable/index.js
476
480
  - webpack/components/LinkButton.js
481
+ - webpack/components/OpenscapRemediationWizard/OpenscapRemediationSelectors.js
482
+ - webpack/components/OpenscapRemediationWizard/OpenscapRemediationWizardContext.js
483
+ - webpack/components/OpenscapRemediationWizard/ViewSelectedHostsLink.js
484
+ - webpack/components/OpenscapRemediationWizard/WizardHeader.js
485
+ - webpack/components/OpenscapRemediationWizard/constants.js
486
+ - webpack/components/OpenscapRemediationWizard/helpers.js
487
+ - webpack/components/OpenscapRemediationWizard/index.js
488
+ - webpack/components/OpenscapRemediationWizard/steps/Finish.js
489
+ - webpack/components/OpenscapRemediationWizard/steps/ReviewHosts.js
490
+ - webpack/components/OpenscapRemediationWizard/steps/ReviewRemediation.js
491
+ - webpack/components/OpenscapRemediationWizard/steps/ReviewRemediation.scss
492
+ - webpack/components/OpenscapRemediationWizard/steps/SnippetSelect.js
493
+ - webpack/components/OpenscapRemediationWizard/steps/index.js
477
494
  - webpack/components/RuleSeverity/RuleSeverity.scss
478
495
  - webpack/components/RuleSeverity/RuleSeverity.test.js
479
496
  - webpack/components/RuleSeverity/__snapshots__/RuleSeverity.test.js.snap
@@ -570,7 +587,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
570
587
  - !ruby/object:Gem::Version
571
588
  version: '0'
572
589
  requirements: []
573
- rubygems_version: 3.1.6
590
+ rubygems_version: 3.2.33
574
591
  signing_key:
575
592
  specification_version: 4
576
593
  summary: Foreman plug-in for displaying OpenSCAP audit reports