foreman_openscap 4.0.4 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/foreman_openscap/policy.css +5 -0
  3. data/app/controllers/api/v2/compliance/scap_contents_controller.rb +32 -1
  4. data/app/helpers/arf_reports_helper.rb +7 -10
  5. data/app/helpers/policies_helper.rb +4 -17
  6. data/app/models/concerns/foreman_openscap/host_extensions.rb +5 -0
  7. data/app/models/foreman_openscap/arf_report.rb +3 -7
  8. data/app/models/foreman_openscap/compliance_status.rb +4 -0
  9. data/app/models/foreman_openscap/policy.rb +11 -6
  10. data/app/views/api/v2/compliance/scap_contents/bulk_upload.json.rabl +7 -0
  11. data/app/views/arf_reports/show.html.erb +1 -1
  12. data/app/views/arf_reports/show_html.html.erb +1 -0
  13. data/app/views/compliance_hosts/show.html.erb +1 -8
  14. data/app/views/policies/edit.html.erb +3 -2
  15. data/app/views/policies/show.html.erb +3 -1
  16. data/app/views/scap_contents/edit.html.erb +2 -12
  17. data/app/views/tailoring_files/edit.html.erb +2 -10
  18. data/config/routes.rb +3 -0
  19. data/db/migrate/20201202110213_update_puppet_port_param_type.rb +28 -0
  20. data/db/seeds.d/75-job_templates.rb +3 -2
  21. data/lib/foreman_openscap/bulk_upload.rb +46 -20
  22. data/lib/foreman_openscap/engine.rb +14 -14
  23. data/lib/foreman_openscap/version.rb +1 -1
  24. data/lib/tasks/foreman_openscap_tasks.rake +15 -3
  25. data/test/factories/compliance_log_factory.rb +0 -6
  26. data/test/functional/api/v2/compliance/arf_reports_controller_test.rb +4 -4
  27. data/test/lib/foreman_openscap/bulk_upload_test.rb +48 -0
  28. data/test/test_plugin_helper.rb +3 -3
  29. data/test/unit/policy_test.rb +24 -0
  30. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4a4ecc74498e831daaf3b06da9a2ab475c1eac67f34ef698fe7aabc949e7fa3
4
- data.tar.gz: b917c3d1c392311306404f261541bbabbc63fcabdfb5ee277a25a794eb3cf0f2
3
+ metadata.gz: 69eab4d9434f1b502ba511db38d8a7faff9721c5416703f6010ccc87fdc52b86
4
+ data.tar.gz: 94ba4cbecc85106f968d9b5f137e0808dbd12711db01fd14e0f0c4e9761e27a1
5
5
  SHA512:
6
- metadata.gz: 2f50b5057eac300b2f23d006d2523d0a1241d1133ce108a2836f4833a1b491a8b365ba3bb9428b9a120b7c89bf1278274844eb8e02304d2dc8edc37952477629
7
- data.tar.gz: d7c772636e3a3406cf1df32cdb6521716800acc61b31825ed7a9c1d4819411ca4047aaf43c16c346eb715b83c7778b5b37daf6d41ad38a20b89435be4b5466c0
6
+ metadata.gz: 4e3253f876e3ab4efd5c853fdb05f0b81cbbe7184c5b00ea552690b0cce9664a76210c32f92fe86c631bc9eaa2ed81ba1a8762b8b47e0678149a946cf593554e
7
+ data.tar.gz: a6c3706f6fcc836af18f7aeda76c1cf735981836a0661cdcc66e4ead2272b6249519f305ff3b6766266ebb05eda1ebfe778811993286be3e162e269412aa6fd8
@@ -6,3 +6,8 @@
6
6
  display: none;
7
7
  }
8
8
 
9
+ span.scap_policy_popover {
10
+ float: left;
11
+ margin-top: 2px;
12
+ }
13
+
@@ -1,3 +1,5 @@
1
+ require 'foreman_openscap/bulk_upload'
2
+
1
3
  module Api::V2
2
4
  module Compliance
3
5
  class ScapContentsController < ::Api::V2::BaseController
@@ -5,7 +7,11 @@ module Api::V2
5
7
  include ForemanOpenscap::BodyLogExtensions
6
8
  include ForemanOpenscap::Api::V2::ScapApiControllerExtensions
7
9
 
8
- before_action :find_resource, :except => %w[index create]
10
+ def self.bulk_upload_types
11
+ ['files', 'directory', 'default']
12
+ end
13
+
14
+ before_action :find_resource, :except => %w[index create bulk_upload]
9
15
 
10
16
  api :GET, '/compliance/scap_contents', N_('List SCAP contents')
11
17
  param_group :search_and_pagination, ::Api::V2::BaseController
@@ -61,6 +67,29 @@ module Api::V2
61
67
  process_response @scap_content.destroy
62
68
  end
63
69
 
