foreman_openscap 0.11.5 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/compliance/arf_reports_controller.rb +3 -6
  3. data/app/controllers/api/v2/compliance/policies_controller.rb +3 -1
  4. data/app/controllers/concerns/foreman/controller/parameters/policy_api.rb +1 -1
  5. data/app/controllers/policies_controller.rb +2 -1
  6. data/app/helpers/foreman_openscap_helper.rb +14 -0
  7. data/app/helpers/policies_helper.rb +36 -0
  8. data/app/models/concerns/foreman_openscap/host_extensions.rb +5 -1
  9. data/app/models/concerns/foreman_openscap/openscap_proxy_core_extensions.rb +15 -19
  10. data/app/models/foreman_openscap/policy.rb +14 -80
  11. data/app/services/foreman_openscap/client_config/ansible.rb +38 -0
  12. data/app/services/foreman_openscap/client_config/base.rb +41 -0
  13. data/app/services/foreman_openscap/client_config/manual.rb +27 -0
  14. data/app/services/foreman_openscap/client_config/puppet.rb +38 -0
  15. data/app/services/foreman_openscap/config_name_service.rb +29 -0
  16. data/app/services/foreman_openscap/hostgroup_overrider.rb +71 -0
  17. data/app/services/foreman_openscap/lookup_key_overrider.rb +94 -0
  18. data/app/views/policies/_form.html.erb +6 -2
  19. data/app/views/policies/steps/_deployment_options_form.html.erb +11 -0
  20. data/app/views/policies/steps/{_create_policy_form.html.erb → _policy_attributes_form.html.erb} +0 -0
  21. data/db/migrate/20190103093409_add_deployment_option_to_policy.foreman_openscap.rb +15 -0
  22. data/lib/foreman_openscap/engine.rb +3 -3
  23. data/lib/foreman_openscap/version.rb +1 -1
  24. data/locale/de/foreman_openscap.edit.po +302 -106
  25. data/locale/en_GB/foreman_openscap.edit.po +302 -106
  26. data/locale/es/foreman_openscap.edit.po +302 -106
  27. data/locale/fr/foreman_openscap.edit.po +302 -106
  28. data/locale/gl/foreman_openscap.edit.po +302 -106
  29. data/locale/it/foreman_openscap.edit.po +302 -106
  30. data/locale/ja/foreman_openscap.edit.po +302 -106
  31. data/locale/ko/foreman_openscap.edit.po +302 -106
  32. data/locale/pt_BR/foreman_openscap.edit.po +302 -106
  33. data/locale/ru/foreman_openscap.edit.po +302 -106
  34. data/locale/sv_SE/foreman_openscap.edit.po +302 -106
  35. data/locale/zh_CN/foreman_openscap.edit.po +302 -106
  36. data/locale/zh_TW/foreman_openscap.edit.po +302 -106
  37. data/test/factories/policy_factory.rb +1 -0
  38. data/test/functional/api/v2/compliance/arf_reports_controller_test.rb +2 -3
  39. data/test/functional/api/v2/compliance/policies_controller_test.rb +2 -2
  40. data/test/test_plugin_helper.rb +26 -7
  41. data/test/unit/openscap_host_test.rb +0 -2
  42. data/test/unit/policy_test.rb +32 -23
  43. data/test/unit/services/config_name_service_test.rb +39 -0
  44. data/test/unit/services/hostgroup_overrider_test.rb +78 -0
  45. data/test/unit/services/lookup_key_overrider_test.rb +52 -0
  46. metadata +19 -5
  47. data/test/unit/puppet_overrides_test.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 476be55fdeeda480329624fd4ca562c93e33c370
4
- data.tar.gz: 7d58930838e01c45d99fcd9b11444696c336eaa0
3
+ metadata.gz: 32dd2a50a02e9810d04dbb252858b165e734c999
4
+ data.tar.gz: 40bd3d5ca9a1f27d8904fb07298772d624ac8728
5
5
  SHA512:
