foreman_rh_cloud 12.2.1 → 12.2.3

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/rh_cloud/advisor_engine_config_controller.rb +1 -1
  3. data/app/controllers/api/v2/rh_cloud/cloud_request_controller.rb +3 -0
  4. data/app/controllers/api/v2/rh_cloud/inventory_controller.rb +3 -0
  5. data/app/controllers/concerns/foreman_rh_cloud/iop_smart_proxy_access.rb +28 -0
  6. data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +1 -1
  7. data/app/controllers/foreman_inventory_upload/uploads_controller.rb +3 -0
  8. data/app/controllers/foreman_rh_cloud/foreman_rh_cloud_controller.rb +22 -0
  9. data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +19 -5
  10. data/app/models/foreman_rh_cloud/ping.rb +90 -0
  11. data/app/services/foreman_rh_cloud/cert_auth.rb +1 -1
  12. data/app/services/foreman_rh_cloud/cloud_request.rb +1 -1
  13. data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +1 -1
  14. data/app/services/foreman_rh_cloud/hit_remediations_retriever.rb +27 -10
  15. data/app/services/foreman_rh_cloud/insights_api_forwarder.rb +14 -12
  16. data/app/services/foreman_rh_cloud/tags_auth.rb +3 -2
  17. data/app/views/api/v2/hosts/insights/base.rabl +2 -2
  18. data/app/views/api/v2/hosts/insights/single.rabl +1 -1
  19. data/config/routes.rb +6 -14
  20. data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +2 -2
  21. data/lib/foreman_inventory_upload/async/upload_report_job.rb +1 -1
  22. data/lib/foreman_inventory_upload/generators/slice.rb +24 -0
  23. data/lib/foreman_rh_cloud/engine.rb +6 -2
  24. data/lib/foreman_rh_cloud/plugin.rb +18 -2
  25. data/lib/foreman_rh_cloud/version.rb +1 -1
  26. data/lib/foreman_rh_cloud.rb +5 -6
  27. data/lib/insights_cloud/async/insights_scheduled_sync.rb +2 -2
  28. data/lib/inventory_sync/async/inventory_hosts_sync.rb +1 -1
  29. data/lib/inventory_sync/async/inventory_scheduled_sync.rb +2 -2
  30. data/lib/tasks/insights.rake +1 -1
  31. data/lib/tasks/rh_cloud_inventory.rake +20 -2
  32. data/package.json +1 -1
  33. data/test/controllers/insights_cloud/api/machine_telemetries_controller_test.rb +20 -3
  34. data/test/controllers/insights_sync/settings_controller_test.rb +1 -1
  35. data/test/factories/inventory_upload_factories.rb +4 -112
  36. data/test/jobs/inventory_scheduled_sync_test.rb +3 -3
  37. data/test/test_plugin_helper.rb +8 -2
  38. data/test/unit/rh_cloud_http_proxy_test.rb +3 -3
  39. data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +4 -1
  40. data/test/unit/services/foreman_rh_cloud/insights_api_forwarder_test.rb +43 -2
  41. data/test/unit/services/foreman_rh_cloud/tags_auth_test.rb +15 -1
  42. data/test/unit/slice_generator_test.rb +33 -0
  43. data/test/unit/tags_generator_test.rb +4 -1
  44. data/webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js +1 -1
  45. data/webpack/CveDetailsPage/CveDetailsPage.js +1 -1
  46. data/webpack/CveDetailsPage/CveDetailsPage.test.js +1 -3
  47. data/webpack/ForemanColumnExtensions/index.js +1 -1
  48. data/webpack/ForemanRhCloudPages.js +1 -0
  49. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationHelpers.js +26 -4
  50. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +85 -11
  51. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModalFooter.js +39 -5
  52. data/webpack/InsightsCloudSync/Components/RemediationModal/Resolutions.js +13 -0
  53. data/webpack/InsightsCloudSync/InsightsCloudSync.js +9 -7
  54. data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +12 -10
  55. data/webpack/InsightsVulnerability/InsightsVulnerabilityListPage.js +1 -1
  56. data/webpack/IopRecommendationDetails/IopRecommendationDetails.js +1 -1
  57. data/webpack/common/Hooks/ConfigHooks.js +1 -2
  58. data/webpack/common/styles.scss +7 -0
  59. metadata +5 -1