70
+ api :POST, '/compliance/scap_contents/bulk_upload', N_('Upload scap contents in bulk')
71
+ param :type, bulk_upload_types, :required => true, :desc => N_('Type of the upload')
72
+ param :files, Array, :desc => N_('File paths to upload when using "files" upload type')
73
+ param :directory, String, :desc => N_('Directory to upload when using "directory" upload type')
74
+
75
+ def bulk_upload
76
+ case params[:type]
77
+ when 'files'
78
+ @result = ForemanOpenscap::BulkUpload.new.upload_from_files(params[:files])
79
+ when 'directory'
80
+ @result = ForemanOpenscap::BulkUpload.new.upload_from_directory(params[:directory])
81
+ when 'default'
82
+ @result = ForemanOpenscap::BulkUpload.new.upload_from_scap_guide
83
+ else
84
+ return render :json => {
85
+ :errors => [
86
+ _("Please specify import type, received: %{received}, expected one of: %{expected}") %
87
+ { :expected => self.class.bulk_upload_types.join(', '), :received => params[:type] }
88
+ ]
89
+ }, :status => :unprocessable_entity
90
+ end
91
+ end
92
+
64
93
  private
65
94
 
66
95
  def find_resource
@@ -70,6 +99,8 @@ module Api::V2
70
99
 
71
100
  def action_permission
72
101
  case params[:action]
102
+ when 'bulk_upload'
103
+ :create
73
104
  when 'xml'
74
105
  :view
75
106
  else
@@ -14,16 +14,13 @@ module ArfReportsHelper
14
14
  end
15
15
 
16
16
  def arf_report_breadcrumbs
17
- if @arf_report && @arf_report.host
18
- breadcrumbs(:resource_url => api_compliance_arf_reports_path,
19
- :switchable => false,
20
- :items => [
21
- { :caption => _('Compliance Reports'),
22
- :url => url_for(arf_reports_path) },
23
- { :caption => @arf_report.host.name,
24
- :url => (arf_report_path(@arf_report) if authorized_for(hash_for_arf_report_path(@arf_report))) }
25
- ])
26
- end
17
+ breadcrumbs(:resource_url => api_compliance_arf_reports_path,
18
+ :switchable => false,
19
+ :items => [
20
+ { :caption => _('Compliance Reports'),
21
+ :url => url_for(arf_reports_path) },
22
+ { :caption => @arf_report.host.to_s }
23
+ ])
27
24
  end
28
25
 
29
26
  def result_tag(level)
@@ -11,10 +11,10 @@ module PoliciesHelper
11
11
 
12
12
  def deploy_by_radios(f, policy)
13
13
  ForemanOpenscap::ConfigNameService.new.configs.map do |tool|
14
- popover_block = popover("", config_inline_help(tool.inline_help))
14
+ popover_block = tag.span(popover("", config_inline_help(tool.inline_help)), class: 'scap_policy_popover')
15
15
 
16
- label = label_tag('', :class => 'col-md-2 control-label') do
17
- tool.type.to_s.capitalize.html_safe + ' ' + popover_block.html_safe
16
+ label = label_tag('', :class => 'col-md-2 control-label', :for => "policy_deploy_by_#{tool.type}") do
17
+ tool.type.to_s.capitalize.html_safe
18
18
  end
19
19
 
20
20
  radio = content_tag(:div, :class => "col-md-2") do
@@ -23,7 +23,7 @@ module PoliciesHelper
23
23
 
24
24
  content_tag(:div, :class => "clearfix") do
25
25
  content_tag(:div, :class => "form-group") do
26
- label.html_safe + radio.html_safe
26
+ label.html_safe + popover_block.html_safe + radio.html_safe
27
27
  end
28
28
  end
29
29
  end.join('').html_safe
@@ -136,17 +136,4 @@ module PoliciesHelper
136
136
  def translate_steps(policy)
137
137
  policy.steps.map { |step| _(step) }
138
138
  end
139
-
140
- def policy_breadcrumbs
141
- if @policy
142
- breadcrumbs(:resource_url => api_compliance_policies_path,
143
- :name_field => 'name',
144
- :items => [
145
- { :caption => _('Policies'),
146
- :url => url_for(policies_path) },
147
- { :caption => @policy.name,
148
- :url => (edit_policy_path(@policy) if authorized_for(hash_for_edit_policy_path(@policy))) }
149
- ])
150
- end
151
- end
152
139
  end
@@ -81,6 +81,11 @@ module ForemanOpenscap
81
81
  }
82
82
 
83
83
  base.send :extend, ClassMethods
84
+
85
+ base.apipie :class do
86
+ property :policies_enc, String, desc: 'Returns JSON string containing policies for the host'
87
+ property :policies_enc_raw, array_of: Hash, desc: 'Returns a list with key:value objects containing policies for the host'
88
+ end
84
89
  end
85
90
 
86
91
  def inherited_attributes
@@ -125,11 +125,9 @@ module ForemanOpenscap
125
125
  msg = Log.where(:source_id => src.id).order(:id => :desc).first.message
126
126
  update_msg_with_changes(msg, log)
127
127
  else
128
- digest = Digest::SHA1.hexdigest(log[:title])
129
- if (msg = Message.find_by(:digest => digest))
128
+ if (msg = Message.find_by(:value => log[:title]))
130
129
  msg.attributes = {
131
130
  :value => N_(log[:title]),
132
- :digest => digest,
133
131
  :severity => log[:severity],
134
132
  :description => newline_to_space(log[:description]),
135
133
  :rationale => newline_to_space(log[:rationale]),
@@ -137,7 +135,6 @@ module ForemanOpenscap
137
135
  }