6
- metadata.gz: d2bac463d3ffd03167b30a84d38194d6a5a12e8d331c09a0cbe4dabbd2ad2c785652b4bfe2ed873bd1af80ed24aeb73bd36459e0db2ecc067af975a6777d013f
7
- data.tar.gz: 4cc7c132c045f5baf2a30e92cbc9bc55f39e4ae4eea23c044f87c981057e38a82b55c4a52e6ad08d3dc406e79c425115636110877d945d7e6fb4c20897b7d5be
6
+ metadata.gz: 51df4d59920bcc1e1467837d08ec086c4a9f3d304d39836f38b57654b5b5dbdb1f298feb426454e39623eefe5d984f6f4e5dc9c9ee8efb3a462fa3b58d71715b
7
+ data.tar.gz: 9f8b8ae9ac001d65a8bdcd773c7d729129ae889b080412bb7cc346913919739c9f079cd0ac78d5f1619b97beacc4efcea341dee48e1990238d1f39e9dac162ea
@@ -76,7 +76,9 @@ module Api
76
76
  private
77
77
 
78
78
  def respond_for_report(arf_report)
79
- if arf_report.new_record?
79
+ if arf_report.nil?
80
+ upload_fail(_("Policy with id %s not found.") % params[:policy_id])
81
+ elsif arf_report.new_record?
80
82
  upload_fail arf_report.errors.full_messages.to_sentence
81
83
  else
82
84
  render :json => { :result => :ok, :id => arf_report.id.to_s }
@@ -89,11 +91,6 @@ module Api
89
91
  end
90
92
 
91
93
  def find_resources_before_create
92
- unless ForemanOpenscap::Policy.where(:id => params[:policy_id]).any?
93
- upload_fail(_("Policy with id %s not found.") % params[:policy_id])
94
- return
95
- end
96
-
97
94
  @asset = ForemanOpenscap::Helper::get_asset(params[:cname], params[:policy_id])
98
95
 
99
96
  unless @asset
@@ -49,6 +49,7 @@ module Api::V2
49
49
  param :host_ids, Array, :desc => N_('Apply policy to hosts')
50
50
  param :tailoring_file_id, Integer, :desc => N_('Tailoring file ID')
51
51
  param :tailoring_file_profile_id, Integer, :desc => N_('Tailoring file profile ID')
52
+ param :deploy_by, ForemanOpenscap::Policy.deploy_by_variants, :desc => N_('How the policy should be deployed')
52
53
  param_group :taxonomies, ::Api::V2::BaseController
53
54
  end
54
55
  end
@@ -58,7 +59,8 @@ module Api::V2
58
59
 
59
60
  def create
60
61
  @policy = ForemanOpenscap::Policy.new(policy_params)
61
- process_response @policy.save
62
+ ForemanOpenscap::LookupKeyOverrider.new(@policy).override
63
+ process_response(@policy.errors.none? && @policy.save)
62
64
  end
63
65
 
64
66
  api :PUT, '/compliance/policies/:id', N_('Update a Policy')
@@ -3,7 +3,7 @@ module Foreman::Controller::Parameters::PolicyApi
3
3
 
4
4
  class_methods do
5
5
  def filter_params_list
