foreman_rh_cloud 12.1.5 → 12.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abf912ff1170fb60a3b10a6d1178f71ad7a92662c2272a883179eb30a62e2c2e
4
- data.tar.gz: 3ff64877a61a50890423e1d25980ea37e9fc3ae949f875be344b299f5580ab24
3
+ metadata.gz: a5297c9be7a8e61f55e175c20b5f322b19c015d9a29bdd9c1bf42248ad1ffedf
4
+ data.tar.gz: 59cab12bcca78ee78eba81af4c0089f1dcaac84b35244936b707692c4881f7ba
5
5
  SHA512:
6
- metadata.gz: 5792bc34bf4e7a254cacc14cd014b9e008378d695ddc5ae00afcbd5f10371840a53ecdd106f2a845531a2c174fab3c7d1b931ba0a6f766c749124adcbcff742f
7
- data.tar.gz: dffa948ae7cca41a839be2c07f26193ccc11c9af71d84c07d4b0f256a0ad0e5763ce107cf69a22ecb6436212a5e68d09512a4043eb8eb5b01a2268c88d0d44fd
6
+ metadata.gz: d8a544fe9144aad08668231c90d3c221a316501dc3d7f3766c444d2617c22949a5d4bde889960f6ff5cd9a6005f07885cb99ca059ab8b64ca7a5f058fc8df192
7
+ data.tar.gz: 123d446d857e98c371c362b26af1be131e59d41c7ade186a11d061fcb5078b39358a998be23eceb1e4dafcc66e9e6a8dd10c70652ad60b13f01d54675fbd4576
@@ -75,6 +75,17 @@ module InsightsCloud
75
75
  res.headers[new_header] = header_content
76
76
  end
77
77
 
78
+ def translate_insights_host
79
+ facet = InsightsFacet.find_by(uuid: params[:uuid])
80
+ if facet.present?
81
+ Rails.logger.debug "Found InsightsFacet #{params[:uuid]}"
82
+ redirect_to host_details_page_path(facet.host_id)
83
+ else
84
+ Rails.logger.error "Could not find InsightsFacet for #{params[:uuid]}"
85
+ redirect_to '/page-not-found'
86
+ end
87
+ end
88
+
78
89
  private
79
90
 
80
91
  def ensure_org
@@ -28,7 +28,7 @@ module ForemanRhCloud
28
28
  end
29
29
 
30
30
  def payload
31
- @payload.to_json
31
+ @payload.present? ? @payload.to_json : @payload # don't run .to_json if @payload is ''
32
32
  end
33
33
 
34
34
  def method
data/config/routes.rb CHANGED
@@ -38,8 +38,13 @@ Rails.application.routes.draw do
38
38
  unless ForemanRhCloud.with_local_advisor_engine?
39
39
  get 'inventory_upload', to: '/react#index'
40
40
  end
41
+ if ForemanRhCloud.with_local_advisor_engine?
42
+ get 'recommendations', to: '/react#index'
43
+ get 'recommendations/:rule_id', to: '/react#index'
44
+ end
41
45
  get 'insights_cloud', to: '/react#index' # Uses foreman's react controller
42
46
  get 'insights_vulnerability', to: '/react#index'
47
+ get 'insights_vulnerability/:cve_id', to: '/react#index'
43
48
  end
44
49
 
45
50
  scope :module => :'insights_cloud/api', :path => :redhat_access do
@@ -56,6 +61,8 @@ Rails.application.routes.draw do
56
61
  match '/api/lightspeed/*path', to: 'machine_telemetries#forward_request', via: :all
57
62
  end
58
63
 
64
+ get '/insights_hosts/:uuid', to: 'insights_cloud/ui_requests#translate_insights_host'
65
+
59
66
  # API routes
60
67
 
61
68
  namespace :api, :defaults => { :format => 'json' } do
@@ -33,134 +33,7 @@ module ForemanRhCloud
33
33
 
34
34
  initializer 'foreman_rh_cloud.register_plugin', :before => :finisher_hook do |app|
35
35
  app.reloader.to_prepare do