138
136
  else
139
137
  msg = Message.new(:value => N_(log[:title]),
140
- :digest => digest,
141
138
  :severity => log[:severity],
142
139
  :description => newline_to_space(log[:description]),
143
140
  :rationale => newline_to_space(log[:rationale]),
@@ -159,8 +156,8 @@ module ForemanOpenscap
159
156
 
160
157
  def assign_locations_organizations
161
158
  if host
162
- self.location_ids = [host.location_id] if SETTINGS[:locations_enabled]
163
- self.organization_ids = [host.organization_id] if SETTINGS[:organizations_enabled]
159
+ self.location_ids = [host.location_id]
160
+ self.organization_ids = [host.organization_id]
164
161
  end
165
162
  end
166
163
 
@@ -233,7 +230,6 @@ module ForemanOpenscap
233
230
  msg.value = incoming_data['title']
234
231
 
235
232
  return unless msg.changed?
236
- msg.digest = Digest::SHA1.hexdigest(msg.value) if msg.value_changed?
237
233
  msg.save
238
234
  end
239
235
  end
@@ -8,6 +8,10 @@ module ForemanOpenscap
8
8
  N_('Compliance')
9
9
  end
10
10
 
11
+ def status_link
12
+ host.arf_reports_path(:search => "host = #{host.name}")
13
+ end
14
+
11
15
  def self.bit_mask(status)
12
16
  "#{ArfReport::BIT_NUM * ArfReport::METRIC.index(status)} & #{ArfReport::MAX}"
13
17
  end
@@ -6,6 +6,8 @@ module ForemanOpenscap
6
6
  include Taxonomix
7
7
  attr_writer :current_step, :wizard_initiated
8
8
 
9
+ STEPS_LIST = [N_('Deployment Options'), N_('Policy Attributes'), N_('SCAP Content'), N_('Schedule'), N_('Locations'), N_('Organizations'), N_('Hostgroups')]
10
+
9
11
  belongs_to :scap_content
10
12
  belongs_to :scap_content_profile
11
13
  belongs_to :tailoring_file
@@ -108,10 +110,7 @@ module ForemanOpenscap
108
110
  end
109
111
 
110
112
  def steps
111
- base_steps = [N_('Deployment Options'), N_('Policy Attributes'), N_('SCAP Content'), N_('Schedule')]
112
- base_steps << N_('Locations') if SETTINGS[:locations_enabled]
113
- base_steps << N_('Organizations') if SETTINGS[:organizations_enabled]
114
- base_steps << N_('Hostgroups') # always be last.
113
+ STEPS_LIST
115
114
  end
116
115
 
117
116
  def current_step
@@ -174,8 +173,14 @@ module ForemanOpenscap
174
173
  end
175
174
 
176
175
  def unassign_hosts(hosts)
177
- host_asset_ids = ForemanOpenscap::Asset.where(:assetable_type => 'Host::Base', :assetable_id => hosts.map(&:id)).pluck(:id)
178
- self.asset_ids = self.asset_ids - host_asset_ids
176
+ policy_host_assets = ForemanOpenscap::Asset.joins(:asset_policies).where(
177
+ :assetable_type => 'Host::Base',
178
+ :assetable_id => hosts.map(&:id),
179
+ :foreman_openscap_asset_policies => { :policy_id => id }
180
+ ).pluck(:id)
181
+
182
+ self.asset_ids = self.asset_ids - policy_host_assets
183
+ ForemanOpenscap::Asset.where(:id => policy_host_assets).destroy_all
179
184
  end
180
185
 
181
186
  def to_enc
@@ -0,0 +1,7 @@
1
+ object @result
2
+
3
+ attributes :errors
4
+
5
+ child :results => :results do
6
+ extends 'api/v2/compliance/scap_contents/index'
7
+ end
@@ -2,7 +2,7 @@
2
2
  <% javascript 'foreman_openscap/reports' %>
3
3
  <% stylesheet 'foreman_openscap/reports' %>
4
4
 
5
- <% title "#{@arf_report.host}" %>
5
+ <% title @arf_report.host.to_s %>
6
6
  <%= arf_report_breadcrumbs %>
7
7
 
8
8
  <p class='ra'><%= reported_info @arf_report %></p>
@@ -1,5 +1,6 @@
1
1
  <%= javascript 'foreman_openscap/load_report'%>
2
2
 
3
+ <% title @arf_report.host.to_s %>
3
4
  <%= arf_report_breadcrumbs %>
4
5
 
5
6
  <div class="row">
@@ -3,14 +3,7 @@
3
3
 
4
4
  <%= breadcrumbs(:resource_url => api_hosts_path,
5
5
  :resource_filter => "is_compliance_host = true",
6
- :name_field => 'name',
7
- :switchable => true,
8
- :items => [
9
- { :caption => _('Compliance Hosts'),
10
- :url => url_for(hosts_path(:search => "is_compliance_host = true")) },
11
- { :caption => ((N_("%s compliance reports by policy") % @host.to_label)),
12
- :url => (host_path(@host) if authorized_for(hash_for_host_path(@host))) }
13
- ])
6
+ :name_field => 'name')
14
7
  %>