6
- [:description, :name, :period, :scap_content_id, :scap_content_profile_id,
6
+ [:description, :name, :period, :scap_content_id, :scap_content_profile_id, :deploy_by,
7
7
  :weekday, :day_of_month, :cron_line, :tailoring_file_id, :tailoring_file_profile_id,
8
8
  :location_ids => [], :organization_ids => [], :hostgroup_ids => [], :host_ids => []]
9
9
  end
@@ -32,9 +32,10 @@ class PoliciesController < ApplicationController
32
32
 
33
33
  def create
34
34
  @policy = ::ForemanOpenscap::Policy.new(policy_params)
35
+ ForemanOpenscap::LookupKeyOverrider.new(@policy).override if @policy.current_step?('Policy Attributes')
35
36
  if @policy.wizard_completed? && @policy.save
36
37
  process_success :success_redirect => policies_path
37
- elsif @policy.valid?
38
+ elsif @policy.errors.none? && @policy.valid?
38
39
  render('new') && return
39
40
  else
40
41
  @policy.rewind_step
@@ -0,0 +1,14 @@
1
+ module ForemanOpenscapHelper
2
+ def scap_doc_link(section = '', text = _('documentation'))
3
+ link_to(
4
+ text,
5
+ scap_doc_url(section),
6
+ :rel => 'external noopener noreferrer', :target => '_blank'
7
+ )
8
+ end
9
+
10
+ def scap_doc_url(section = '')
11
+ version = ForemanOpenscap::VERSION.split('.')[0..-2].join('.')
12
+ "https://theforeman.org/plugins/foreman_openscap/#{version}/index.html#{section}"
13
+ end
14
+ end
@@ -9,6 +9,42 @@ module PoliciesHelper
9
9
  policy.scap_content_profile.nil? ? "Default" : policy.scap_content_profile.title
10
10
  end
11
11
 
12
+ def deploy_by_radios(f, policy)
13
+ ForemanOpenscap::ConfigNameService.new.configs.map do |tool|
14
+ popover_block = popover("", config_inline_help(tool.inline_help))
15
+
16
+ label = label_tag('', :class => 'col-md-2 control-label') do
17
+ tool.type.to_s.capitalize.html_safe + ' ' + popover_block.html_safe
18
+ end
19
+
20
+ radio = content_tag(:div, :class => "col-md-2") do
21
+ f.radio_button(:deploy_by, tool.type, :disabled => !tool.available?, :checked => deploy_by_radio_checked(policy, tool))
22
+ end
23
+
24
+ content_tag(:div, :class => "clearfix") do
25
+ content_tag(:div, :class => "form-group") do
26
+ label.html_safe + radio.html_safe
27
+ end
28
+ end
29
+ end.join('').html_safe
30
+ end
31
+
32
+ def config_inline_help(help_hash)
33
+ link = if help_hash[:route_helper_method]
34
+ link_to_if_authorized help_hash[:replace_text], public_send(help_hash[:route_helper_method])
35
+ else
36
+ help_hash[:replace_text]
37
+ end
38
+ text = help_hash[:text]
39
+ text = text.split(help_hash[:replace_text], 2).join(link) if help_hash.key?(:replace_text)
40
+ text.html_safe
41
+ end
42
+
43
+ def deploy_by_radio_checked(policy, tool)
44
+ type = policy.deploy_by ? policy.deploy_by.to_sym : :puppet
45
+ tool.type == type
46
+ end
47
+
12
48
  def effective_policy_profile(policy)
13
49
  policy.tailoring_file ? policy.tailoring_file_profile.title : policy_profile_from_scap_content(policy)
14
50
  end
@@ -36,7 +36,11 @@ module ForemanOpenscap
36
36
  base.scoped_search :on => :id, :rename => :others_xccdf_rule,
37
37
  :only_explicit => true, :operators => ['= '], :ext_method => :search_by_rule_othered
38
38
 
39
- base.after_update :puppetrun!, :if => ->(host) { Setting[:puppetrun] && host.changed.include?('openscap_proxy_id') }
39
+ base.after_update :puppetrun!, :if => ->(host) do
40
+ Setting[:puppetrun] &&
41
+ host.changed.include?('openscap_proxy_id') &&
42
+ (host.individual_puppetclasses + host.parent_classes).pluck(:name).include?(ClientConfig::Puppet.new.puppetclass_name)
43
+ end
40
44
 
41
45
  base.scope :comply_with, lambda { |policy|
42
46
  joins(:arf_reports).merge(ArfReport.latest_of_policy(policy)).merge(ArfReport.passed)
@@ -4,22 +4,28 @@ module ForemanOpenscap
4
4
 
5
5
  included do
6
6
  validate :openscap_proxy_has_feature
7
- validate :scap_client_class_present
8
7
  after_save :update_scap_client
9
8
  end
10
9
 
11
10
  def update_scap_client
12
- update_scap_client_params if openscap_proxy_id_previously_changed?
11
+ name_service = ConfigNameService.new
12
+ if openscap_proxy_id_previously_changed?
13
+ model_match = self.class.name.underscore =~ /\Ahostgroup\z/ ? "hostgroup" : "fqdn"
14
+ name_service.all_available_except(:manual).each do |config|
15
+ update_client_params(model_match, config)
16
+ end
17
+ end
13
18
  end
14
19
 
15
- def update_scap_client_params
16
- model_match = self.class.name.underscore =~ /\Ahostgroup\z/ ? "hostgroup" : "fqdn"
17
- scap_params = find_scap_client.class_params
18
- server_lookup_key = scap_params.find { |param| param.key == "server" }
19
- port_lookup_key = scap_params.find { |param| param.key == "port" }
20
- pairs = scap_client_lookup_values_for([server_lookup_key, port_lookup_key], model_match)
20
+ def update_client_params(model_match, config)
21
+ client_item = config.find_config_item self.public_send(config.collection_method)
22
+ return unless client_item
23
+ lookup_keys = client_item.public_send(config.override_method_name)
24
+ server_key = lookup_keys.find { |param| param.key == config.server_param }
25
+ port_key = lookup_keys.find { |param| param.key == config.port_param }
26
+ pairs = scap_client_lookup_values_for([server_key, port_key], model_match)
21
27
  if openscap_proxy_id
22
- mapping = { "server" => openscap_proxy.hostname, "port" => openscap_proxy.port }
28
+ mapping = { config.server_param => openscap_proxy.hostname, config.port_param => openscap_proxy.port }
23
29
  update_scap_client_lookup_values(pairs, model_match, mapping)
24
30
  else
25
31
  destroy_scap_client_lookup_values pairs
@@ -54,10 +60,6 @@ module ForemanOpenscap
54
60
  end
55
61
  end
56
62
 
57
- def find_scap_client
58
- Puppetclass.find_by(name: "foreman_scap_client")
59
- end
60
-
61
63
  def lookup_matcher(model_match)
62
64
  model_match == "fqdn" ? "#{model_match}=#{name}" : "#{model_match}=#{title}"
63
65
  end
@@ -65,11 +67,5 @@ module ForemanOpenscap
65
67
  def openscap_proxy_has_feature
66
68
  errors.add(:openscap_proxy_id, _("must have Openscap feature")) if openscap_proxy_id && !openscap_proxy.has_feature?("Openscap")
67
69
  end
68
-
69
- def scap_client_class_present
70
- if changed.include?('openscap_proxy_id') && self.respond_to?(:openscap_proxy_id) && openscap_proxy_id
71
- errors.add(:openscap_proxy_id, _("Puppet class 'foreman_scap_client' not found, make sure it is imported from Puppet master")) unless find_scap_client
72
- end
73
- end
74
70
  end
75
71
  end
@@ -16,18 +16,18 @@ module ForemanOpenscap
16
16
  has_many :assets, :through => :asset_policies, :as => :assetable, :dependent => :destroy
17
17
 
18
18
  scoped_search :on => :name, :complete_value => true
19
-
20
- SCAP_PUPPET_CLASS = 'foreman_scap_client'.freeze
21
- POLICIES_CLASS_PARAMETER = 'policies'.freeze
22
- SERVER_CLASS_PARAMETER = 'server'.freeze
23
- PORT_CLASS_PARAMETER = 'port'.freeze
24
-
25
19
  before_validation :update_period_attrs
26
20
 
27
- validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 255 }
28
- validate :ensure_needed_puppetclasses
21
+ def self.deploy_by_variants
22
+ %w[puppet ansible manual]
23
+ end
24
+
25
+ validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 255 },
26
+ :if => Proc.new { |policy| policy.should_validate?('Policy Attributes') }
29
27
  validates :period, :inclusion => { :in => %w[weekly monthly custom], :message => _('is not a valid value') },