@@ -13,7 +13,7 @@ module InsightsCloud
13
13
  return
14
14
  end
15
15
 
16
- if ForemanRhCloud.with_local_advisor_engine?
16
+ if ForemanRhCloud.with_iop_smart_proxy?
17
17
  plan_self
18
18
  else
19
19
  after_delay do
@@ -23,7 +23,7 @@ module InsightsCloud
23
23
  end
24
24
 
25
25
  def run
26
- output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
26
+ output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local IoP Smart Proxy.') if ForemanRhCloud.with_iop_smart_proxy?
27
27
  end
28
28
 
29
29
  def plan_full_sync
@@ -9,7 +9,7 @@ module InventorySync
9
9
 
10
10
  def plan(organizations)
11
11
  # Do not run for local advisor, since we use sub-man id to identify hosts.
12
- return if ForemanRhCloud.with_local_advisor_engine?
12
+ return if ForemanRhCloud.with_iop_smart_proxy?
13
13
  # by default the tasks will be executed concurrently
14
14
  super(organizations)
15
15
  plan_self_host_sync
@@ -13,7 +13,7 @@ module InventorySync
13
13
  return
14
14
  end
15
15
 
16
- if ForemanRhCloud.with_local_advisor_engine?
16
+ if ForemanRhCloud.with_iop_smart_proxy?
17
17
  plan_self # so that 'run' runs
18
18
  else
19
19
  after_delay do
@@ -35,7 +35,7 @@ module InventorySync
35
35
  end
36
36
 
37
37
  def run
38
- output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
38
+ output[:status] = _('The scheduled process is disabled because this Foreman is configured with a local IoP Smart Proxy.') if ForemanRhCloud.with_iop_smart_proxy?
39
39
  end
40
40
 
41
41
  def plan_remove_insights_hosts(org_id)
@@ -24,7 +24,7 @@ namespace :rh_cloud_insights do
24
24
  desc "Re-announce all organizations into Sources on RH cloud."
25
25
  task announce_to_sources: [:environment] do
26
26
  logger = Logging::Logger.new(STDOUT)
27
- if ForemanRhCloud.with_local_advisor_engine?
27
+ if ForemanRhCloud.with_iop_smart_proxy?
28
28
  logger.warn('Task announce_to_sources is not available when using local advisor engine')
29
29
  else
30
30
  Organization.unscoped.each do |org|
@@ -9,7 +9,7 @@ namespace :rh_cloud_inventory do
9
9
  else
10
10
  organizations = [Organization.where(:id => ENV['organization_id']).first]
11
11
  end
12
- disconnected = ForemanRhCloud.with_local_advisor_engine?
12
+ disconnected = ForemanRhCloud.with_iop_smart_proxy?
13
13
  User.as_anonymous_admin do
14
14
  organizations.each do |organization|