15
8
  <% title n_("%s compliance report by policy", "%s compliance reports by policy" , @host.combined_policies.length) % @host.to_label %>
16
9
  <% @host.combined_policies.each do |policy| %>
@@ -1,4 +1,5 @@
1
- <% title _("Edit Compliance Policy") %>
2
- <%= policy_breadcrumbs %>
1
+ <% title _("Edit %s") % @policy.name %>
2
+ <%= breadcrumbs(:resource_url => api_compliance_policies_path,
3
+ :name_field => 'name') %>
3
4
 
4
5
  <%= render :partial => "form" %>
@@ -1,4 +1,6 @@
1
- <%= policy_breadcrumbs %>
1
+ <% title _("Details for Compliance Policy %s") % @policy.name %>
2
+ <%= breadcrumbs(:resource_url => api_compliance_policies_path,
3
+ :name_field => 'name') %>
2
4
 
3
5
  <div class="row">
4
6
  <iframe style="min-height: 800px" height="100%" width="100%" frameborder="0" src="<%= parse_policy_path(@policy) %>"></iframe>
@@ -1,15 +1,5 @@
1
- <% title _("Edit SCAP Content") %>
1
+ <% title _("Edit %s") % @scap_content.title %>
2
2
  <%= breadcrumbs(:resource_url => api_compliance_scap_contents_path,
3
- :name_field => 'title',
4
- :items => [
5
- { :caption => _('Scap Contents'),
6
- :url => url_for(scap_contents_path)
7
- },
8
- { :caption => @scap_content.title,
9
- :url => (edit_scap_content_path(@scap_content) if authorized_for(hash_for_edit_scap_content_path(@scap_content)))
10
- }
11
- ]
12
- ) if @scap_content %>
13
-
3
+ :name_field => 'title') %>
14
4
 
15
5
  <%= render :partial => 'form' %>
@@ -1,13 +1,5 @@
1
- <% title _("Edit Tailoring File") %>
1
+ <% title _("Edit %s") % @tailoring_file.name %>
2
2
  <%= breadcrumbs(:resource_url => api_compliance_tailoring_files_path,
3
- :items => [
4
- { :caption => _('Tailoring Files'),
5
- :url => url_for(tailoring_files_path)
6
- },
7
- { :caption => @tailoring_file.name,
8
- :url => (edit_tailoring_file_path(@tailoring_file) if authorized_for(hash_for_edit_tailoring_file_path(@tailoring_file)))
9
- }
10
- ]
11
- ) if @tailoring_file %>
3
+ :name_field => 'name') %>
12
4
 
13
5
  <%= render :partial => 'form' %>
data/config/routes.rb CHANGED
@@ -64,6 +64,9 @@ Rails.application.routes.draw do
64
64
  member do
65
65
  get 'xml'
66
66
  end
67
+ collection do
68
+ post 'bulk_upload'
69
+ end
67
70
  end
68
71
  resources :scap_content_profiles, :only => %i[index]
69
72
 
@@ -0,0 +1,28 @@
1
+ class UpdatePuppetPortParamType < ActiveRecord::Migration[6.0]
2
+ def up
3
+ update_port_type :to_i
4
+ end
5
+
6
+ def down
7
+ update_port_type :to_s
8
+ end
9
+
10
+ private
11
+
12
+ def update_port_type(method)
13
+ puppet_class = Puppetclass.find_by :name => 'foreman_scap_client'
14
+ return unless puppet_class
15
+ port_key = puppet_class.class_params.find_by :key => 'port'
16
+ return unless port_key
17
+ def_value = port_key.default_value
18
+
19
+ if method == :to_i
20
+ port_key.key_type = "integer"
21
+ port_key.default_value = def_value.to_i
22
+ else
23
+ port_key.key_type == "string"
24
+ port_key.default_value = port_key.default_value.to_s
25
+ end
26
+ port_key.save!
27
+ end
28
+ end
@@ -11,8 +11,9 @@ if ForemanOpenscap.with_remote_execution?
11
11
  else
12
12
  template = JobTemplate.import!(File.read(template), :default => true, :lock => true, :update => sync)
13
13
  end
14
- template.organizations = organizations if SETTINGS[:organizations_enabled] && template.present?
15
- template.locations = locations if SETTINGS[:locations_enabled] && template.present?
14
+ next unless template.present?
15
+ template.organizations = organizations
16
+ template.locations = locations
16
17
  end
17
18
  end
18
19
  end
@@ -1,48 +1,74 @@
1
1
  require 'digest/sha2'
2
+ require 'ostruct'
3
+
2
4
  module ForemanOpenscap
3
5
  class BulkUpload
4
- attr_accessor :from_scap_security_guide
5
- def initialize(from_scap_security_guide = false)
6
- @from_scap_security_guide = from_scap_security_guide
6
+ def initialize
7
+ @result = OpenStruct.new(:errors => [], :results => [])
8
+ end
9
+
10
+ def files_from_guide
11
+ `rpm -ql scap-security-guide | grep ds.xml`.split
7
12
  end
8
13
 
9
- def generate_scap_default_content
10
- return unless @from_scap_security_guide
14
+ def scap_guide_installed?
15
+ `rpm -qa | grep scap-security-guide`.present?
16
+ end
11
17
 