30
28
  :if => Proc.new { |policy| policy.should_validate?('Schedule') }
29
+ validates :deploy_by, :inclusion => { :in => Policy.deploy_by_variants },
30
+ :if => Proc.new { |policy| policy.should_validate?('Deployment Options') }
31
31
 
32
32
  validates :scap_content_id, presence: true, if: Proc.new { |policy| policy.should_validate?('SCAP Content') }
33
33
  validate :matching_content_profile, if: Proc.new { |policy| policy.should_validate?('SCAP Content') }
@@ -97,7 +97,7 @@ module ForemanOpenscap
97
97
  end
98
98
 
99
99
  def steps
100
- base_steps = [N_('Create policy'), N_('SCAP Content'), N_('Schedule')]
100
+ base_steps = [N_('Deployment Options'), N_('Policy Attributes'), N_('SCAP Content'), N_('Schedule')]
101
101
  base_steps << N_('Locations') if SETTINGS[:locations_enabled]
102
102
  base_steps << N_('Organizations') if SETTINGS[:organizations_enabled]
103
103
  base_steps << N_('Hostgroups') # always be last.
@@ -123,6 +123,10 @@ module ForemanOpenscap
123
123
  current_step == steps.first
124
124
  end
125
125
 
126
+ def current_step?(step_name)
127
+ current_step == step_name
128
+ end
129
+
126
130
  def last_step?