36
- Foreman::Plugin.register :foreman_rh_cloud do
37
- requires_foreman '>= 3.13'
38
- register_gettext
39
-
40
- apipie_documented_controllers ["#{ForemanRhCloud::Engine.root}/app/controllers/api/v2/**/*.rb"]
41
-
42
- settings do
43
- category(:rh_cloud, N_('Insights')) do
44
- setting('allow_auto_inventory_upload', type: :boolean, description: N_('Enable automatic upload of your host inventory to the Red Hat cloud'), default: true, full_name: N_('Automatic inventory upload'))
45
- setting('allow_auto_insights_sync', type: :boolean, description: N_('Enable automatic synchronization of Insights recommendations from the Red Hat cloud'), default: true, full_name: N_('Synchronize recommendations Automatically'))
46
- setting('allow_auto_insights_mismatch_delete', type: :boolean, description: N_('Enable automatic deletion of mismatched host records from the Red Hat cloud'), default: false, full_name: N_('Automatic mismatch deletion'))
47
- setting('obfuscate_inventory_hostnames', type: :boolean, description: N_('Obfuscate host names sent to the Red Hat cloud. (If insights_minimal_data_collection is set to true, this setting is ignored because host names are not included in the report.)'), default: false, full_name: N_('Obfuscate host names'))
48
- setting('obfuscate_inventory_ips', type: :boolean, description: N_('Obfuscate ipv4 addresses sent to the Red Hat cloud. (If insights_minimal_data_collection is set to true, this setting is ignored because host IPv4 addresses are not included in the report.)'), default: false, full_name: N_('Obfuscate host ipv4 addresses.'))
49
- setting('exclude_installed_packages', type: :boolean, description: N_('Exclude installed packages from being uploaded to the Red Hat cloud. (If insights_minimal_data_collection is set to true, this setting is ignored and installed packages are always excluded.)'), default: false, full_name: N_("Exclude installed packages"))
50
- setting('include_parameter_tags', type: :boolean, description: N_('Should import include parameter tags from Foreman?'), default: false, full_name: N_('Include parameters in insights-client reports'))
51
- setting('rhc_instance_id', type: :string, description: N_('RHC daemon id'), default: nil, full_name: N_('ID of the RHC(Yggdrasil) daemon'))
52
- setting('insights_minimal_data_collection', type: :boolean, default: false, full_name: N_('Minimal data collection'), description: N_('Only include the minimum required data in inventory reports for uploading to Red Hat cloud. When this is true, installed packages are excluded from the report regardless of the exclude_installed_packages setting, and host names and IPv4 addresses are excluded from the report regardless of obfuscation settings.'))
53
- end
54
- end
55
-
56
- # Add permissions
57
- security_block :foreman_rh_cloud do
58
- permission(
59
- :generate_foreman_rh_cloud,
60
- 'foreman_inventory_upload/reports': [:generate],
61
- 'foreman_inventory_upload/tasks': [:create],
62
- 'api/v2/rh_cloud/inventory': [:get_hosts, :remove_hosts, :sync_inventory_status, :download_file, :generate_report, :enable_cloud_connector],
63
- 'foreman_inventory_upload/uploads': [:enable_cloud_connector],
64
- 'foreman_inventory_upload/uploads_settings': [:set_advanced_setting],
65
- 'foreman_inventory_upload/missing_hosts': [:remove_hosts],
66
- 'insights_cloud/settings': [:update],
67
- 'insights_cloud/tasks': [:create]
68
- )
69
- permission(
70
- :view_foreman_rh_cloud,
71
- 'foreman_inventory_upload/accounts': [:index],
72
- 'foreman_inventory_upload/reports': [:last],
73
- 'foreman_inventory_upload/uploads': [:auto_upload, :show_auto_upload, :download_file, :last],
74
- 'foreman_inventory_upload/tasks': [:show],
75
- 'foreman_inventory_upload/cloud_status': [:index],
76
- 'foreman_inventory_upload/uploads_settings': [:index],
77
- 'foreman_inventory_upload/missing_hosts': [:index],
78
- 'api/v2/rh_cloud/advisor_engine_config': [:show],
79
- 'react': [:index]
80
- )
81
- permission(
82
- :view_insights_hits,
83
- {
84
- '/foreman_rh_cloud/insights_cloud': [:index], # for bookmarks and later for showing the page
85
- 'insights_cloud/hits': [:index, :show, :auto_complete_search, :resolutions],
86
- 'insights_cloud/settings': [:index, :show],
87
- 'insights_cloud/ui_requests': [:forward_request],
88
- 'react': [:index],
89
- },
90
- :resource_type => ::InsightsHit.name
91
- )
92
- permission(
93
- :dispatch_cloud_requests,
94
- 'api/v2/rh_cloud/cloud_request': [:update]
95
- )
96
- permission(
97
- :control_organization_insights,
98
- 'insights_cloud/settings': [:set_org_parameter]
99
- )
100
- end
101
-
102
- plugin_permissions = [:view_foreman_rh_cloud, :generate_foreman_rh_cloud, :view_insights_hits, :dispatch_cloud_requests, :control_organization_insights]
103
-
104
- role 'ForemanRhCloud', plugin_permissions, 'Role granting permissions to view the hosts inventory,
105
- generate a report, upload it to the cloud and download it locally'
106
-
107
- add_permissions_to_default_roles Role::ORG_ADMIN => plugin_permissions,
108
- Role::MANAGER => plugin_permissions,
109
- Role::SYSTEM_ADMIN => plugin_permissions
110
-
111
- # Adding a top-level menu item
112
- sub_menu :top_menu, :insights_menu, caption: N_('Insights'), icon: 'fa fa-cloud', after: :hosts_menu do
113
- menu :top_menu,
114
- :inventory_upload,
115
- caption: N_('Inventory Upload'),
116
- url: '/foreman_rh_cloud/inventory_upload',
117
- url_hash: { controller: :react, action: :index },
118
- parent: :insights_menu
119
- menu :top_menu, :insights_hits, caption: N_('Recommendations'), url: '/foreman_rh_cloud/insights_cloud', url_hash: { controller: :react, action: :index }, parent: :insights_menu
120
- menu :top_menu,
121
- :insights_vulnerability,
122
- caption: N_('Vulnerability'),
123
- url: '/foreman_rh_cloud/insights_vulnerability',
124
- url_hash: { controller: :react, action: :index },
125
- parent: :insights_menu,
126
- if: -> { ForemanRhCloud.with_local_advisor_engine? }
127
- end
128
-
129
- register_facet InsightsFacet, :insights do
130
- configure_host do
131
- api_view :list => 'api/v2/hosts/insights/insights', :single => 'api/v2/hosts/insights/single'
132
- set_dependent_action :destroy
133
- end
134
- end
135
-
136
- register_global_js_file 'global'
137
-
138
- register_custom_status InventorySync::InventoryStatus
139
- register_custom_status InsightsClientReportStatus
140
-
141
- describe_host do
142
- overview_buttons_provider :insights_host_overview_buttons
143
- end
144
-
145
- extend_page 'hosts/show' do |context|
146
- context.add_pagelet :main_tabs,
147
- partial: 'hosts/insights_tab',
148
- name: _('Insights'),
149
- id: 'insights',
150
- onlyif: proc { |host| host.insights }
151
- end
152
-
153
- extend_page 'hosts/_list' do |context|
154
- context.with_profile :cloud, _('RH Cloud'), default: true do
155
- add_pagelet :hosts_table_column_header, key: :insights_recommendations_count, label: _('Recommendations'), sortable: true, width: '12%', class: 'hidden-xs ellipsis', priority: 100,
156
- export_data: CsvExporter::ExportDefinition.new(:insights_recommendations_count, callback: ->(host) { host&.insights_hits&.count })
157
- add_pagelet :hosts_table_column_content, key: :insights_recommendations_count, callback: ->(host) { hits_counts_cell(host) }, class: 'hidden-xs ellipsis text-center', priority: 100
158
- end
159
- end
160
-
161
- extend_template_helpers ForemanRhCloud::TemplateRendererHelper
162
- allowed_template_helpers :remediations_playbook, :download_rh_playbook
163
- end
36
+ ForemanRhCloud::Plugin.register
164
37
 