15
15
  ForemanTasks.async_task(
@@ -45,6 +45,24 @@ namespace :rh_cloud_inventory do
45
45
  archived_report_generator = ForemanInventoryUpload::Generators::ArchivedReport.new(target, Logger.new(STDOUT))
46
46
  archived_report_generator.render(organization: organization, filter: filter)
47
47
  puts "Successfully generated #{target} for organization id #{organization}"
48
+
49
+ next unless ForemanRhCloud.with_iop_smart_proxy?
50
+
51
+ puts 'Creating missing insights facets'
52
+ hosts_without_facets = ForemanInventoryUpload::Generators::Queries.for_org(organization, hosts_query: 'null? insights_uuid')
53
+ hosts_without_facets.each do |batch|
54
+ facets = batch.pluck(:id, 'katello_subscription_facets.uuid').map do |host_id, uuid|
55
+ {
56
+ host_id: host_id,
57
+ uuid: uuid,
58
+ }
59
+ end
60
+ # We don't need to validate the facets here as we create the necessary fields.
61
+ # rubocop:disable Rails/SkipsModelValidations
62
+ InsightsFacet.upsert_all(facets, unique_by: :host_id) unless facets.empty?
63
+ # rubocop:enable Rails/SkipsModelValidations
64
+ end
65
+ puts 'Missing Insights facets created'
48
66
  end
49
67
  end
50
68
  end
@@ -53,7 +71,7 @@ namespace :rh_cloud_inventory do
53
71
  base_folder = ENV['target'] || ForemanInventoryUpload.generated_reports_folder
54
72
  organization_id = ENV['organization_id']
55
73
  report_file = ForemanInventoryUpload.facts_archive_name(organization_id)
56
- disconnected = ForemanRhCloud.with_local_advisor_engine?
74
+ disconnected = ForemanRhCloud.with_iop_smart_proxy?
57
75
  ForemanTasks.sync_task(ForemanInventoryUpload::Async::QueueForUploadJob, base_folder, report_file, organization_id, disconnected)
58
76
  puts "Uploaded #{report_file}"
59
77
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "12.2.1",
3
+ "version": "12.2.3",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -17,8 +17,8 @@ module InsightsCloud::Api
17
17
  @http_req = RestClient::Request.new(:method => 'GET', :url => 'http://test.theforeman.org')
18
18
 
19
19
  org = FactoryBot.create(:organization)
20
- host = FactoryBot.create(:host, :with_subscription, :organization => org)
21
- User.current = ::Katello::CpConsumerUser.new(:uuid => host.subscription_facet.uuid, :login => host.subscription_facet.uuid)
20
+ @host = FactoryBot.create(:host, :with_subscription, :organization => org)
21
+ User.current = ::Katello::CpConsumerUser.new(:uuid => @host.subscription_facet.uuid, :login => @host.subscription_facet.uuid)
22
22
  InsightsCloud::Api::MachineTelemetriesController.any_instance.stubs(:upstream_owner).returns({ 'uuid' => 'abcdefg' })
23
23
 
24
24
  setup_certs_expectation do
@@ -151,6 +151,20 @@ module InsightsCloud::Api
151
151
  assert_equal 'Cloud request failed', JSON.parse(@response.body)['message']
152
152
  assert_match /#{@body}/, JSON.parse(@response.body)['response']
153
153
  end
154
+
155
+ test "should create insights facet" do
156
+ assert_nil InsightsFacet.find_by(host_id: @host.id)
157
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
158
+ req = RestClient::Request.new(:method => 'GET', :url => 'http://test.theforeman.org/')
159
+ net_http_resp = Net::HTTPResponse.new(1.0, 200, "OK")
160
+ net_http_resp[:content_type] = 'application/zip'
161
+ res = RestClient::Response.create(@body, net_http_resp, req)
162
+ ::ForemanRhCloud::CloudRequestForwarder.any_instance.stubs(:forward_request).returns(res)
163
+
164
+ get :forward_request, params: { "path" => "/redhat_access/r/insights/uploads/" }
165
+
166
+ assert_not_nil InsightsFacet.find_by(host_id: @host.id)
167
+ end
154
168
  end
155
169
 
156
170
  context '#branch_info' do
@@ -166,7 +180,10 @@ module InsightsCloud::Api
166
180
  :with_content,
167
181
  :with_hostgroup,
168
182
  :with_parameter,
169
- content_view_environments: [make_cve(lifecycle_environment: env), make_cve(lifecycle_environment: env2)],
183
+ content_facet: FactoryBot.build(
184
+ :content_facet,
185
+ content_view_environments: [make_cve(lifecycle_environment: env), make_cve(lifecycle_environment: env2)]
186
+ ),
170
187
  organization: env.organization
171
188
  )
172
189
 
@@ -3,7 +3,7 @@ require 'test_plugin_helper'
3
3
  class SettingsControllerTest < ActionController::TestCase
4
4
  tests InsightsCloud::SettingsController
5
5
  def setup
6
- ForemanRhCloud.stubs(:with_local_advisor_engine?).returns(false)
6
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
7
7
  end
8
8
 
9
9
  test 'should return allow_auto_insights_sync setting' do