12
- if `rpm -qa | grep scap-security-guide`.empty?
13
- Rails.logger.debug "Can't find scap-security-guide RPM"
14
- return
18
+ def upload_from_scap_guide
19
+ unless scap_guide_installed?
20
+ @result.errors.push("Can't find scap-security-guide RPM, are you sure it is installed on your server?")
21
+ return @result
15
22
  end
16
23
 
17
- files_array = `rpm -ql scap-security-guide | grep ds.xml`.split
18
- upload_from_files(files_array) unless files_array.empty?
24
+ upload_from_files(files_from_guide, true)
19
25
  end
20
26
 
21
- def upload_from_files(files_array)
27
+ def upload_from_files(files_array, from_scap_guide = false)
28
+ unless files_array.is_a? Array
29
+ @result.errors.push("Expected an array of files to upload, got: #{files_array}.")
30
+ return @result
31
+ end
32
+
22
33
  files_array.each do |datastream|
34
+ if File.directory?(datastream)
35
+ @result.errors.push("#{datastream} is a directory, expecting file.")
36
+ next
37
+ end
38
+
39
+ unless File.file?(datastream)
40
+ @result.errors.push("#{datastream} does not exist, skipping.")
41
+ next
42
+ end
43
+
23
44
  file = File.open(datastream, 'rb').read
24
45
  digest = Digest::SHA2.hexdigest(datastream)
25
- title = content_name(datastream)
46
+ title = content_name(datastream, from_scap_guide)
26
47
  filename = original_filename(datastream)
27
48
  scap_content = ScapContent.where(:title => title, :digest => digest).first_or_initialize
28
49
  next if scap_content.persisted?
29
50
  scap_content.scap_file = file
30
51
  scap_content.original_filename = filename
31
- scap_content.location_ids = Location.all.map(&:id) if SETTINGS[:locations_enabled]
32
- scap_content.organization_ids = Organization.all.map(&:id) if SETTINGS[:organizations_enabled]
52
+ scap_content.location_ids = Location.all.pluck(:id)
53
+ scap_content.organization_ids = Organization.all.pluck(:id)
33
54
 
34
- next puts "## SCAP content is invalid: #{scap_content.errors.full_messages.uniq.join(',')} ##" unless scap_content.valid?
35
55
  if scap_content.save
36
- puts "Saved #{datastream} as #{scap_content.title}"
56
+ @result.results.push(scap_content)
37
57
  else
38
- puts "Failed saving #{datastream}"
58
+ @result.errors.push("Failed saving #{datastream}: #{scap_content.errors.full_messages.uniq.join(',')}")
39
59
  end
40
60
  end
61
+ @result
41
62
  end
42
63
 
43
64
  def upload_from_directory(directory_path)
65
+ unless directory_path && Dir.exist?(directory_path)
66
+ @result[:errors].push("No such directory: #{directory_path}. Please check the path you have provided.")
67
+ return @result
68
+ end
69
+
44
70
  files_array = Dir["#{directory_path}/*-ds.xml"]
45
- upload_from_files(files_array) unless files_array.empty?
71
+ upload_from_files(files_array)
46
72
  end
47
73
 
48
74
  private
@@ -57,9 +83,9 @@ module ForemanOpenscap
57
83
  file.split('/').last
58
84
  end
59
85
 
60
- def content_name(datastream)
86
+ def content_name(datastream, from_scap_guide)
61
87
  os_name = extract_name_from_file(datastream)
62
- @from_scap_security_guide ? "Red Hat #{os_name} default content" : "#{os_name} content"
88
+ from_scap_guide ? "Red Hat #{os_name} default content" : "#{os_name} content"
63
89
  end
64
90
  end
65
91
  end
@@ -92,7 +92,7 @@ module ForemanOpenscap
92
92
  'api/v2/compliance/scap_contents' => [:update] },
93
93
  :resource_type => 'ForemanOpenscap::ScapContent'
94
94
  permission :create_scap_contents, { :scap_contents => %i[new create],
95
- 'api/v2/compliance/scap_contents' => [:create] },
95
+ 'api/v2/compliance/scap_contents' => %i[create bulk_upload] },
96
96
  :resource_type => 'ForemanOpenscap::ScapContent'
97
97
  permission :destroy_scap_contents, { :scap_contents => [:destroy],
98
98
  'api/v2/compliance/scap_contents' => [:destroy] },
@@ -180,19 +180,6 @@ module ForemanOpenscap
180
180
  :description => proxy_description,
181
181
  :api_description => N_('ID of OpenSCAP Proxy')
182
182
 
183
- if ForemanOpenscap.with_remote_execution?
184
- options = {
185
- :description => N_("Run OpenSCAP scan"),
186
- :provided_inputs => "policies"
187
- }
188
-
189
- if Gem::Version.new(ForemanRemoteExecution::VERSION) >= Gem::Version.new('1.2.3')
190
- options[:host_action_button] = true
191
- end
192
-
193
- RemoteExecutionFeature.register(:foreman_openscap_run_scans, N_("Run OpenSCAP scan"), options)
194
- end
195
-
196
183
  add_controller_action_scope('Api::V2::HostsController', :index) do |base_scope|
197
184
  base_scope.preload(:policies)
198
185
  end