165
38
  ::Katello::UINotifications::Subscriptions::ManifestImportSuccess.include ForemanInventoryUpload::Notifications::ManifestImportSuccessNotificationOverride if defined?(Katello)
166
39
 
@@ -229,10 +102,15 @@ module ForemanRhCloud
229
102
  Katello::Api::V2::OrganizationsController.before_action(:local_find_taxonomy, only: :download_debug_certificate)
230
103
 
231
104
  Katello::Api::V2::RepositoriesController.include Foreman::Controller::SmartProxyAuth
105
+ # patch the callbacks order for :index, since find_product has to run after the user is already initialized
106
+ Katello::Api::V2::RepositoriesController.skip_before_action(:find_product, only: :index)
107
+ Katello::Api::V2::RepositoriesController.skip_before_action(:find_optional_organization, only: :index)
232
108
  Katello::Api::V2::RepositoriesController.add_smart_proxy_filters(
233
109
  :index,
234
110
  features: ForemanRhCloud.on_prem_smart_proxy_features
235
111
  )
112
+ Katello::Api::V2::RepositoriesController.before_action(:find_product, only: :index)
113
+ Katello::Api::V2::RepositoriesController.before_action(:find_optional_organization, only: :index)
236
114
  end
237
115
  end
238
116
 
@@ -259,6 +137,6 @@ module ForemanRhCloud
259
137
  end
260
138
 
261
139
  def self.on_prem_smart_proxy_features
262
- ['Insights']
140
+ ['iop']
263
141
  end
264
142
  end