@@ -1,87 +1,3 @@
1
- # redefine katello factories, as long as katello is not compatible with dynamic properties
2
- FactoryBot.define do
3
- factory :katello_organization, :class => "Organization" do
4
- type { "Organization" }
5
- sequence(:name) { |n| "Organization#{n}" }
6
- sequence(:label) { |n| "org#{n}" }
7
- sequence(:id) { |n| n }
8
-
9
- trait :acme_corporation do
10
- name { "ACME_Corporation" }
11
- type { "Organization" }
12
- description { "This is the first Organization." }
13
- label { "acme_corporation_label" }
14
- end
15
-
16
- trait :with_library do
17
- association :library, :factory => :katello_library
18
- end
19
-
20
- factory :acme_corporation, :traits => [:acme_corporation]
21
- end
22
- end
23
-
24
- FactoryBot.define do
25
- factory :katello_content_view, :class => Katello::ContentView do
26
- sequence(:name) { |n| "Database#{n}" }
27
- description { "This content view is for database content" }
28
- association :organization, :factory => :katello_organization
29
-
30
- trait :composite do
31
- composite { true }
32
- end
33
- end
34
- end
35
-
36
- FactoryBot.define do
37
- factory :katello_content_view_environment, :class => Katello::ContentViewEnvironment do
38
- sequence(:name) { |n| "name#{n}" }
39
- sequence(:label) { |n| "label#{n}" }
40
- end
41
- end
42
-
43
- FactoryBot.define do
44
- factory :katello_k_t_environment, :aliases => [:katello_environment], :class => Katello::KTEnvironment do
45
- sequence(:name) { |n| "Environment#{n}" }
46
- sequence(:label) { |n| "environment#{n}" }
47
- association :organization, :factory => :katello_organization
48
- end
49
- end
50
-
51
- FactoryBot.define do
52
- factory :katello_content_facets, :aliases => [:content_facet], :class => ::Katello::Host::ContentFacet do
53
- sequence(:uuid) { |n| "uuid-#{n}" }
54
- end
55
- end
56
-
57
- FactoryBot.define do
58
- factory :katello_subscription_facets, :aliases => [:subscription_facet], :class => ::Katello::Host::SubscriptionFacet do
59
- sequence(:uuid) { |n| "00000000-%<n>04d-%<r>04d-0000-000000000000" % { n: n, r: rand(500) } }
60
- facts { { 'memory.memtotal' => "12 GB" } }
61
- end
62
- end
63
-
64
- FactoryBot.define do
65
- factory :katello_subscription, :class => Katello::Subscription do
66
- end
67
- end
68
-
69
- FactoryBot.define do
70
- factory :katello_pool, :class => Katello::Pool do
71
- active { true }
72
- end_date { Date.today + 1.year }
73
- cp_id { 1 }
74
-
75
- association :organization, :factory => :katello_organization
76
-
77
- after(:build) do |pool, _evaluator|
78
- pool.subscription.organization = pool.organization
79
- end
80
-
81
- association :subscription, :factory => :katello_subscription
82
- end
83
- end
84
-
85
1
  FactoryBot.define do
86
2
  factory :katello_host_collection_host, :class => Katello::HostCollectionHosts do
87
3
  host_id { nil }
@@ -94,34 +10,10 @@ FactoryBot.define do
94
10
  end
95
11
  end
96
12
 
13
+ # Fix Katello factories to return a valid UUID
97
14
  FactoryBot.modify do
98
- factory :host do
99
- transient do
100
- content_view { nil }
101
- lifecycle_environment { nil }
102
- content_source { nil }
103
- content_view_environments { [] }
104
- end
105
-
106
- trait :with_content do
107
- association :content_facet, :factory => :content_facet, :strategy => :build
108
-
109
- after(:build) do |host, evaluator|
110
- if host.content_facet
111
- if evaluator.content_view && evaluator.lifecycle_environment
112
- host.content_facet.assign_single_environment(
113
- content_view_id: evaluator.content_view.id,
114
- lifecycle_environment_id: evaluator.lifecycle_environment.id
115
- )
116
- end
117
- host.content_facet.content_source = evaluator.content_source if evaluator.content_source
118
- host.content_facet.content_view_environments = evaluator.content_view_environments unless evaluator.content_view_environments.empty?
119
- end
120
- end
121
- end
122
-
123
- trait :with_subscription do
124
- association :subscription_facet, :factory => :subscription_facet, :strategy => :build
125
- end
15
+ factory :katello_subscription_facets, :aliases => [:subscription_facet], :class => ::Katello::Host::SubscriptionFacet do
16
+ sequence(:uuid) { |n| "00000000-%<n>04d-%<r>04d-0000-000000000000" % { n: n, r: rand(500) } }
17
+ facts { { 'memory.memtotal' => "12 GB" } }
126
18
  end