@@ -231,6 +218,19 @@ module ForemanOpenscap
231
218
  Log.send(:include, ForemanOpenscap::LogExtensions)
232
219
  BookmarkControllerValidator.send(:prepend, ForemanOpenscap::BookmarkControllerValidatorExtensions)
233
220
  ProxyStatus.status_registry.add(ProxyStatus::OpenscapSpool)
221
+
222
+ if ForemanOpenscap.with_remote_execution?
223
+ options = {
224
+ :description => N_("Run OpenSCAP scan"),
225
+ :provided_inputs => "policies"
226
+ }
227
+
228
+ if Gem::Version.new(ForemanRemoteExecution::VERSION) >= Gem::Version.new('1.2.3')
229
+ options[:host_action_button] = true
230
+ end
231
+
232
+ RemoteExecutionFeature.register(:foreman_openscap_run_scans, N_("Run OpenSCAP scan"), options)
233
+ end
234
234
  end
235
235
 
236
236
  rake_tasks do
@@ -1,3 +1,3 @@
1
1
  module ForemanOpenscap
2
- VERSION = "4.0.4".freeze
2
+ VERSION = "4.2.0".freeze
3
3
  end
@@ -6,23 +6,26 @@ namespace :foreman_openscap do
6
6
  namespace :bulk_upload do
7
7
  desc 'Bulk upload SCAP content from directory'
8
8
  task :directory, [:directory] => [:environment] do |task, args|
9
+ deprecate_upload_from_rake
9
10
  abort("# No such directory, please check the path you have provided. #") unless args[:directory].blank? || Dir.exist?(args[:directory])
10
11
  User.current = User.anonymous_admin
11
- ForemanOpenscap::BulkUpload.new.upload_from_directory(args[:directory])
12
+ print_upload_result ForemanOpenscap::BulkUpload.new.upload_from_directory(args[:directory])
12
13
  end
13
14
 
14
15
  task :files, [:files] => [:environment] do |task, args|
16
+ deprecate_upload_from_rake
15
17
  files_array = args[:files].split(' ')
16
18
  files_array.each do |file|
17
19
  abort("# #{file} is a directory, expecting file. Try using 'rake foreman_openscap:bulk_upload:directory' with this directory. #") if File.directory?(file)
18
20
  end
19
21
  User.current = User.anonymous_admin
20
- ForemanOpenscap::BulkUpload.new.upload_from_files(files_array)
22
+ print_upload_result ForemanOpenscap::BulkUpload.new.upload_from_files(files_array)
21
23
  end
22
24
 
23
25
  task :default => [:environment] do
26
+ deprecate_upload_from_rake
24
27
  User.current = User.anonymous_admin
25
- ForemanOpenscap::BulkUpload.new(true).generate_scap_default_content
28
+ print_upload_result ForemanOpenscap::BulkUpload.new.upload_from_scap_guide
26
29
  end
27
30
  end
28
31
 
@@ -67,6 +70,15 @@ namespace :foreman_openscap do
67
70
  end
68
71
  end
69
72
 
73
+ def deprecate_upload_from_rake
74
+ puts 'DEPRECATION WARNING: Uploading scap contents using rake task is deprecated and will be removed in a future version. Please use API or CLI.'
75
+ end
76
+
77
+ def print_upload_result(result)
78
+ puts result.errors.join(' ') if result.errors.present?
79
+ puts result.results.map { |sc| "Saved #{sc.original_filename} as #{sc.title}" }.join("\n") if result.results.present?
80
+ end
81
+
70
82
  # Tests
71
83
  namespace :test do
72
84
  desc "Test ForemanOpenscap"
@@ -9,15 +9,9 @@ FactoryBot.define do
9
9
 
10
10
  factory :compliance_message, :class => :message do
11
11
  sequence(:value) { |n| "message#{n}" }
12
- after(:build) do |msg|
13
- msg.digest = Digest::SHA1.hexdigest(msg.value)
14
- end
15
12
  end
16
13
 
17
14
  factory :compliance_source, :class => :source do
18
15
  sequence(:value) { |n| "source#{n}" }
19
- after(:build) do |source|
20
- source.digest = Digest::SHA1.hexdigest(source.value)
21
- end
22
16
  end
23
17
  end
@@ -139,7 +139,7 @@ class Api::V2::Compliance::ArfReportsControllerTest < ActionController::TestCase
139
139
  :date => dates[1].to_i,
140
140
  :openscap_proxy_name => @proxy.name),
141
141
  :session => set_session_user
142
- assert_equal Message.where(:digest => ForemanOpenscap::ArfReport.unscoped.last.logs.first.message.digest).count, 1
142
+ assert_equal Message.where(:value => ForemanOpenscap::ArfReport.unscoped.last.logs.first.message.value).count, 1
143
143
  end
144
144
 
145
145
  test "should recognize changes in messages" do
@@ -187,12 +187,12 @@ class Api::V2::Compliance::ArfReportsControllerTest < ActionController::TestCase
187
187
 
188
188
  reports = ForemanOpenscap::ArfReport.unscoped.all
189
189
  assert_equal reports.count, 2