127
131
  current_step == steps.last
128
132
  end
@@ -246,49 +250,6 @@ module ForemanOpenscap
246
250
  (Date::DAYS_INTO_WEEK.with_indifferent_access[weekday] + 1) % 7
247
251
  end
248
252
 
249
- def ensure_needed_puppetclasses
250
- unless puppetclass = Puppetclass.find_by(name: SCAP_PUPPET_CLASS)
251
- errors[:base] << _("Required Puppet class %{class} is not found, please ensure it imported first.") % { :class => SCAP_PUPPET_CLASS }
252
- return false
253
- end
254
-
255
- return false unless override_policies_param(puppetclass)
256
- return false unless override_port_param(puppetclass)
257
- return false unless override_server_param(puppetclass)
258
- end
259
-
260
- def override_policies_param(puppetclass)
261
- override_param(puppetclass, POLICIES_CLASS_PARAMETER) do |param|
262
- param.key_type = 'array'
263
- param.default_value = '<%= @host.policies_enc %>'
264
- end
265
- end
266
-
267
- def override_port_param(puppetclass)
268
- override_param puppetclass, PORT_CLASS_PARAMETER
269
- end
270
-
271
- def override_server_param(puppetclass)
272
- override_param puppetclass, SERVER_CLASS_PARAMETER
273
- end
274
-
275
- def override_param(puppetclass, param_name)
276
- unless param = puppetclass.class_params.find_by(key: param_name)
277
- errors[:base] << _("Puppet class %{class} does not have %{parameter} class parameter.") % { :class => SCAP_PUPPET_CLASS, :parameter => param_name }
278
- return
279
- end
280
-
281
- param.override = true
282
-
283
- yield param if block_given?
284
-
285
- if param.changed? && !param.save
286
- errors[:base] << _("%{parameter} class parameter for class %{class} could not be configured.") % { :class => SCAP_PUPPET_CLASS, :parameter => param_name }
287
- return
288
- end
289
- param
290
- end
291
-
292
253
  def cron_line_split
293
254
  cron_line.to_s.split(' ')
294
255
  end
@@ -329,13 +290,7 @@ module ForemanOpenscap
329
290
  end
330
291
 
331
292
  def assign_policy_to_hostgroups
332
- if hostgroups.any?
333
- puppetclass = find_scap_puppetclass
334
- hostgroups.each do |hostgroup|
335
- hostgroup.puppetclasses << puppetclass unless hostgroup.puppetclasses.include? puppetclass
336
- populate_overrides(puppetclass, hostgroup)
337
- end
338
- end
293
+ HostgroupOverrider.new(self).populate
339
294
  end
340
295
 
341
296
  def profile_for_scan
@@ -348,27 +303,6 @@ module ForemanOpenscap
348
303
  end
349
304
  end
350
305
 