127
19
  end
@@ -14,14 +14,14 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
14
14
  ForemanTasks.sync_task(InventorySync::Async::InventoryScheduledSync)
15
15
  end
16
16
 
17
- test 'Skips execution if with_local_advisor_engine? is true' do
18
- ForemanRhCloud.stubs(:with_local_advisor_engine?).returns(true)
17
+ test 'Skips execution if with_iop_smart_proxy? is true' do
18
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
19
19
 
20
20
  InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).never
21
21
 
22
22
  task = ForemanTasks.sync_task(InventorySync::Async::InventoryScheduledSync)
23
23
  status = task.output[:status].to_s
24
- assert_match(/Foreman is configured with the use_local_advisor_engine option/, status)
24
+ assert_match(/Foreman is configured with a local IoP Smart Proxy/, status)
25
25
  end
26
26
 
27
27
  test 'Skips execution if auto upload is disabled' do
@@ -2,10 +2,16 @@
2
2
  require 'test_helper'
3
3
 
4
4
  # Add plugin to FactoryBot's paths
5
- FactoryBot.definition_file_paths << "#{ForemanTasks::Engine.root}/test/factories"
5
+ katello_files = Dir.glob("#{Katello::Engine.root}/test/factories/**/*.rb")
6
+ FactoryBot.definition_file_paths +=
7
+ katello_files
8
+ # skip foreman_task factories, since we already have those definitions in ForemanTasks
9
+ .reject { |f| f =~ /foreman_task|recurring_logic/ }
10
+ .map { |f| f.gsub('.rb', '') } # .rb extension is will be appended by factorybot
6
11
  FactoryBot.definition_file_paths << "#{ForemanRemoteExecution::Engine.root}/test/factories"
12
+ FactoryBot.definition_file_paths << "#{ForemanTasks::Engine.root}/test/factories"
13
+
7
14
  FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
8
- # FactoryBot.definition_file_paths << "#{Katello::Engine.root}/test/factories"
9
15
  FactoryBot.reload
10
16
 
11
17
  begin
@@ -4,7 +4,7 @@ class RhCloudHttpProxyTest < ActiveSupport::TestCase
4
4
  setup do
5
5
  @global_content_proxy_mock = 'http://global:content@localhost:80'
6
6
  @global_foreman_proxy_mock = 'http://global:foreman@localhost:80'
7
- ForemanRhCloud.stubs(:with_local_advisor_engine?).returns(false)
7
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
8
8
  end
9
9
 
10
10
  test 'selects global content proxy' do
@@ -20,8 +20,8 @@ class RhCloudHttpProxyTest < ActiveSupport::TestCase
20
20
  end
21
21
 
22
22
  test 'returns empty string in on-prem setup' do
23
- ForemanRhCloud.unstub(:with_local_advisor_engine?)
24
- ForemanRhCloud.stubs(:with_local_advisor_engine?).returns(true)
23
+ ForemanRhCloud.unstub(:with_iop_smart_proxy?)
24
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
25
25
 
26
26
  assert_empty ForemanRhCloud.proxy_setting
27
27
  end
@@ -22,7 +22,10 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
22
22
  :with_content,
23
23
  :with_hostgroup,
24
24
  :with_parameter,
25
- content_view_environments: [make_cve(lifecycle_environment: env), make_cve(lifecycle_environment: env2)],
25
+ content_facet: FactoryBot.build(
26
+ :content_facet,
27
+ content_view_environments: [make_cve(lifecycle_environment: env), make_cve(lifecycle_environment: env2)]
28
+ ),
26
29
  organization: env.organization
27
30
  )
28
31
 
@@ -32,7 +32,7 @@ class UIRequestForwarderTest < ActiveSupport::TestCase
32
32
  ::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag)
33
33
  @forwarder.expects(:execute_cloud_request).with do |actual_params|