@@ -0,0 +1,138 @@
1
+ module ForemanRhCloud
2
+ module Plugin
3
+ def self.register
4
+ # This module is auto-loaded, but plugin settings cannot be redefined
5
+ # Ensure that we don't try to re-register the plugin on code reload
6
+ return if Foreman::Plugin.find(:foreman_rh_cloud)
7
+
8
+ Foreman::Plugin.register :foreman_rh_cloud do
9
+ requires_foreman '>= 3.13'
10
+ register_gettext
11
+
12
+ apipie_documented_controllers ["#{ForemanRhCloud::Engine.root}/app/controllers/api/v2/**/*.rb"]
13
+
14
+ settings do
15
+ category(:rh_cloud, N_('Insights')) do
16
+ setting('allow_auto_inventory_upload', type: :boolean, description: N_('Enable automatic upload of your host inventory to the Red Hat cloud'), default: true, full_name: N_('Automatic inventory upload'))
17
+ setting('allow_auto_insights_sync', type: :boolean, description: N_('Enable automatic synchronization of Insights recommendations from the Red Hat cloud'), default: true, full_name: N_('Synchronize recommendations Automatically'))
18
+ setting('allow_auto_insights_mismatch_delete', type: :boolean, description: N_('Enable automatic deletion of mismatched host records from the Red Hat cloud'), default: false, full_name: N_('Automatic mismatch deletion'))
19
+ setting('obfuscate_inventory_hostnames', type: :boolean, description: N_('Obfuscate host names sent to the Red Hat cloud. (If insights_minimal_data_collection is set to true, this setting is ignored because host names are not included in the report.)'), default: false, full_name: N_('Obfuscate host names'))
20
+ setting('obfuscate_inventory_ips', type: :boolean, description: N_('Obfuscate ipv4 addresses sent to the Red Hat cloud. (If insights_minimal_data_collection is set to true, this setting is ignored because host IPv4 addresses are not included in the report.)'), default: false, full_name: N_('Obfuscate host ipv4 addresses.'))
21
+ setting('exclude_installed_packages', type: :boolean, description: N_('Exclude installed packages from being uploaded to the Red Hat cloud. (If insights_minimal_data_collection is set to true, this setting is ignored and installed packages are always excluded.)'), default: false, full_name: N_("Exclude installed packages"))
22
+ setting('include_parameter_tags', type: :boolean, description: N_('Should import include parameter tags from Foreman?'), default: false, full_name: N_('Include parameters in insights-client reports'))
23
+ setting('rhc_instance_id', type: :string, description: N_('RHC daemon id'), default: nil, full_name: N_('ID of the RHC(Yggdrasil) daemon'))
24
+ setting('insights_minimal_data_collection', type: :boolean, default: false, full_name: N_('Minimal data collection'), description: N_('Only include the minimum required data in inventory reports for uploading to Red Hat cloud. When this is true, installed packages are excluded from the report regardless of the exclude_installed_packages setting, and host names and IPv4 addresses are excluded from the report regardless of obfuscation settings.'))
25
+ end
26
+ end
27
+
28
+ # Add permissions
29
+ security_block :foreman_rh_cloud do
30
+ permission(
31
+ :generate_foreman_rh_cloud,
32
+ 'foreman_inventory_upload/reports': [:generate],
33
+ 'foreman_inventory_upload/tasks': [:create],
34
+ 'api/v2/rh_cloud/inventory': [:get_hosts, :remove_hosts, :sync_inventory_status, :download_file, :generate_report, :enable_cloud_connector],
35
+ 'foreman_inventory_upload/uploads': [:enable_cloud_connector],
36
+ 'foreman_inventory_upload/uploads_settings': [:set_advanced_setting],
37
+ 'foreman_inventory_upload/missing_hosts': [:remove_hosts],
38
+ 'insights_cloud/settings': [:update],
39
+ 'insights_cloud/tasks': [:create]
40
+ )
41
+ permission(
42
+ :view_foreman_rh_cloud,
43
+ 'foreman_inventory_upload/accounts': [:index],
44
+ 'foreman_inventory_upload/reports': [:last],
45
+ 'foreman_inventory_upload/uploads': [:auto_upload, :show_auto_upload, :download_file, :last],
46
+ 'foreman_inventory_upload/tasks': [:show],
47
+ 'foreman_inventory_upload/cloud_status': [:index],
48
+ 'foreman_inventory_upload/uploads_settings': [:index],
49
+ 'foreman_inventory_upload/missing_hosts': [:index],
50
+ 'api/v2/rh_cloud/advisor_engine_config': [:show],
51
+ 'react': [:index]
52
+ )
53
+ permission(
54
+ :view_insights_hits,
55
+ {
56
+ '/foreman_rh_cloud/insights_cloud': [:index], # for bookmarks and later for showing the page
57
+ 'insights_cloud/hits': [:index, :show, :auto_complete_search, :resolutions],
58
+ 'insights_cloud/settings': [:index, :show],
59
+ 'insights_cloud/ui_requests': [:forward_request, :translate_insights_host],
60
+ 'react': [:index],
61
+ },
62
+ :resource_type => ::InsightsHit.name
63
+ )
64
+ permission(
65
+ :dispatch_cloud_requests,
66
+ 'api/v2/rh_cloud/cloud_request': [:update]
67
+ )
68
+ permission(
69
+ :control_organization_insights,
70
+ 'insights_cloud/settings': [:set_org_parameter]
71
+ )
72
+ end
73
+
74
+ plugin_permissions = [:view_foreman_rh_cloud, :generate_foreman_rh_cloud, :view_insights_hits, :dispatch_cloud_requests, :control_organization_insights]
75
+
76
+ role 'ForemanRhCloud', plugin_permissions, 'Role granting permissions to view the hosts inventory,
77
+ generate a report, upload it to the cloud and download it locally'
78
+
79
+ add_permissions_to_default_roles Role::ORG_ADMIN => plugin_permissions,
80
+ Role::MANAGER => plugin_permissions,
81
+ Role::SYSTEM_ADMIN => plugin_permissions
82
+
83
+ # Adding a top-level menu item
84
+ sub_menu :top_menu, :insights_menu, caption: N_('Insights'), icon: 'fa fa-cloud', after: :hosts_menu do
85
+ menu :top_menu,
86
+ :inventory_upload,
87
+ caption: N_('Inventory Upload'),
88
+ url: '/foreman_rh_cloud/inventory_upload',
89
+ url_hash: { controller: :react, action: :index },
90
+ parent: :insights_menu
91
+ menu :top_menu, :insights_hits, caption: N_('Recommendations'), url: '/foreman_rh_cloud/insights_cloud', url_hash: { controller: :react, action: :index }, parent: :insights_menu
92
+ menu :top_menu,
93
+ :insights_vulnerability,
94
+ caption: N_('Vulnerability'),
95
+ url: '/foreman_rh_cloud/insights_vulnerability',
96
+ url_hash: { controller: :react, action: :index },
97
+ parent: :insights_menu,
98
+ if: -> { ForemanRhCloud.with_local_advisor_engine? }
99
+ end
100
+
101
+ register_facet InsightsFacet, :insights do
102
+ configure_host do
103
+ api_view :list => 'api/v2/hosts/insights/insights', :single => 'api/v2/hosts/insights/single'
104
+ set_dependent_action :destroy
105
+ end
106
+ end
107
+
108
+ register_global_js_file 'global'
109
+
110
+ register_custom_status InventorySync::InventoryStatus
111
+ register_custom_status InsightsClientReportStatus
112
+
113
+ describe_host do
114
+ overview_buttons_provider :insights_host_overview_buttons
115
+ end
116
+
117
+ extend_page 'hosts/show' do |context|
118
+ context.add_pagelet :main_tabs,
119
+ partial: 'hosts/insights_tab',
120
+ name: _('Insights'),
121
+ id: 'insights',
122
+ onlyif: proc { |host| host.insights }
123
+ end
124
+
125
+ extend_page 'hosts/_list' do |context|
126
+ context.with_profile :cloud, _('RH Cloud'), default: true do
127
+ add_pagelet :hosts_table_column_header, key: :insights_recommendations_count, label: _('Recommendations'), sortable: true, width: '12%', class: 'hidden-xs ellipsis', priority: 100,
128
+ export_data: CsvExporter::ExportDefinition.new(:insights_recommendations_count, callback: ->(host) { host&.insights_hits&.count })
129
+ add_pagelet :hosts_table_column_content, key: :insights_recommendations_count, callback: ->(host) { hits_counts_cell(host) }, class: 'hidden-xs ellipsis text-center', priority: 100
130
+ end
131
+ end
132
+
133
+ extend_template_helpers ForemanRhCloud::TemplateRendererHelper
134
+ allowed_template_helpers :remediations_playbook, :download_rh_playbook
135
+ end
136
+ end
137
+ end
138
+ end
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '12.1.5'.freeze
2
+ VERSION = '12.2.1'.freeze
3
3
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "12.1.5",
3
+ "version": "12.2.1",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -9,6 +9,29 @@ module InsightsCloud
9
9
  FactoryBot.create(:common_parameter, name: InsightsCloud.enable_client_param, key_type: 'boolean', value: true)