351
- def find_scap_puppetclass
352
- Puppetclass.find_by(name: SCAP_PUPPET_CLASS)
353
- end
354
-
355
- def populate_overrides(puppetclass, hostgroup)
356
- puppetclass.class_params.where(:override => true).find_each do |override|
357
- next unless hostgroup.puppet_proxy && (url = hostgroup.puppet_proxy.url).present?
358
-
359
- case override.key
360
- when SERVER_CLASS_PARAMETER
361
- lookup_value = LookupValue.where(:match => "hostgroup=#{hostgroup.to_label}", :lookup_key_id => override.id).first_or_initialize
362
- puppet_proxy_fqdn = URI.parse(url).host
363
- lookup_value.update_attribute(:value, puppet_proxy_fqdn)
364
- when PORT_CLASS_PARAMETER
365
- lookup_value = LookupValue.where(:match => "hostgroup=#{hostgroup.to_label}", :lookup_key_id => override.id).first_or_initialize
366
- puppet_proxy_port = URI.parse(url).port
367
- lookup_value.update_attribute(:value, puppet_proxy_port)
368
- end
369
- end
370
- end
371
-
372
306
  def assign_ids(ids, class_name)
373
307
  new_assets = ids.reject { |id| id.respond_to?(:empty?) && id.empty? }.reduce([]) do |memo, id|
374
308
  memo << assets.where(:assetable_type => class_name, :assetable_id => id).first_or_initialize
@@ -0,0 +1,38 @@
1
+ module ForemanOpenscap
2
+ module ClientConfig
3
+ class Ansible < Base
4
+ delegate :ansible_role_name, :to => :constants
5
+
6
+ alias config_item_name ansible_role_name
7
+
8
+ def type
9
+ :ansible
10
+ end
11
+
12
+ def available?
13
+ defined?(ForemanAnsible)
14
+ end
15
+
16
+ def inline_help
17
+ {
18
+ :text => "Requires Ansible plugin, #{ansible_role_name} Ansible role and variables. This will assign the role to the hosts or selected hostgroups.<br>To deploy foreman_scap_client, ansible roles run needs to be triggered manually. Manual run is also required after any change to this policy.",
19
+ :replace_text => 'Ansible role',
20
+ :route_helper_method => :hash_for_ansible_roles_path
21
+ }
22
+ end
23
+
24
+ def constants
25
+ OpenStruct.new(
26
+ :server_param => 'foreman_scap_client_server',
27
+ :port_param => 'foreman_scap_client_port',
28
+ :policies_param => 'foreman_scap_client_policies',
29
+ :ansible_role_name => 'theforeman.foreman_scap_client',
30
+ :config_item_class_name => 'AnsibleRole',
31
+ :override_method_name => 'ansible_variables',
32
+ :msg_name => _('Ansible role'),
33
+ :lookup_key_plural_name => _('Ansible variables')
34
+ )
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ module ForemanOpenscap
2
+ module ClientConfig
3
+ class Base
4
+ delegate :server_param, :port_param, :policies_param, :config_item_name,
5
+ :config_item_class_name, :override_method_name, :msg_name,
6
+ :lookup_key_plural_name, :to => :constants
7
+
8
+ def type
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def inline_help
13
+ {
14
+ :text => '',
15
+ :replace_text => '',
16
+ :route_helper_method => nil
17
+ }
18
+ end
19
+
20
+ def managed_overrides?
21
+ true
22
+ end
23
+
24
+ def available?
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def constants
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def collection_method
33
+ constants.config_item_class_name&.pluralize&.underscore
34
+ end
35
+
36
+ def find_config_item(scope = config_item_class_name.constantize)
37
+ scope.find_by :name => config_item_name
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ module ForemanOpenscap
2
+ module ClientConfig
3
+ class Manual < Base
4
+ def type
5
+ :manual
6
+ end
7
+
8
+ def available?
9
+ true
10
+ end
11
+
12
+ def inline_help
13
+ {
14
+ :text => "This leaves the setup of the foreman_scap_client solely on the user. The policy still needs to be defined in order to link incoming ARF reports."
15
+ }
16
+ end
17
+
18
+ def constants
19
+ OpenStruct.new
20
+ end
21
+
22
+ def managed_overrides?
23
+ false
24
+ end
25
+ end
26
+ end
27
+ end