34
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])
35
+ assert_equal "U:\"#{@user.login}\"O:\"#{@organization.name}\"L:\"#{@location.name}\"", tag_value(actual.find { |param| param[0] == :tags && tag_name(param[1]) =~ /#{ForemanRhCloud::TagsAuth::TAG_NAME}/ }[1])
36
36
  true
37
37
  end
38
38
 
@@ -82,7 +82,7 @@ class UIRequestForwarderTest < ActiveSupport::TestCase
82
82
  ::ForemanRhCloud::TagsAuth.any_instance.expects(:update_tag)
83
83
  @forwarder.expects(:execute_cloud_request).with do |actual_params|
84
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])
85
+ assert_equal "U:\"#{@user.login}\"O:\"#{@organization.name}\"L:\"#{@location.name}\"", tag_value(actual.find { |param| param[0] == :tags && tag_name(param[1]) =~ /#{ForemanRhCloud::TagsAuth::TAG_NAME}/ }[1])
86
86
  assert_equal 5, actual.find { |param| param[0] == :page }[1]
87
87
  assert_equal 42, actual.find { |param| param[0] == :per_page }[1]
88
88
  true
@@ -160,6 +160,47 @@ class UIRequestForwarderTest < ActiveSupport::TestCase
160
160
  # This is done by setting the expectation before the actual call.
161
161
  end
162
162
 
163
+ test 'scope_request? should return tag_name for scoped requests' do
164
+ get_req = ActionDispatch::Request.new(
165
+ 'REQUEST_URI' => '/api/vulnerability/v1/vulnerabilities/cves',
166
+ 'REQUEST_METHOD' => 'GET',
167
+ 'rack.input' => ::Puma::NullIO.new
168
+ )
169
+
170
+ result = @forwarder.send(:scope_request?, get_req, 'api/vulnerability/v1/vulnerabilities/cves')
171
+ assert_equal :tags, result
172
+ end
173
+
174
+ test 'scope_request? should return nil for non-GET requests' do
175
+ post_req = ActionDispatch::Request.new(
176
+ 'REQUEST_URI' => '/api/vulnerability/v1/cves',
177
+ 'REQUEST_METHOD' => 'POST',
178
+ 'rack.input' => ::Puma::NullIO.new
179
+ )
180
+
181
+ result = @forwarder.send(:scope_request?, post_req, '/api/vulnerability/v1/cves')
182
+ assert_nil result
183
+ end
184
+
185
+ test 'scope_request? should return nil for unmatched paths' do
186
+ get_req = ActionDispatch::Request.new(
187
+ 'REQUEST_URI' => '/api/unmatched/path',
188
+ 'REQUEST_METHOD' => 'GET',
189
+ 'rack.input' => ::Puma::NullIO.new
190
+ )
191
+
192
+ result = @forwarder.send(:scope_request?, get_req, '/api/unmatched/path')
193
+ assert_nil result
194
+ end
195
+
196
+ test 'prepare_tags should use provided tag_name' do
197
+ result = @forwarder.send(:prepare_tags, @user, @organization, @location, :custom_tag)
198
+
199
+ assert_equal 1, result.length
200
+ assert_equal :custom_tag, result[0][0]
201
+ assert_equal "U:\"#{@user.login}\"O:\"#{@organization.name}\"L:\"#{@location.name}\"", tag_value(result[0][1])
202
+ end
203
+
163
204
  def tag_value(param_value)
164
205
  return param_value unless param_value.is_a?(String)
165
206
 
@@ -10,7 +10,7 @@ class TagsAuthTest < ActiveSupport::TestCase
10
10
  @auth = ::ForemanRhCloud::TagsAuth.new(@user, @org, @loc, @logger)
11
11
  end
12
12
 
13
- test 'Generates tags update request' do
13
+ test 'Generates tags update request when hosts are present' do
14
14
  uuid1 = 'test_uuid1'
15
15
  uuid2 = 'test_uuid2'
16
16
 
@@ -26,4 +26,18 @@ class TagsAuthTest < ActiveSupport::TestCase
26
26
 
27
27
  @auth.update_tag
28
28
  end
29
+
30
+ test 'Should not execute cloud request when no hosts are present' do
31
+ @auth.expects(:allowed_hosts).returns([])
32
+ @auth.expects(:execute_cloud_request).never
33
+
34
+ @auth.update_tag
35
+ end
36
+
37
+ test 'Should not execute cloud request when allowed_hosts is nil' do
38
+ @auth.expects(:allowed_hosts).returns(nil)
39
+ @auth.expects(:execute_cloud_request).never
40
+
41
+ @auth.update_tag
42
+ end
29
43
  end
@@ -998,6 +998,39 @@ class SliceGeneratorTest < ActiveSupport::TestCase
998
998
  assert_not_nil actual_host['insights_id']
999
999
  end
1000
1000
 
1001
+ test 'reports yum repos' do
1002
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
1003
+ FactoryBot.create(:katello_content, cp_content_id: '1', organization: @host.organization, name: 'Test Content', label: 'test-content')
1004
+ repo = FactoryBot.build(
1005
+ :katello_repository,
1006
+ :fedora_17_x86_64_dev,
1007
+ :with_content_view,
1008
+ product: FactoryBot.create(:katello_product, :redhat, :with_provider, organization: @host.organization)
1009
+ )
1010
+ # force-save the root repo to avoid validation errors
1011
+ repo.root.save(validate: false)
1012
+ repo.save(validate: false)
1013
+ @host.content_facet.bound_repositories << repo
1014
+ @host.content_facet.content_source = FactoryBot.create(:smart_proxy, :with_pulp3)
1015
+ @host.save(validate: false)
1016
+
1017
+ batch = Host.where(id: @host.id).in_batches.first
1018
+ generator = create_generator(batch)
1019
+ json_str = generator.render
1020
+ actual = JSON.parse(json_str.join("\n"))
1021
+
1022
+ assert_not_nil(actual_host = actual['hosts'].first)
1023
+ assert_not_nil(actual_system_profile = actual_host['system_profile'])
1024
+ assert_not_nil(actual_yum_repos = actual_system_profile['yum_repos'])
1025
+ assert_equal 1, actual_yum_repos.count
1026
+ assert_not_nil(actual_yum_repo = actual_yum_repos.first)
1027
+ assert_equal 'Test Content', actual_yum_repo['name']
1028
+ assert_equal 'test-content', actual_yum_repo['id']
1029
+ assert_match(/fedora_17/, actual_yum_repo['base_url'])
1030
+ assert_equal true, actual_yum_repo['enabled']
1031
+ assert_equal true, actual_yum_repo['gpgcheck']
1032
+ end
1033
+
1001
1034
  private
1002
1035
 
1003
1036
  def create_generator(batch, name = '00000000-0000-0000-0000-000000000000')
@@ -26,7 +26,10 @@ class TagsGeneratorTest < ActiveSupport::TestCase
26
26
  organization: env.organization,
27
27
  location: @location2,
28
28
  hostgroup: @hostgroup2,
29
- content_view_environments: [make_cve(lifecycle_environment: env), make_cve(lifecycle_environment: env2)]
29
+ content_facet: FactoryBot.build(
30
+ :content_facet,
31
+ content_view_environments: [make_cve(lifecycle_environment: env), make_cve(lifecycle_environment: env2)]
32
+ )
30
33
  )
31
34
 
32
35
  @host.organization.pools << FactoryBot.create(:katello_pool, account_number: '1234', cp_id: 1)
@@ -8,7 +8,7 @@ const CVEsHostDetailsTab = ({ systemId }) => {
8
8
  const scope = 'vulnerability';
9
9
  const module = './SystemDetailTable';
10
10
  return (
11
- <div className="rh-cloud-insights-vulnerability-host-details-component">
11
+ <div className="rh-cloud-insights-vulnerability-host-details-component vulnerability">
12
12
  <ScalprumComponent scope={scope} module={module} systemId={systemId} />
13
13
  </div>
14
14
  );
@@ -10,7 +10,7 @@ const CveDetailsPage = () => {
10
10
 
11
11
  return (
12
12
  <ScalprumProvider {...providerOptions}>
13
- <div className="rh-cloud-cve-details-page">
13
+ <div className="rh-cloud-cve-details-page vulnerability">
14
14
  <ScalprumComponent scope={scope} module={module} cveId={cveId} />
15
15
  </div>
16
16
  </ScalprumProvider>
@@ -18,9 +18,7 @@ jest.mock('@scalprum/react-core', () => ({
18
18
  describe('CveDetailsPage component', () => {
19
19
  it('renders the container with correct class', () => {
20
20
  const { container } = render(<CveDetailsPage />);
21
- expect(
22
- container.querySelector('.rh-cloud-cve-details-page')
23
- ).toBeTruthy();
21
+ expect(container.querySelector('.rh-cloud-cve-details-page')).toBeTruthy();
24
22
  });
25
23
 
26
24
  it('passes cveId from URL params to ScalprumComponent', () => {
@@ -46,7 +46,7 @@ const RecommendationsCell = hostDetails => {
46
46
  hostDetails?.insights_attributes ?? {}
47
47
  );
48
48
 
49
- return insightsAttributes.useLocalAdvisorEngine ? (
49
+ return insightsAttributes.useIopMode ? (
50
50
  <IopRecommendationsCell hostDetails={hostDetails} />
51
51
  ) : (
52
52
  <HostedRecommendationsCell hostDetails={hostDetails} />
@@ -8,6 +8,7 @@ import InsightsCloudSync from './InsightsCloudSync';
8
8
  import IopRecommendationDetails from './IopRecommendationDetails/IopRecommendationDetails';
9
9
  import InsightsHostDetailsTab from './InsightsHostDetailsTab';
10
10
  import CveDetailsPage from './CveDetailsPage';
11
+ import './common/styles.scss';
11
12
 
12
13
  const pages = [
13
14
  { name: 'ForemanInventoryUpload', type: ForemanInventoryUpload },
@@ -3,7 +3,15 @@ import React from 'react';
3
3
  import { orderBy } from 'lodash';
4
4
  import Resolutions from './Resolutions';
5
5
 
6
- export const modifyRows = (remediations, setResolutions, setHostsIds) => {
6
+ export const getResolutionId = (selectedResolution, id) =>
7
+ `${id}_${selectedResolution}`;
8
+
9
+ export const modifyRows = (
10
+ remediations,
11
+ setResolutions,
12
+ setHostsIds,
13
+ isIop
14
+ ) => {
7
15
  if (remediations.length === 0) return [];
8
16
 
9
17
  const resolutionToSubmit = [];
@@ -15,9 +23,22 @@ export const modifyRows = (remediations, setResolutions, setHostsIds) => {
15
23
  ).map(({ id, host_id, hostname, title, resolutions, reboot }) => {
16
24
  hostsIdsToSubmit.add(host_id);
17
25
  const selectedResolution = resolutions[0]?.id;
26
+ /* eslint-disable spellcheck/spell-checker */
27
+
28
+ // For IoP: {
29
+ // hit_id: "c7c6727e-2966-4f7c-87f1-20ef14db7a2d",
30
+ // rule_id: "hardening_ssh_client_alive|OPENSSH_HARDENING_CLIENT_ALIVE",
31
+ // resolution_type: "less_secure",
32
+ // resolution_id:"hardening_ssh_client_alive|OPENSSH_HARDENING_CLIENT_ALIVE_less_secure",
33
+ // }
34
+ // for Hosted, hit_id and rule_id will be Foreman database IDs
35
+
36
+ /* eslint-enable spellcheck/spell-checker */
18
37
  resolutionToSubmit.push({
19
- hit_id: id,
20
- resolution_id: selectedResolution /** defaults to the first resolution if many */,
38
+ hit_id: isIop ? host_id : id,
39
+ rule_id: id,
40
+ resolution_type: selectedResolution /** defaults to the first resolution if many */,
41
+ resolution_id: getResolutionId(selectedResolution, id),
21
42
  });
22
43
  return {
23
44
  cells: [
@@ -25,10 +46,11 @@ export const modifyRows = (remediations, setResolutions, setHostsIds) => {
25
46
  title,
26
47
  <div>
27
48
  <Resolutions
28
- hit_id={id}
49
+ hit_id={isIop ? host_id : id}
29
50
  resolutions={resolutions}
30
51
  setResolutions={setResolutions}
31
52
  selectedResolution={selectedResolution}
53
+ isIop={isIop}
32
54
  />
33
55
  </div>,
34
56
  reboot,