10
10
  end
11
11
 
12
+ context '#translate_insights_host' do
13
+ setup do
14
+ @org = FactoryBot.create(:organization)
15
+ @loc = FactoryBot.create(:location)
16
+ @host = FactoryBot.create(:host, :with_subscription, :organization => @org)
17
+ @facet = InsightsFacet.create(host: @host, uuid: @host.subscription_facet.uuid)
18
+ end
19
+
20
+ test "should redirect to host details page by id" do
21
+ get :translate_insights_host, params: { "uuid" => @host.subscription_facet.uuid }, session: set_session
22
+ assert_equal 302, @response.status
23
+ assert @response.redirect?
24
+ assert_equal "http://test.host/new/hosts/#{@host.id}", @response.redirect_url
25
+ end
26
+
27
+ test "should redirect to not-found page" do
28
+ get :translate_insights_host, params: { "uuid" => "foo" }, session: set_session
29
+ assert_equal 302, @response.status
30
+ assert @response.redirect?
31
+ assert_equal "http://test.host/page-not-found", @response.redirect_url
32
+ end
33
+ end
34
+
12
35
  context '#forward_request' do
13
36
  include MockCerts
14
37
 
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
4
4
  import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
5
+ import './CVEsHostDetailsTab.scss';
5
6
 