190
-
191
- new_msgs = Message.where(:value => "Disable Firefox Configuration File ROT-13 Encoding Changed For Test")
190
+ msg_value = "Disable Firefox Configuration File ROT-13 Encoding Changed For Test"
191
+ new_msgs = Message.where(:value => msg_value)
192
192
  old_msgs = Message.where(:value => "Disable Firefox Configuration File ROT-13 Encoding")
193
193
  assert_equal new_msgs.count, 1
194
194
  assert_equal old_msgs.count, 0
195
- assert_equal new_msgs.first.digest, Digest::SHA1.hexdigest("Disable Firefox Configuration File ROT-13 Encoding Changed For Test")
195
+ assert_equal new_msgs.first.value, msg_value
196
196
  end
197
197
 
198
198
  test "should find reports by policy name" do
@@ -3,6 +3,7 @@ require 'test_plugin_helper'
3
3
  class BulkUploadTest < ActiveSupport::TestCase
4
4
  setup do
5
5
  require 'foreman_openscap/bulk_upload'
6
+ ForemanOpenscap::ScapContent.all.map(&:destroy)
6
7
  end
7
8
 
8
9
  test 'upload_from_files should create only one scap content' do
@@ -13,4 +14,51 @@ class BulkUploadTest < ActiveSupport::TestCase
13
14
  end
14
15
  end
15
16
  end
17
+
18
+ test 'upload_from_files should not crash when scap files are not array' do
19
+ scap_files = '/tmp/foo'
20
+ res = ForemanOpenscap::BulkUpload.new.upload_from_files(scap_files)
21
+ assert_equal "Expected an array of files to upload, got: #{scap_files}.", res.errors.first
22
+ end
23
+
24
+ test 'upload_from_files should skip directories' do
25
+ dir = "#{ForemanOpenscap::Engine.root}/test/files/scap_contents"
26
+ res = ForemanOpenscap::BulkUpload.new.upload_from_files([dir])
27
+ assert_equal "#{dir} is a directory, expecting file.", res.errors.first
28
+ end
29
+
30
+ test 'upload_from_files should skip files that does not exist' do
31
+ file = "#{ForemanOpenscap::Engine.root}/test/files/scap_contents/foo-ds.xml"
32
+ res = ForemanOpenscap::BulkUpload.new.upload_from_files([file])
33
+ assert_equal "#{file} does not exist, skipping.", res.errors.first
34
+ end
35
+
36
+ test 'upload_from_directory should check if directory exists' do
37
+ dir = "#{ForemanOpenscap::Engine.root}/test/files/scap_contents/foo"
38
+ res = ForemanOpenscap::BulkUpload.new.upload_from_directory(dir)
39
+ assert_equal "No such directory: #{dir}. Please check the path you have provided.", res.errors.first
40
+ end
41
+
42
+ test 'upload_from_directory should upload from directory' do
43
+ dir = "#{ForemanOpenscap::Engine.root}/test/files/scap_contents"
44
+ assert_difference('ForemanOpenscap::ScapContent.count', 1) do
45
+ ForemanOpenscap::BulkUpload.new.upload_from_directory(dir)
46
+ end
47
+ end
48
+
49
+ test 'should handle case when scap security guide is not installed' do
50
+ upload = ForemanOpenscap::BulkUpload.new
51
+ upload.stubs(:scap_guide_installed?).returns(false)
52
+ res = upload.upload_from_scap_guide
53
+ assert_equal "Can't find scap-security-guide RPM, are you sure it is installed on your server?", res.errors.first
54
+ end
55
+
56
+ test 'should upload files from guide' do
57
+ upload = ForemanOpenscap::BulkUpload.new
58
+ upload.stubs(:scap_guide_installed?).returns(true)
59
+ upload.stubs(:files_from_guide).returns(["#{ForemanOpenscap::Engine.root}/test/files/scap_contents/ssg-fedora-ds.xml"])
60
+ assert_difference('ForemanOpenscap::ScapContent.count', 1) do
61
+ upload.upload_from_scap_guide
62
+ end
63
+ end
16
64
  end
@@ -11,9 +11,9 @@ module ScapClientPuppetclass
11
11
  Puppetclass.find_by(:name => puppet_config.puppetclass_name)&.destroy
12
12
 
13
13
  puppet_class = FactoryBot.create(:puppetclass, :name => puppet_config.puppetclass_name)
14
- server_param = FactoryBot.create(:puppetclass_lookup_key, :key => puppet_config.server_param, :puppetclass_id => puppet_class.id)
15
- port_param = FactoryBot.create(:puppetclass_lookup_key, :key => puppet_config.port_param, :puppetclass_id => puppet_class.id)
16
- policies_param = FactoryBot.create(:puppetclass_lookup_key, :key => puppet_config.policies_param, :puppetclass_id => puppet_class.id)
14
+ server_param = FactoryBot.create(:puppetclass_lookup_key, :key => puppet_config.server_param, :default_value => nil)
15
+ port_param = FactoryBot.create(:puppetclass_lookup_key, :key => puppet_config.port_param, :default_value => nil)
16
+ policies_param = FactoryBot.create(:puppetclass_lookup_key, :key => puppet_config.policies_param, :default_value => nil)
17
17
 
18
18
  env = FactoryBot.create :environment
19
19
 
