foreman_rh_cloud 12.1.4 → 12.2.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.
- checksums.yaml +4 -4
- data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +1 -2
- data/app/controllers/insights_cloud/ui_requests_controller.rb +99 -0
- data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +7 -13
- data/app/services/foreman_rh_cloud/gateway_request.rb +26 -0
- data/app/services/foreman_rh_cloud/insights_api_forwarder.rb +116 -0
- data/app/services/foreman_rh_cloud/tags_auth.rb +55 -0
- data/config/routes.rb +7 -0
- data/lib/foreman_rh_cloud/engine.rb +7 -1
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/insights_cloud.rb +8 -0
- data/package.json +5 -1
- data/test/controllers/insights_cloud/ui_requests_controller_test.rb +169 -0
- data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +3 -3
- data/test/unit/services/foreman_rh_cloud/insights_api_forwarder_test.rb +176 -0
- data/test/unit/services/foreman_rh_cloud/tags_auth_test.rb +29 -0
- data/webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js +30 -10
- data/webpack/CVEsHostDetailsTab/__tests__/CVEsHostDetailsTab.test.js +18 -11
- data/webpack/CVEsHostDetailsTab/index.js +2 -2
- data/webpack/CveDetailsPage/CveDetailsPage.js +20 -0
- data/webpack/CveDetailsPage/CveDetailsPage.test.js +31 -0
- data/webpack/CveDetailsPage/index.js +1 -0
- data/webpack/ForemanColumnExtensions/index.js +49 -14
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +1 -0
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilter.test.js.snap +1 -0
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/MinimalInventoryDropdown.js +2 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js +8 -1
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +4 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/CloudConnectorButton.js +3 -3
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorButton.test.js.snap +3 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js +10 -4
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +6 -6
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/SettingsWarning.js +2 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/__snapshots__/SettingsWarning.test.js.snap +2 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButton.js +1 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButton.test.js.snap +1 -0
- data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/InventoryAutoUpload.js +3 -1
- data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/__snapshots__/InventoryAutoUpload.test.js.snap +3 -0
- data/webpack/ForemanRhCloudFills.js +6 -3
- data/webpack/ForemanRhCloudPages.js +21 -3
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +1 -0
- data/webpack/InsightsCloudSync/Components/InsightsTable/SelectAllAlert.js +2 -0
- data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +1 -0
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +3 -0
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModalFooter.js +12 -2
- data/webpack/InsightsCloudSync/Components/RemediationModal/Resolutions.js +1 -0
- data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +6 -1
- data/webpack/InsightsCloudSync/InsightsCloudSync.js +39 -1
- data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +6 -50
- data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +51 -1
- data/webpack/InsightsVulnerability/InsightsVulnerabilityListPage.js +21 -0
- data/webpack/InsightsVulnerability/InsightsVulnerabilityListPage.test.js +20 -0
- data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +45 -0
- data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +28 -0
- data/webpack/IopRecommendationDetails/IopRecommendationDetails.js +44 -0
- data/webpack/common/DropdownToggle.js +1 -0
- data/webpack/common/ScalprumModule/ScalprumContext.js +73 -0
- data/webpack/common/Switcher/SwitcherPF4.js +1 -0
- data/webpack/common/Switcher/__tests__/__snapshots__/SwitcherPF4.test.js.snap +1 -0
- data/webpack/common/Switcher/index.js +1 -0
- metadata +21 -4
- data/webpack/InsightsVulnerability/InsightsVulnerability.js +0 -13
- data/webpack/InsightsVulnerability/InsightsVulnerability.test.js +0 -18
@@ -42,7 +42,7 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
42
42
|
}
|
43
43
|
|
44
44
|
paths.each do |key, value|
|
45
|
-
actual_params = @forwarder.path_params(key
|
45
|
+
actual_params = @forwarder.path_params(key)
|
46
46
|
assert_equal value, actual_params[:url]
|
47
47
|
end
|
48
48
|
end
|
@@ -167,7 +167,7 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
167
167
|
'action_dispatch.request.query_parameters' => params
|
168
168
|
)
|
169
169
|
|
170
|
-
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params,
|
170
|
+
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params, @host)
|
171
171
|
|
172
172
|
assert_match /foo/, actual[:headers][:user_agent]
|
173
173
|
assert_match /bar/, actual[:headers][:user_agent]
|
@@ -192,7 +192,7 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
192
192
|
'action_dispatch.request.query_parameters' => params
|
193
193
|
)
|
194
194
|
|
195
|
-
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params,
|
195
|
+
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params, @host)
|
196
196
|
|
197
197
|
assert_match /text\/html/, actual[:headers][:content_type]
|
198
198
|
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
require 'puma/null_io'
|
3
|
+
|
4
|
+
class UIRequestForwarderTest < ActiveSupport::TestCase
|
5
|
+
include MockCerts
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@forwarder = ::ForemanRhCloud::InsightsApiForwarder.new
|
9
|
+
@user = FactoryBot.build(:user)
|
10
|
+
@organization = FactoryBot.build(:organization)
|
11
|
+
@location = FactoryBot.build(:location)
|
12
|
+
|
13
|
+
setup_certs_expectation do
|
14
|
+
@forwarder.stubs(:foreman_certificates)
|
15
|
+
end
|
16
|
+
|
17
|
+
ForemanRhCloud.stubs(:cert_base_url).returns('https://cert.cloud.example.com')
|
18
|
+
end
|
19
|
+
|
20
|
+
test 'should scope GET requests with proper tags' do
|
21
|
+
user_agent = { :foo => :bar }
|
22
|
+
params = {}
|
23
|
+
|
24
|
+
req = ActionDispatch::Request.new(
|
25
|
+
'REQUEST_URI' => '/api/vulnerability/v1/cves/abc-123/affected_systems',
|
26
|
+
'REQUEST_METHOD' => 'GET',
|
27
|
+
'HTTP_USER_AGENT' => user_agent,
|
28
|
+
'rack.input' => ::Puma::NullIO.new,
|
29
|
+
'action_dispatch.request.query_parameters' => params
|
30
|
+
)
|
31
|
+
|
32
|
+
::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag)
|
33
|
+
@forwarder.expects(:execute_cloud_request).with do |actual_params|
|
34
|
+
actual = actual_params[:headers][:params]
|
35
|
+
assert_equal "U:\"#{@user.login}\"O:\"#{@organization.name}\"L:\"#{@location.name}\"", tag_value(actual.find { |param| param[0] == :tag && tag_name(param[1]) =~ /#{ForemanRhCloud::TagsAuth::TAG_NAME}/ }[1])
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
@forwarder.forward_request(req, '/api/vulnerability/v1/cves/abc-123/affected_systems', 'test_controller', @user, @organization, @location)
|
40
|
+
|
41
|
+
# This test asserts the parameters that are sent to the execute_cloud_request method.
|
42
|
+
# This is done by setting the expectation before the actual call.
|
43
|
+
end
|
44
|
+
|
45
|
+
test 'should not scope GET requests for unknown uris' do
|
46
|
+
user_agent = { :foo => :bar }
|
47
|
+
params = {}
|
48
|
+
|
49
|
+
req = ActionDispatch::Request.new(
|
50
|
+
'REQUEST_URI' => '/api/vulnerability/foo/bar',
|
51
|
+
'REQUEST_METHOD' => 'GET',
|
52
|
+
'HTTP_USER_AGENT' => user_agent,
|
53
|
+
'rack.input' => ::Puma::NullIO.new,
|
54
|
+
'action_dispatch.request.query_parameters' => params
|
55
|
+
)
|
56
|
+
|
57
|
+
::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag).never
|
58
|
+
@forwarder.expects(:execute_cloud_request).with do |actual_params|
|
59
|
+
actual = actual_params[:headers][:params]
|
60
|
+
assert_equal 0, actual.count
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
@forwarder.forward_request(req, '/api/vulnerability/foo/bar', 'test_controller', @user, @organization, @location)
|
65
|
+
|
66
|
+
# This test asserts the parameters that are sent to the execute_cloud_request method.
|
67
|
+
# This is done by setting the expectation before the actual call.
|
68
|
+
end
|
69
|
+
|
70
|
+
test 'should merge URI params in GET requests' do
|
71
|
+
user_agent = { :foo => :bar }
|
72
|
+
params = { :page => 5, :per_page => 42 }
|
73
|
+
|
74
|
+
req = ActionDispatch::Request.new(
|
75
|
+
'REQUEST_URI' => '/api/vulnerability/v1/cves/abc-123/affected_systems',
|
76
|
+
'REQUEST_METHOD' => 'GET',
|
77
|
+
'HTTP_USER_AGENT' => user_agent,
|
78
|
+
'rack.input' => ::Puma::NullIO.new,
|
79
|
+
'action_dispatch.request.query_parameters' => params
|
80
|
+
)
|
81
|
+
|
82
|
+
::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag)
|
83
|
+
@forwarder.expects(:execute_cloud_request).with do |actual_params|
|
84
|
+
actual = actual_params[:headers][:params]
|
85
|
+
assert_equal "U:\"#{@user.login}\"O:\"#{@organization.name}\"L:\"#{@location.name}\"", tag_value(actual.find { |param| param[0] == :tag && tag_name(param[1]) =~ /#{ForemanRhCloud::TagsAuth::TAG_NAME}/ }[1])
|
86
|
+
assert_equal 5, actual.find { |param| param[0] == :page }[1]
|
87
|
+
assert_equal 42, actual.find { |param| param[0] == :per_page }[1]
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
@forwarder.forward_request(req, '/api/vulnerability/v1/cves/abc-123/affected_systems', 'test_controller', @user, @organization, @location)
|
92
|
+
# This test asserts the parameters that are sent to the execute_cloud_request method.
|
93
|
+
# This is done by setting the expectation before the actual call.
|
94
|
+
end
|
95
|
+
|
96
|
+
test 'should not scope POST requests' do
|
97
|
+
post_data = 'Random POST data'
|
98
|
+
req = ActionDispatch::Request.new(
|
99
|
+
'REQUEST_URI' => '/foo/bar',
|
100
|
+
'REQUEST_METHOD' => 'POST',
|
101
|
+
'rack.input' => ::Puma::NullIO.new,
|
102
|
+
'RAW_POST_DATA' => post_data
|
103
|
+
)
|
104
|
+
|
105
|
+
::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag).never
|
106
|
+
@forwarder.expects(:execute_cloud_request).with do |actual_params|
|
107
|
+
actual = actual_params[:headers][:params]
|
108
|
+
assert_equal 0, actual.count
|
109
|
+
true
|
110
|
+
end
|
111
|
+
|
112
|
+
@forwarder.forward_request(req, '/api/vulnerability/v1/cves', 'test_controller', @user, @organization, @location)
|
113
|
+
|
114
|
+
# This test asserts the parameters that are sent to the execute_cloud_request method.
|
115
|
+
# This is done by setting the expectation before the actual call.
|
116
|
+
end
|
117
|
+
|
118
|
+
test 'should not scope PUT requests' do
|
119
|
+
put_data = 'Random PUT data'
|
120
|
+
req = ActionDispatch::Request.new(
|
121
|
+
'REQUEST_URI' => '/foo/bar',
|
122
|
+
'REQUEST_METHOD' => 'PUT',
|
123
|
+
'rack.input' => ::Puma::NullIO.new,
|
124
|
+
'RAW_POST_DATA' => put_data
|
125
|
+
)
|
126
|
+
|
127
|
+
::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag).never
|
128
|
+
@forwarder.expects(:execute_cloud_request).with do |actual_params|
|
129
|
+
actual = actual_params[:headers][:params]
|
130
|
+
assert_equal 0, actual.count
|
131
|
+
true
|
132
|
+
end
|
133
|
+
|
134
|
+
@forwarder.forward_request(req, '/api/vulnerability/v1/cves', 'test_controller', @user, @organization, @location)
|
135
|
+
|
136
|
+
# This test asserts the parameters that are sent to the execute_cloud_request method.
|
137
|
+
# This is done by setting the expectation before the actual call.
|
138
|
+
end
|
139
|
+
|
140
|
+
test 'should not scope PATCH requests' do
|
141
|
+
post_data = 'Random PATCH data'
|
142
|
+
req = ActionDispatch::Request.new(
|
143
|
+
'REQUEST_URI' => '/foo/bar',
|
144
|
+
'REQUEST_METHOD' => 'PATCH',
|
145
|
+
'rack.input' => ::Puma::NullIO.new,
|
146
|
+
'RAW_POST_DATA' => post_data,
|
147
|
+
"action_dispatch.request.path_parameters" => { :format => "json" }
|
148
|
+
)
|
149
|
+
|
150
|
+
::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag).never
|
151
|
+
@forwarder.expects(:execute_cloud_request).with do |actual_params|
|
152
|
+
actual = actual_params[:headers][:params]
|
153
|
+
assert_equal 0, actual.count
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
@forwarder.forward_request(req, '/api/vulnerability/v1/cves', 'test_controller', @user, @organization, @location)
|
158
|
+
|
159
|
+
# This test asserts the parameters that are sent to the execute_cloud_request method.
|
160
|
+
# This is done by setting the expectation before the actual call.
|
161
|
+
end
|
162
|
+
|
163
|
+
def tag_value(param_value)
|
164
|
+
return param_value unless param_value.is_a?(String)
|
165
|
+
|
166
|
+
tag_string = CGI.unescape(param_value)
|
167
|
+
tag_string.split('=')[1]
|
168
|
+
end
|
169
|
+
|
170
|
+
def tag_name(param_value)
|
171
|
+
return param_value unless param_value.is_a?(String)
|
172
|
+
|
173
|
+
tag_string = CGI.unescape(param_value)
|
174
|
+
tag_string.split('=')[0]
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class TagsAuthTest < ActiveSupport::TestCase
|
5
|
+
setup do
|
6
|
+
@user = FactoryBot.build(:user)
|
7
|
+
@logger = Logger.new(IO::NULL)
|
8
|
+
@org = FactoryBot.build(:organization)
|
9
|
+
@loc = FactoryBot.build(:location)
|
10
|
+
@auth = ::ForemanRhCloud::TagsAuth.new(@user, @org, @loc, @logger)
|
11
|
+
end
|
12
|
+
|
13
|
+
test 'Generates tags update request' do
|
14
|
+
uuid1 = 'test_uuid1'
|
15
|
+
uuid2 = 'test_uuid2'
|
16
|
+
|
17
|
+
@auth.expects(:allowed_hosts).returns([uuid1, uuid2])
|
18
|
+
@auth.expects(:execute_cloud_request).with do |actual_params|
|
19
|
+
actual = JSON.parse(actual_params[:payload])
|
20
|
+
assert_includes actual['host_id_list'], uuid1
|
21
|
+
assert_includes actual['host_id_list'], uuid2
|
22
|
+
assert_equal ForemanRhCloud::TagsAuth::TAG_SHORT_NAME, actual['tags'].first['key']
|
23
|
+
assert_equal ForemanRhCloud::TagsAuth::TAG_NAMESPACE, actual['tags'].first['namespace']
|
24
|
+
assert_equal "U:\"#{@user.login}\"O:\"#{@org.name}\"L:\"#{@loc.name}\"", actual['tags'].first['value']
|
25
|
+
end
|
26
|
+
|
27
|
+
@auth.update_tag
|
28
|
+
end
|
29
|
+
end
|
@@ -1,17 +1,37 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import {
|
3
|
+
import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
|
4
|
+
import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
|
4
5
|
|
5
|
-
const CVEsHostDetailsTab = ({
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
const CVEsHostDetailsTab = ({ systemId }) => {
|
7
|
+
const scope = 'vulnerability';
|
8
|
+
const module = './SystemDetailTable';
|
9
|
+
return (
|
10
|
+
<div className="rh-cloud-insights-vulnerability-host-details-component">
|
11
|
+
<ScalprumComponent scope={scope} module={module} systemId={systemId} />
|
12
|
+
</div>
|
13
|
+
);
|
14
|
+
};
|
12
15
|
|
13
16
|
CVEsHostDetailsTab.propTypes = {
|
14
|
-
|
17
|
+
systemId: PropTypes.string.isRequired,
|
18
|
+
};
|
19
|
+
|
20
|
+
const CVEsHostDetailsTabWrapper = ({ response }) => (
|
21
|
+
<ScalprumProvider {...providerOptions}>
|
22
|
+
<CVEsHostDetailsTab
|
23
|
+
// eslint-disable-next-line camelcase
|
24
|
+
systemId={response?.subscription_facet_attributes?.uuid}
|
25
|
+
/>
|
26
|
+
</ScalprumProvider>
|
27
|
+
);
|
28
|
+
|
29
|
+
CVEsHostDetailsTabWrapper.propTypes = {
|
30
|
+
response: PropTypes.shape({
|
31
|
+
subscription_facet_attributes: PropTypes.shape({
|
32
|
+
uuid: PropTypes.string.isRequired,
|
33
|
+
}),
|
34
|
+
}).isRequired,
|
15
35
|
};
|
16
36
|
|
17
|
-
export default
|
37
|
+
export default CVEsHostDetailsTabWrapper;
|
@@ -1,18 +1,25 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { render
|
3
|
-
import
|
2
|
+
import { render } from '@testing-library/react';
|
3
|
+
import CVEsHostDetailsTabWrapper from '../CVEsHostDetailsTab';
|
4
4
|
|
5
|
-
|
5
|
+
jest.mock('@scalprum/react-core', () => ({
|
6
|
+
ScalprumComponent: jest.fn(props => (
|
7
|
+
<div data-testid="mock-scalprum-component">{JSON.stringify(props)}</div>
|
8
|
+
)),
|
9
|
+
ScalprumProvider: jest.fn(({ children }) => <div>{children}</div>),
|
10
|
+
}));
|
11
|
+
|
12
|
+
describe('CVEsHostDetailsTabWrapper', () => {
|
6
13
|
it('renders without crashing', () => {
|
7
|
-
|
14
|
+
const { container } = render(
|
15
|
+
<CVEsHostDetailsTabWrapper
|
16
|
+
response={{ subscription_facet_attributes: { uuid: '1-2-3' } }}
|
17
|
+
/>
|
18
|
+
);
|
8
19
|
expect(
|
9
|
-
|
20
|
+
container.querySelector(
|
21
|
+
'.rh-cloud-insights-vulnerability-host-details-component'
|
22
|
+
)
|
10
23
|
).toBeTruthy();
|
11
24
|
});
|
12
|
-
|
13
|
-
it('renders the host name', () => {
|
14
|
-
const hostName = 'test-host.example.com';
|
15
|
-
render(<CVEsHostDetailsTab hostName={hostName} />);
|
16
|
-
expect(screen.getByText(`CVEs tab for host: ${hostName}`)).toBeTruthy();
|
17
|
-
});
|
18
25
|
});
|
@@ -1,3 +1,3 @@
|
|
1
|
-
import
|
1
|
+
import CVEsHostDetailsTabWrapper from './CVEsHostDetailsTab';
|
2
2
|
|
3
|
-
export default
|
3
|
+
export default CVEsHostDetailsTabWrapper;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useParams } from 'react-router-dom';
|
3
|
+
import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
|
4
|
+
import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
|
5
|
+
|
6
|
+
const CveDetailsPage = () => {
|
7
|
+
const { cveId } = useParams();
|
8
|
+
const scope = 'vulnerability';
|
9
|
+
const module = './CveDetailPage';
|
10
|
+
|
11
|
+
return (
|
12
|
+
<ScalprumProvider {...providerOptions}>
|
13
|
+
<div className="rh-cloud-cve-details-page">
|
14
|
+
<ScalprumComponent scope={scope} module={module} cveId={cveId} />
|
15
|
+
</div>
|
16
|
+
</ScalprumProvider>
|
17
|
+
);
|
18
|
+
};
|
19
|
+
|
20
|
+
export default CveDetailsPage;
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { render } from '@testing-library/react';
|
3
|
+
import '@testing-library/jest-dom';
|
4
|
+
import CveDetailsPage from './CveDetailsPage';
|
5
|
+
|
6
|
+
// Mock react-router-dom
|
7
|
+
jest.mock('react-router-dom', () => ({
|
8
|
+
useParams: jest.fn(() => ({ cveId: 'CVE-2021-1234' })),
|
9
|
+
}));
|
10
|
+
|
11
|
+
jest.mock('@scalprum/react-core', () => ({
|
12
|
+
ScalprumComponent: jest.fn(props => (
|
13
|
+
<div data-testid="mock-scalprum-component">{JSON.stringify(props)}</div>
|
14
|
+
)),
|
15
|
+
ScalprumProvider: jest.fn(({ children }) => <div>{children}</div>),
|
16
|
+
}));
|
17
|
+
|
18
|
+
describe('CveDetailsPage component', () => {
|
19
|
+
it('renders the container with correct class', () => {
|
20
|
+
const { container } = render(<CveDetailsPage />);
|
21
|
+
expect(
|
22
|
+
container.querySelector('.rh-cloud-cve-details-page')
|
23
|
+
).toBeTruthy();
|
24
|
+
});
|
25
|
+
|
26
|
+
it('passes cveId from URL params to ScalprumComponent', () => {
|
27
|
+
const { getByTestId } = render(<CveDetailsPage />);
|
28
|
+
const mockComponent = getByTestId('mock-scalprum-component');
|
29
|
+
expect(mockComponent.textContent).toContain('CVE-2021-1234');
|
30
|
+
});
|
31
|
+
});
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default } from './CveDetailsPage';
|
@@ -1,19 +1,15 @@
|
|
1
1
|
import React from 'react';
|
2
|
+
import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
|
2
3
|
import { translate as __ } from 'foremanReact/common/I18n';
|
3
4
|
import { propsToCamelCase } from 'foremanReact/common/helpers';
|
5
|
+
import { CVECountCell } from '../InsightsVulnerabilityHostIndexExtensions/CVECountCell';
|
6
|
+
import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
|
4
7
|
|
5
|
-
const
|
8
|
+
const HostedRecommendationsCell = hostDetails => {
|
6
9
|
const insightsAttributes = propsToCamelCase(
|
7
10
|
// eslint-disable-next-line camelcase
|
8
11
|
hostDetails?.insights_attributes ?? {}
|
9
12
|
);
|
10
|
-
// Local insights advisor
|
11
|
-
if (insightsAttributes.useLocalAdvisorEngine) {
|
12
|
-
// TODO: Replace this placeholder with the actual local advisor integration
|
13
|
-
return <span>Local advisor placeholder</span>;
|
14
|
-
}
|
15
|
-
|
16
|
-
// Hosted insights advisor
|
17
13
|
const { insightsHitsCount: hitsCount } = insightsAttributes;
|
18
14
|
if (hitsCount === undefined || hitsCount === null) return '—';
|
19
15
|
const hostname = hostDetails?.name;
|
@@ -22,6 +18,38 @@ const RecommendationsCell = hostDetails => {
|
|
22
18
|
return <a href={hitsUrl}>{hitsCount}</a>;
|
23
19
|
};
|
24
20
|
|
21
|
+
const IopRecommendationsCell = hostDetails => {
|
22
|
+
const scope = 'advisor';
|
23
|
+
const module = './RecommendationsCellWrapped';
|
24
|
+
|
25
|
+
return (
|
26
|
+
<span className="rh-cloud-insights-recommendations-cell">
|
27
|
+
<ScalprumComponent scope={scope} module={module} />
|
28
|
+
</span>
|
29
|
+
);
|
30
|
+
};
|
31
|
+
|
32
|
+
const IopRecommendationsCellWrapped = hostDetails => (
|
33
|
+
<ScalprumProvider {...providerOptions}>
|
34
|
+
<IopRecommendationsCell hostDetails={hostDetails} />
|
35
|
+
</ScalprumProvider>
|
36
|
+
);
|
37
|
+
|
38
|
+
const RecommendationsCell = hostDetails => {
|
39
|
+
const insightsAttributes = propsToCamelCase(
|
40
|
+
// eslint-disable-next-line camelcase
|
41
|
+
hostDetails?.insights_attributes ?? {}
|
42
|
+
);
|
43
|
+
|
44
|
+
return insightsAttributes.useLocalAdvisorEngine ? (
|
45
|
+
<IopRecommendationsCellWrapped hostDetails={hostDetails} />
|
46
|
+
) : (
|
47
|
+
<HostedRecommendationsCell hostDetails={hostDetails} />
|
48
|
+
);
|
49
|
+
};
|
50
|
+
|
51
|
+
const insightsCategoryName = __('Insights');
|
52
|
+
|
25
53
|
const hostsIndexColumnExtensions = [
|
26
54
|
{
|
27
55
|
columnName: 'insights_recommendations_count',
|
@@ -29,13 +57,20 @@ const hostsIndexColumnExtensions = [
|
|
29
57
|
wrapper: RecommendationsCell,
|
30
58
|
weight: 1500,
|
31
59
|
isSorted: true,
|
60
|
+
tableName: 'hosts',
|
61
|
+
categoryName: insightsCategoryName,
|
62
|
+
categoryKey: 'insights',
|
63
|
+
},
|
64
|
+
{
|
65
|
+
columnName: 'cves_count',
|
66
|
+
title: __('Total CVEs'),
|
67
|
+
wrapper: hostDetails => <CVECountCell hostDetails={hostDetails} />,
|
68
|
+
weight: 2600,
|
69
|
+
tableName: 'hosts',
|
70
|
+
categoryName: insightsCategoryName,
|
71
|
+
categoryKey: 'insights',
|
72
|
+
isSorted: false,
|
32
73
|
},
|
33
74
|
];
|
34
75
|
|
35
|
-
hostsIndexColumnExtensions.forEach(column => {
|
36
|
-
column.tableName = 'hosts';
|
37
|
-
column.categoryName = 'Insights';
|
38
|
-
column.categoryKey = 'insights';
|
39
|
-
});
|
40
|
-
|
41
76
|
export default hostsIndexColumnExtensions;
|
data/webpack/ForemanInventoryUpload/Components/InventorySettings/MinimalInventoryDropdown.js
CHANGED
@@ -68,6 +68,7 @@ const MinimalInventoryDropdown = ({ setChosenValue }) => {
|
|
68
68
|
};
|
69
69
|
return (
|
70
70
|
<Dropdown
|
71
|
+
ouiaId="inventory-dropdown"
|
71
72
|
isOpen={isOpen}
|
72
73
|
onSelect={onSelect}
|
73
74
|
onOpenChange={val => setIsOpen(val)}
|
@@ -90,6 +91,7 @@ const MinimalInventoryDropdown = ({ setChosenValue }) => {
|
|
90
91
|
value={value}
|
91
92
|
key={value}
|
92
93
|
description={item.description}
|
94
|
+
ouiaId={`inventory-dropdownItem-${value}`}
|
93
95
|
>
|
94
96
|
{item.title}
|
95
97
|
</DropdownItem>
|
@@ -26,6 +26,7 @@ const PageTitle = () => {
|
|
26
26
|
const dropdownItems = [
|
27
27
|
<DropdownItem
|
28
28
|
key="tasks-history-button"
|
29
|
+
ouiaId="tasks-history-button"
|
29
30
|
href={getActionsHistoryUrl()}
|
30
31
|
target="_blank"
|
31
32
|
rel="noopener noreferrer"
|
@@ -34,13 +35,18 @@ const PageTitle = () => {
|
|
34
35
|
</DropdownItem>,
|
35
36
|
<DropdownItem
|
36
37
|
key="inventory-documentation-button"
|
38
|
+
ouiaId="inventory-documentation-button"
|
37
39
|
href={getInventoryDocsUrl()}
|
38
40
|
target="_blank"
|
39
41
|
rel="noopener noreferrer"
|
40
42
|
>
|
41
43
|
{DOCS_BUTTON_TEXT}
|
42
44
|
</DropdownItem>,
|
43
|
-
<DropdownItem
|
45
|
+
<DropdownItem
|
46
|
+
key="cloud-ping"
|
47
|
+
ouiaId="dropdownItem-cloud-ping"
|
48
|
+
onClick={togglePingModal}
|
49
|
+
>
|
44
50
|
{CLOUD_PING_TITLE}
|
45
51
|
</DropdownItem>,
|
46
52
|
];
|
@@ -55,6 +61,7 @@ const PageTitle = () => {
|
|
55
61
|
<GridItem span={6}>
|
56
62
|
<Dropdown
|
57
63
|
className="title-dropdown"
|
64
|
+
ouiaId="title-dropdown"
|
58
65
|
onSelect={() => setIsDropdownOpen(false)}
|
59
66
|
toggle={
|
60
67
|
<KebabToggle
|
@@ -25,6 +25,7 @@ exports[`PageTitle rendering render without Props 1`] = `
|
|
25
25
|
Array [
|
26
26
|
<DropdownItem
|
27
27
|
href="/foreman_tasks/tasks?search=label+%3D+ForemanInventoryUpload%3A%3AAsync%3A%3AGenerateReportJob+or+label+%3D+ForemanInventoryUpload%3A%3AAsync%3A%3AGenerateAllReportsJob&page=1"
|
28
|
+
ouiaId="tasks-history-button"
|
28
29
|
rel="noopener noreferrer"
|
29
30
|
target="_blank"
|
30
31
|
>
|
@@ -32,6 +33,7 @@ exports[`PageTitle rendering render without Props 1`] = `
|
|
32
33
|
</DropdownItem>,
|
33
34
|
<DropdownItem
|
34
35
|
href="/links/manual/?root_url=https%3A%2F%2Faccess.redhat.com%2Fdocumentation%2Fen-us%2Fred_hat_insights%2F2023%2Fhtml%2Fred_hat_insights_remediations_guide%2Fhost-communication-with-insights_red-hat-insights-remediation-guide%23uploading-satellite-host-inventory-to-insights_configuring-satellite-cloud-connector"
|
36
|
+
ouiaId="inventory-documentation-button"
|
35
37
|
rel="noopener noreferrer"
|
36
38
|
target="_blank"
|
37
39
|
>
|
@@ -39,6 +41,7 @@ exports[`PageTitle rendering render without Props 1`] = `
|
|
39
41
|
</DropdownItem>,
|
40
42
|
<DropdownItem
|
41
43
|
onClick={[Function]}
|
44
|
+
ouiaId="dropdownItem-cloud-ping"
|
42
45
|
>
|
43
46
|
Connectivity test
|
44
47
|
</DropdownItem>,
|
@@ -47,6 +50,7 @@ exports[`PageTitle rendering render without Props 1`] = `
|
|
47
50
|
isOpen={false}
|
48
51
|
isPlain={true}
|
49
52
|
onSelect={[Function]}
|
53
|
+
ouiaId="title-dropdown"
|
50
54
|
position="right"
|
51
55
|
toggle={
|
52
56
|
<KebabToggle
|
@@ -26,7 +26,7 @@ export const CloudConnectorButton = ({ status, onClick, jobLink }) => {
|
|
26
26
|
className="cloud-connector-pending-button"
|
27
27
|
onMouseEnter={() => setIsPopoverVisible(true)}
|
28
28
|
>
|
29
|
-
<Button variant="secondary" isDisabled>
|
29
|
+
<Button variant="secondary" ouiaId="button-in-progress" isDisabled>
|
30
30
|
<Spinner size="sm" /> {__('Cloud Connector is in progress')}
|
31
31
|
</Button>
|
32
32
|
</div>
|
@@ -36,14 +36,14 @@ export const CloudConnectorButton = ({ status, onClick, jobLink }) => {
|
|
36
36
|
|
37
37
|
if (status === CONNECTOR_STATUS.RESOLVED) {
|
38
38
|
return (
|
39
|
-
<Button variant="secondary" onClick={onClick}>
|
39
|
+
<Button variant="secondary" ouiaId="button-reconfigure" onClick={onClick}>
|
40
40
|
{__('Reconfigure cloud connector')}
|
41
41
|
</Button>
|
42
42
|
);
|
43
43
|
}
|
44
44
|
|
45
45
|
return (
|
46
|
-
<Button variant="secondary" onClick={onClick}>
|
46
|
+
<Button variant="secondary" ouiaId="button-configure" onClick={onClick}>
|
47
47
|
{__('Configure cloud connector')}
|
48
48
|
</Button>
|
49
49
|
);
|
@@ -3,6 +3,7 @@
|
|
3
3
|
exports[`CloudConnectorButton render no cloud connector 1`] = `
|
4
4
|
<Button
|
5
5
|
onClick={[MockFunction]}
|
6
|
+
ouiaId="button-configure"
|
6
7
|
variant="secondary"
|
7
8
|
>
|
8
9
|
Configure cloud connector
|
@@ -34,6 +35,7 @@ exports[`CloudConnectorButton render pending connector 1`] = `
|
|
34
35
|
>
|
35
36
|
<Button
|
36
37
|
isDisabled={true}
|
38
|
+
ouiaId="button-in-progress"
|
37
39
|
variant="secondary"
|
38
40
|
>
|
39
41
|
<Spinner
|
@@ -49,6 +51,7 @@ exports[`CloudConnectorButton render pending connector 1`] = `
|
|
49
51
|
exports[`CloudConnectorButton render resolved cloud connector 1`] = `
|
50
52
|
<Button
|
51
53
|
onClick={[MockFunction]}
|
54
|
+
ouiaId="button-reconfigure"
|
52
55
|
variant="secondary"
|
53
56
|
>
|
54
57
|
Reconfigure cloud connector
|
data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js
CHANGED
@@ -79,26 +79,32 @@ const CloudPingModal = ({ title, isOpen, toggle }) => {
|
|
79
79
|
<>
|
80
80
|
<Modal
|
81
81
|
id="cloud-ping-modal"
|
82
|
+
ouiaId="cloud-ping-modal"
|
82
83
|
appendTo={document.getElementsByClassName('react-container')[0]}
|
83
84
|
variant={ModalVariant.large}
|
84
85
|
title={title}
|
85
86
|
isOpen={isOpen}
|
86
87
|
onClose={toggle}
|
87
88
|
>
|
88
|
-
<Card className="certs-status">
|
89
|
+
<Card className="certs-status" ouiaId="card-org-status">
|
89
90
|
<CardTitle>{__('Organization status')}</CardTitle>
|
90
91
|
<CardBody>
|
91
|
-
<Text>
|
92
|
+
<Text ouiaId="text-description">
|
92
93
|
{__('Displays manifest statuses per accessible organizations.')}
|
93
94
|
</Text>
|
94
95
|
{isPending ? (
|
95
96
|
<Spinner size="xl" />
|
96
97
|
) : (
|
97
98
|
<>
|
98
|
-
<Text className="pull-right">
|
99
|
+
<Text className="pull-right" ouiaId="text-org-count">
|
99
100
|
{sprintf(__('%s organizations'), rows.length)}
|
100
101
|
</Text>
|
101
|
-
<Table
|
102
|
+
<Table
|
103
|
+
aria-label="Simple Table"
|
104
|
+
ouiaId="simple-table"
|
105
|
+
cells={['']}
|
106
|
+
rows={rows}
|
107
|
+
>
|
102
108
|
<TableHeader />
|
103
109
|
<TableBody />
|
104
110
|
</Table>{' '}
|