6
7
  const CVEsHostDetailsTab = ({ systemId }) => {
7
8
  const scope = 'vulnerability';
@@ -0,0 +1,3 @@
1
+ div.rh-cloud-insights-vulnerability-host-details-component {
2
+ padding: 24px;
3
+ }
@@ -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,20 +1,16 @@
1
1
  import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
4
+ import { Link } from 'react-router-dom';
2
5
  import { translate as __ } from 'foremanReact/common/I18n';
3
6
  import { propsToCamelCase } from 'foremanReact/common/helpers';
4
7
  import { CVECountCell } from '../InsightsVulnerabilityHostIndexExtensions/CVECountCell';
5
8
 
6
- const RecommendationsCell = hostDetails => {
9
+ const HostedRecommendationsCell = hostDetails => {
7
10
  const insightsAttributes = propsToCamelCase(
8
11
  // eslint-disable-next-line camelcase
9
12
  hostDetails?.insights_attributes ?? {}
10
13
  );
11
- // Local insights advisor
12
- if (insightsAttributes.useLocalAdvisorEngine) {
13
- // TODO: Replace this placeholder with the actual local advisor integration
14
- return <span>Local advisor placeholder</span>;
15
- }
16
-
17
- // Hosted insights advisor
18
14
  const { insightsHitsCount: hitsCount } = insightsAttributes;
19
15
  if (hitsCount === undefined || hitsCount === null) return '—';
20
16
  const hostname = hostDetails?.name;
@@ -23,6 +19,40 @@ const RecommendationsCell = hostDetails => {
23
19
  return <a href={hitsUrl}>{hitsCount}</a>;
24
20
  };
25
21
 
22
+ const IopRecommendationsCell = ({ hostDetails }) => {
23
+ // eslint-disable-next-line camelcase
24
+ const uuid = hostDetails?.insights_attributes?.uuid;
25
+ const { response } = useAPI(
26
+ uuid ? 'get' : null,
27
+ `/insights_cloud/api/insights/v1/system/${uuid}`,
28
+ { key: `HOST_RECS_COUNT_${uuid}` }
29
+ );
30
+
31
+ const hits = response?.hits;
32
+ return hits === undefined ? (
33
+ '—'
34
+ ) : (
35
+ <Link to={`hosts/${hostDetails.name}#/Insights`}>{hits}</Link>
36
+ );
37
+ };
38
+
39
+ IopRecommendationsCell.propTypes = {
40
+ hostDetails: PropTypes.object.isRequired,
41
+ };
42
+
43
+ const RecommendationsCell = hostDetails => {
44
+ const insightsAttributes = propsToCamelCase(
45
+ // eslint-disable-next-line camelcase
46
+ hostDetails?.insights_attributes ?? {}
47
+ );
48
+
49
+ return insightsAttributes.useLocalAdvisorEngine ? (
50
+ <IopRecommendationsCell hostDetails={hostDetails} />
51
+ ) : (
52
+ <HostedRecommendationsCell hostDetails={hostDetails} />
53
+ );
54
+ };
55
+
26
56
  const insightsCategoryName = __('Insights');
27
57
 
28
58
  const hostsIndexColumnExtensions = [
@@ -3,6 +3,7 @@ import { Text } from '@patternfly/react-core';
3
3
  import { useSelector } from 'react-redux';
4
4
 
5
5
  import { translate as __ } from 'foremanReact/common/I18n';
6
+ import { getDocsURL } from 'foremanReact/common/helpers';
6
7
  import { FormattedMessage } from 'react-intl';
7
8
  import { selectSubscriptionConnectionEnabled } from '../../../InventorySettings/InventorySettingsSelectors';
8
9
 
@@ -53,6 +54,28 @@ export const PageDescription = () => {
53
54
  />
54
55
  </Text>
55
56
  )}
57
+ <Text ouiaId="text-minimal-data-collection">
58
+ <FormattedMessage
59
+ id="minimal-data-collection-message"
60
+ defaultMessage={__(
61
+ 'Learn more about {minimalDataCollectionSetting}.'
62
+ )}
63
+ values={{
64
+ minimalDataCollectionSetting: (
65
+ <a
66
+ href={getDocsURL(
67
+ 'Managing_Hosts',
68
+ 'setting-minimal-data-collection'
69
+ )}
70
+ target="_blank"
71
+ rel="noopener noreferrer"
72
+ >
73
+ {__('setting minimal data collection')}
74
+ </a>
75
+ ),
76
+ }}
77
+ />
78
+ </Text>
56
79
  <Text ouiaId="text-more-info-subscription">
57
80
  {__('For more information about the Subscriptions service, see:')}
58
81
  &nbsp;
@@ -15,6 +15,8 @@ jest.mock('react-intl', () => {
15
15
  }),
16
16
  };
17
17
  });
18
+ jest.mock('foremanReact/common/helpers', () => ({ getDocsURL: () => {} }));
19
+
18
20
  const middlewares = [thunk];
19
21
  const mockStore = configureMockStore(middlewares);
20
22
 
@@ -1,19 +1,24 @@
1
+ /* eslint-disable spellcheck/spell-checker */
1
2
  import React from 'react';
2
3
  import componentRegistry from 'foremanReact/components/componentRegistry';
3
4
  import { registerRoutes as foremanRegisterRoutes } from 'foremanReact/routes/RoutingService';
4
5
  import ForemanInventoryUpload from './ForemanInventoryUpload';
5
6
  import InsightsVulnerabilityListPage from './InsightsVulnerability/InsightsVulnerabilityListPage';
6
7
  import InsightsCloudSync from './InsightsCloudSync';
8
+ import IopRecommendationDetails from './IopRecommendationDetails/IopRecommendationDetails';
7
9
  import InsightsHostDetailsTab from './InsightsHostDetailsTab';
10
+ import CveDetailsPage from './CveDetailsPage';
8
11
 
9
12
  const pages = [
10
13
  { name: 'ForemanInventoryUpload', type: ForemanInventoryUpload },
11
14
  { name: 'InsightsCloudSync', type: InsightsCloudSync },
15
+ { name: 'IopRecommendationDetails', type: IopRecommendationDetails },
12
16
  { name: 'InsightsHostDetailsTab', type: InsightsHostDetailsTab },
13
17
  {
14
18
  name: 'InsightsVulnerabilityListPage',
15
19
  type: InsightsVulnerabilityListPage,
16
20
  },
21
+ { name: 'CveDetailsPage', type: CveDetailsPage },
17
22
  ];
18
23
 