@@ -46,6 +46,30 @@ class PolicyTest < ActiveSupport::TestCase
46
46
  assert_equal 1, policy.hosts.count
47
47
  end
48
48
 
49
+ test "should delete assets when unassigning hosts" do
50
+ host1 = FactoryBot.create(:compliance_host)
51
+ host2 = FactoryBot.create(:compliance_host)
52
+ asset1 = FactoryBot.create(:asset, :assetable_id => host1.id, :assetable_type => 'Host::Base')
53
+ asset2 = FactoryBot.create(:asset, :assetable_id => host2.id, :assetable_type => 'Host::Base')
54
+ policy = FactoryBot.create(:policy, :assets => [asset1, asset2], :scap_content => @scap_content, :scap_content_profile => @scap_profile)
55
+ policy.unassign_hosts([host1, host2])
56
+
57
+ assert_nil ForemanOpenscap::Asset.find_by(:id => asset1.id)
58
+ assert_nil ForemanOpenscap::Asset.find_by(:id => asset2.id)
59
+ end
60
+
61
+ test "should delete assets only for selected policy when unassigning host" do
62
+ host1 = FactoryBot.create(:compliance_host)
63
+ asset1 = FactoryBot.create(:asset, :assetable_id => host1.id, :assetable_type => 'Host::Base')
64
+ asset2 = FactoryBot.create(:asset, :assetable_id => host1.id, :assetable_type => 'Host::Base')
65
+ policy1 = FactoryBot.create(:policy, :assets => [asset1], :scap_content => @scap_content, :scap_content_profile => @scap_profile)
66
+ policy2 = FactoryBot.create(:policy, :assets => [asset2], :scap_content => @scap_content, :scap_content_profile => @scap_profile)
67
+ policy1.unassign_hosts([host1])
68
+
69
+ assert_nil ForemanOpenscap::Asset.find_by(:id => asset1.id)
70
+ assert_not_nil ForemanOpenscap::Asset.find_by(:id => asset2.id)
71
+ end
72
+
49
73
  test "should remove associated hostgroup" do
50
74
  hg = FactoryBot.create(:hostgroup)
51
75
  asset = FactoryBot.create(:asset, :assetable_id => hg.id, :assetable_type => 'Hostgroup')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_openscap
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.4
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - slukasik@redhat.com
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-02 00:00:00.000000000 Z
11
+ date: 2021-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -130,6 +130,7 @@ files:
130
130
  - app/views/api/v2/compliance/scap_content_profiles/index.json.rabl
131
131
  - app/views/api/v2/compliance/scap_content_profiles/main.json.rabl
132
132
  - app/views/api/v2/compliance/scap_contents/base.json.rabl
133
+ - app/views/api/v2/compliance/scap_contents/bulk_upload.json.rabl
133
134
  - app/views/api/v2/compliance/scap_contents/create.json.rabl
134
135
  - app/views/api/v2/compliance/scap_contents/index.json.rabl
135
136
  - app/views/api/v2/compliance/scap_contents/main.json.rabl
@@ -245,6 +246,7 @@ files:
245
246
  - db/migrate/20190103093409_add_deployment_option_to_policy.foreman_openscap.rb
246
247
  - db/migrate/20200117135424_migrate_port_overrides_to_int.rb
247
248
  - db/migrate/20200803065041_migrate_port_overrides_for_ansible.rb
249
+ - db/migrate/20201202110213_update_puppet_port_param_type.rb
248
250
  - db/seeds.d/75-job_templates.rb
249
251
  - db/seeds.d/openscap_feature.rb
250
252
  - db/seeds.d/openscap_policy_notification.rb
@@ -357,10 +359,10 @@ test_files:
357
359
  - test/factories/arf_report_factory.rb
358
360
  - test/factories/asset_factory.rb
359
361
  - test/factories/compliance_host_factory.rb
360
- - test/factories/compliance_log_factory.rb
361
362
  - test/factories/policy_arf_report_factory.rb
362
363
  - test/factories/policy_factory.rb
363
364
  - test/factories/scap_content_related.rb
365
+ - test/factories/compliance_log_factory.rb
364
366
  - test/files/arf_report/arf_report.bz2
365
367
  - test/files/arf_report/arf_report.html
366
368
  - test/files/arf_report/arf_report.json
@@ -369,11 +371,11 @@ test_files:
369
371
  - test/files/scap_contents/ssg-fedora-ds.xml
370
372
  - test/files/tailoring_files/ssg-firefox-ds-tailoring-2.xml
371
373
  - test/files/tailoring_files/ssg-firefox-ds-tailoring.xml
372
- - test/functional/api/v2/compliance/arf_reports_controller_test.rb
373
374
  - test/functional/api/v2/compliance/policies_controller_test.rb
374
375
  - test/functional/api/v2/compliance/scap_content_profiles_controller_test.rb
375
376
  - test/functional/api/v2/compliance/scap_contents_controller_test.rb
376
377
  - test/functional/api/v2/compliance/tailoring_files_controller_test.rb
378
+ - test/functional/api/v2/compliance/arf_reports_controller_test.rb
377
379
  - test/functional/api/v2/hosts_controller_test.rb
378
380
  - test/functional/arf_reports_controller_test.rb
379
381
  - test/functional/openscap_proxies_controller_test.rb