foreman_openscap 7.1.1 → 8.0.0

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 (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