19
24
  export const registerPages = () => {
@@ -26,6 +31,11 @@ export const routes = [
26
31
  exact: true,
27
32
  render: props => <InsightsCloudSync {...props} />,
28
33
  },
34
+ {
35
+ path: '/foreman_rh_cloud/recommendations',
36
+ exact: false,
37
+ render: props => <IopRecommendationDetails {...props} />,
38
+ },
29
39
  {
30
40
  path: '/foreman_rh_cloud/inventory_upload',
31
41
  exact: true,
@@ -36,6 +46,11 @@ export const routes = [
36
46
  exact: true,
37
47
  render: props => <InsightsVulnerabilityListPage {...props} />,
38
48
  },
49
+ {
50
+ path: '/foreman_rh_cloud/insights_vulnerability/:cveId',
51
+ exact: true,
52
+ render: props => <CveDetailsPage {...props} />,
53
+ },
39
54
  ];
40
55
 
41
56
  export const registerRoutes = () => {
@@ -1,7 +1,10 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
4
+ import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
4
5
  import InsightsTable from './Components/InsightsTable';
6
+ import { useAdvisorEngineConfig } from '../common/Hooks/ConfigHooks';
7
+ import { foremanUrl } from '../ForemanRhCloudHelpers';
5
8
  import RemediationModal from './Components/RemediationModal';
6
9
  import {
7
10
  INSIGHTS_SYNC_PAGE_TITLE,
@@ -11,7 +14,9 @@ import './InsightsCloudSync.scss';
11
14
  import Pagination from './Components/InsightsTable/Pagination';
12
15
  import ToolbarDropdown from './Components/ToolbarDropdown';
13
16
  import InsightsSettings from './Components/InsightsSettings';
17
+ import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
14
18
 
19
+ // Hosted Insights advisor
15
20
  const InsightsCloudSync = ({ syncInsights, query, fetchInsights }) => {
16
21
  const onRecommendationSync = () => syncInsights(fetchInsights, query);
17
22
  const toolbarButtons = (
@@ -54,4 +59,37 @@ InsightsCloudSync.defaultProps = {
54
59
  query: '',
55
60
  };
56
61
 
57
- export default InsightsCloudSync;
62
+ // Local Insights advisor
63
+ const scope = 'advisor';
64
+ const module = './ListWrapped';
65
+
66
+ export const generateRuleUrl = ruleId =>
67
+ foremanUrl(`/foreman_rh_cloud/recommendations/${ruleId}`);
68
+
69
+ const IopRecommendationsPage = props => (
70
+ <ScalprumComponent
71
+ scope={scope}
72
+ module={module}
73
+ IopRemediationModal={RemediationModal}
74
+ generateRuleUrl={generateRuleUrl}
75
+ {...props}
76
+ />
77
+ );
78
+
79
+ const IopRecommendationsPageWrapped = props => (
80
+ <ScalprumProvider {...providerOptions}>
81
+ <IopRecommendationsPage {...props} />
82
+ </ScalprumProvider>
83
+ );
84
+
85
+ const RecommendationsPage = props => {
86
+ const isLocalAdvisorEngine = useAdvisorEngineConfig();
87
+
88
+ return isLocalAdvisorEngine ? (
89
+ <IopRecommendationsPageWrapped {...props} />
90
+ ) : (
91
+ <InsightsCloudSync {...props} />
92
+ );
93
+ };
94
+
95
+ export default RecommendationsPage;
@@ -1,54 +1,10 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`InsightsCloudSync render 1`] = `
4
- <div
5
- className="rh-cloud-insights"
6
- >
7
- <Connect(InsightsSettings) />
8
- <PageLayout
9
- beforeToolbarComponent={null}
10
- header="Red Hat Insights"
11
- onSearch={[Function]}
12
- searchProps={
13
- Object {
14
- "autocomplete": Object {
15
- "id": "searchBar",
16
- "searchQuery": "",
17
- "url": "/insights_cloud/hits/auto_complete_search",
18
- "useKeyShortcuts": true,
19
- },
20
- "bookmarks": Object {
21
- "canCreateBookmarks": true,
22
- "documentationUrl": "4.1.5Searching",
23
- "url": "/api/bookmarks",
24
- },
25
- "controller": "insights_hits",
26
- }
27
- }
28
- searchQuery=""
29
- searchable={true}
30
- toolbarButtons={
31
- <React.Fragment>
32
- <span
33
- className="insights-toolbar-buttons"
34
- >
35
- <Memo(Connect(RemediationModal)) />
36
- <ToolbarDropdown
37
- onRecommendationSync={[Function]}
38
- />
39
- </span>
40
- <span
41
- className="pull-right"
42
- >
43
- <Pagination
44
- isCompact={true}
45
- variant="top"
46
- />
47
- </span>
48
- </React.Fragment>
49
- }
50
- >
51
- <Connect(InsightsTable) />
52
- </PageLayout>
53
- </div>
4
+ <InsightsCloudSync
5
+ fetchInsights={[Function]}
6
+ query=""
7
+ status="RESOLVED"
8
+ syncInsights={[Function]}
9
+ />
54
10
  `;
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
4
  import SearchBar from 'foremanReact/components/SearchBar';
5
5
  import { translate as __ } from 'foremanReact/common/I18n';
6
+ import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
6
7
  import { Grid, GridItem } from '@patternfly/react-core';
7
8
  import {
8
9
  Dropdown,
@@ -21,7 +22,10 @@ import {
21
22
  } from '../InsightsCloudSync/Components/InsightsTable/InsightsTableSelectors';
22
23
  import { redHatAdvisorSystems } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
23
24
  import { useAdvisorEngineConfig } from '../common/Hooks/ConfigHooks';
25
+ import { generateRuleUrl } from '../InsightsCloudSync/InsightsCloudSync';
26
+ import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
24
27
 
28
+ // Hosted Insights advisor
25
29
  const NewHostDetailsTab = ({ hostName, router }) => {
26
30
  const dispatch = useDispatch();
27
31
  const query = useSelector(selectSearch);
@@ -104,4 +108,49 @@ NewHostDetailsTab.defaultProps = {
104
108
  router: {},
105
109
  };
106
110
 
107
- export default NewHostDetailsTab;
111
+ // Local Insights advisor
112
+ const scope = 'advisor';
113
+ const module = './SystemDetailsWrapped';
114
+
115
+ const IopInsightsTab = props => (
116
+ <ScalprumComponent
117
+ scope={scope}
118
+ module={module}
119
+ IopRemediationModal={RemediationModal}
120
+ generateRuleUrl={generateRuleUrl}
121
+ {...props}
122
+ />
123
+ );
124
+
125
+ const IopInsightsTabWrapped = props => (
126
+ <ScalprumProvider {...providerOptions}>
127
+ <IopInsightsTab {...props} />
128
+ </ScalprumProvider>
129
+ );
130
+
131
+ const InsightsTab = props => {
132
+ const { response } = props;
133
+ const isLocalAdvisorEngine =
134
+ // eslint-disable-next-line camelcase
135
+ response?.insights_attributes?.use_local_advisor_engine;
136
+
137
+ return isLocalAdvisorEngine ? (
138
+ <IopInsightsTabWrapped {...props} />
139
+ ) : (
140
+ <NewHostDetailsTab {...props} />
141
+ );
142
+ };
143
+
144
+ InsightsTab.propTypes = {
145
+ response: PropTypes.shape({
146
+ insights_attributes: {
147
+ use_local_advisor_engine: PropTypes.bool,
148
+ },
149
+ }),
150
+ };
151
+
152
+ InsightsTab.defaultProps = {
153
+ response: {},
154
+ };
155
+
156
+ export default InsightsTab;
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { useRouteMatch } from 'react-router-dom';
3
+ import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
4
+
5
+ import RemediationModal from '../InsightsCloudSync/Components/RemediationModal';
6
+ import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
7
+
8
+ const scope = 'advisor';
9
+ const module = './RecommendationDetailsWrapped';
10
+
11
+ const IopRecommendationDetails = props => {
12
+ const urlParams = useRouteMatch('/foreman_rh_cloud/recommendations/:rule_id');
13
+ // eslint-disable-next-line camelcase
14
+ const ruleId = urlParams?.params?.rule_id;
15
+ return (
16
+ <div className="iop-recommendation-details-scalprum">
17
+ <ScalprumComponent
18
+ scope={scope}
19
+ module={module}
20
+ IopRemediationModal={RemediationModal}
21
+ ruleId={ruleId}
22
+ {...props}
23
+ />
24
+ </div>
25
+ );
26
+ };
27
+
28
+ const IopRecommendationDetailsWrapped = props => (
29
+ <ScalprumProvider {...providerOptions}>
30
+ <IopRecommendationDetails {...props} />
31
+ </ScalprumProvider>
32
+ );
33
+
34
+ export default IopRecommendationDetailsWrapped;
@@ -4,6 +4,16 @@ export const modulesConfig = {
4
4
  manifestLocation: `${window.location.origin}/assets/apps/vulnerability/fed-mods.json`,
5
5
  cdnPath: `${window.location.origin}/assets/apps/vulnerability/`,
6
6
  },
7
+ advisor: {
8
+ name: 'advisor',
9
+ manifestLocation: `${window.location.origin}/assets/apps/advisor/fed-mods.json`,
10
+ cdnPath: `${window.location.origin}/assets/apps/advisor/`,
11
+ },
12
+ inventory: {
13
+ name: 'inventory',
14
+ manifestLocation: `${window.location.origin}/assets/apps/inventory/fed-mods.json`,
15
+ cdnPath: `${window.location.origin}/assets/apps/inventory/`,
16
+ },
7
17
  };
8
18
 
9
19
  export const mockUser = {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_rh_cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.1.5
4
+ version: 12.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Red Hat Cloud team
@@ -202,6 +202,7 @@ files:
202
202
  - lib/foreman_rh_cloud.rb
203
203
  - lib/foreman_rh_cloud/async/exponential_backoff.rb
204
204
  - lib/foreman_rh_cloud/engine.rb
205
+ - lib/foreman_rh_cloud/plugin.rb
205
206
  - lib/foreman_rh_cloud/version.rb
206
207
  - lib/insights_cloud.rb
207
208
  - lib/insights_cloud/async/cloud_connector_announce_task.rb
@@ -290,8 +291,12 @@ files:
290
291
  - test/unit/slice_generator_test.rb
291
292
  - test/unit/tags_generator_test.rb
292
293
  - webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js
294
+ - webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.scss
293
295
  - webpack/CVEsHostDetailsTab/__tests__/CVEsHostDetailsTab.test.js
294
296
  - webpack/CVEsHostDetailsTab/index.js
297
+ - webpack/CveDetailsPage/CveDetailsPage.js
298
+ - webpack/CveDetailsPage/CveDetailsPage.test.js
299
+ - webpack/CveDetailsPage/index.js
295
300
  - webpack/ForemanColumnExtensions/index.js
296
301
  - webpack/ForemanInventoryUpload/Components/AccountList/AccountList.fixtures.js
297
302
  - webpack/ForemanInventoryUpload/Components/AccountList/AccountList.js
@@ -621,6 +626,7 @@ files:
621
626
  - webpack/InsightsVulnerability/InsightsVulnerabilityListPage.test.js
622
627
  - webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js
623
628
  - webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js
629
+ - webpack/IopRecommendationDetails/IopRecommendationDetails.js
624
630
  - webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js
625
631
  - webpack/__mocks__/foremanReact/common/I18n.js
626
632
  - webpack/__mocks__/foremanReact/common/MountingService.js