foreman_openscap 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/app/assets/javascripts/foreman_openscap/openscap_proxy.js +7 -0
- data/app/assets/javascripts/foreman_openscap/policy_edit.js +15 -0
- data/app/controllers/api/v2/compliance/arf_reports_controller.rb +2 -2
- data/app/controllers/api/v2/compliance/policies_controller.rb +16 -4
- data/app/controllers/api/v2/compliance/scap_contents_controller.rb +2 -2
- data/app/controllers/api/v2/compliance/tailoring_files_controller.rb +92 -0
- data/app/controllers/concerns/foreman/controller/parameters/policy_api.rb +2 -2
- data/app/controllers/concerns/foreman/controller/parameters/tailoring_file.rb +15 -0
- data/app/controllers/openscap_proxies_controller.rb +31 -0
- data/app/controllers/policies_controller.rb +14 -15
- data/app/controllers/scap_contents_controller.rb +0 -10
- data/app/controllers/tailoring_files_controller.rb +75 -0
- data/app/helpers/compliance_dashboard_helper.rb +2 -2
- data/app/helpers/policies_helper.rb +29 -1
- data/app/helpers/tailoring_files_helper.rb +5 -0
- data/app/lib/proxy_api/openscap.rb +18 -2
- data/app/models/concerns/foreman_openscap/data_stream_content.rb +43 -0
- data/app/models/concerns/foreman_openscap/host_extensions.rb +1 -1
- data/app/models/concerns/foreman_openscap/hostgroup_extensions.rb +8 -0
- data/app/models/foreman_openscap/policy.rb +28 -3
- data/app/models/foreman_openscap/scap_content.rb +4 -72
- data/app/models/foreman_openscap/scap_content_profile.rb +2 -0
- data/app/models/foreman_openscap/tailoring_file.rb +19 -0
- data/app/services/foreman_openscap/openscap_proxy_version_check.rb +63 -0
- data/app/validators/foreman_openscap/data_stream_validator.rb +44 -0
- data/app/views/api/v2/compliance/policies/base.json.rabl +2 -1
- data/app/views/api/v2/compliance/tailoring_files/base.json.rabl +6 -0
- data/app/views/api/v2/compliance/tailoring_files/index.json.rabl +3 -0
- data/app/views/api/v2/compliance/tailoring_files/main.json.rabl +5 -0
- data/app/views/api/v2/compliance/tailoring_files/show.json.rabl +7 -0
- data/app/views/arf_reports/_list.html.erb +3 -2
- data/app/views/dashboard/_compliance_host_reports_widget.html.erb +3 -3
- data/app/views/policies/_form.html.erb +9 -0
- data/app/views/policies/_list.html.erb +16 -4
- data/app/views/policies/_tailoring_file_selected.html.erb +3 -0
- data/app/views/policies/steps/_scap_content_form.html.erb +8 -0
- data/app/views/policies/welcome.html.erb +12 -13
- data/app/views/scap_contents/_list.html.erb +1 -1
- data/app/views/scap_contents/welcome.html.erb +14 -13
- data/app/views/smart_proxies/_openscap_spool.html.erb +9 -0
- data/app/views/smart_proxies/plugins/_openscap.html.erb +12 -0
- data/app/views/tailoring_files/_form.html.erb +25 -0
- data/app/views/tailoring_files/_list.html.erb +29 -0
- data/app/views/tailoring_files/edit.html.erb +3 -0
- data/app/views/tailoring_files/index.html.erb +3 -0
- data/app/views/tailoring_files/new.html.erb +3 -0
- data/app/views/tailoring_files/welcome.html.erb +21 -0
- data/config/routes.rb +22 -0
- data/db/migrate/20161109155255_create_tailoring_files.rb +23 -0
- data/db/migrate/20161223153249_add_permissions_to_arf_report.rb +11 -0
- data/lib/foreman_openscap/engine.rb +30 -5
- data/lib/foreman_openscap/version.rb +1 -1
- data/test/factories/policy_factory.rb +2 -0
- data/test/factories/scap_content_related.rb +7 -0
- data/test/files/tailoring_files/ssg-firefox-ds-tailoring-2.xml +23 -0
- data/test/files/tailoring_files/ssg-firefox-ds-tailoring.xml +31 -0
- data/test/functional/api/v2/compliance/policies_controller_test.rb +35 -8
- data/test/functional/api/v2/compliance/scap_contents_controller_test.rb +1 -1
- data/test/functional/api/v2/compliance/tailoring_files_controller_test.rb +63 -0
- data/test/functional/openscap_proxies_controller_test.rb +14 -0
- data/test/functional/tailoring_files_controller_test.rb +38 -0
- data/test/test_plugin_helper.rb +18 -24
- data/test/unit/openscap_host_test.rb +11 -1
- data/test/unit/policy_test.rb +26 -0
- data/test/unit/services/tailoring_files_proxy_check_test.rb +27 -0
- data/test/unit/tailoring_file_test.rb +26 -0
- metadata +59 -20
@@ -1,8 +1,8 @@
|
|
1
1
|
module ComplianceDashboardHelper
|
2
2
|
|
3
3
|
def latest_compliance_headers
|
4
|
-
string = "<th>#{_("Host")}</th>"
|
5
|
-
string += "<th>#{_("Policy")}</th>"
|
4
|
+
string = "<th class='col-md-7'>#{_("Host")}</th>"
|
5
|
+
string += "<th class='col-md-3'>#{_("Policy")}</th>"
|
6
6
|
# TRANSLATORS: initial character of Passed
|
7
7
|
string += translated_header(s_('Passed|P'), _('Passed'))
|
8
8
|
# TRANSLATORS: initial character of Failed
|
@@ -5,8 +5,16 @@ module PoliciesHelper
|
|
5
5
|
return []
|
6
6
|
end
|
7
7
|
|
8
|
+
def policy_profile_from_scap_content(policy)
|
9
|
+
policy.scap_content_profile.nil? ? "Default" : policy.scap_content_profile.title
|
10
|
+
end
|
11
|
+
|
12
|
+
def effective_policy_profile(policy)
|
13
|
+
policy.tailoring_file ? policy.tailoring_file_profile.title : policy_profile_from_scap_content(policy)
|
14
|
+
end
|
15
|
+
|
8
16
|
def scap_content_selector(form)
|
9
|
-
scap_contents = ::ForemanOpenscap::ScapContent.all
|
17
|
+
scap_contents = ::ForemanOpenscap::ScapContent.authorized(:view_scap_contents).all
|
10
18
|
if scap_contents.length > 1
|
11
19
|
select_f form, :scap_content_id, scap_contents, :id, :title,
|
12
20
|
{:include_blank => _("Choose existing SCAP Content")},
|
@@ -38,6 +46,26 @@ module PoliciesHelper
|
|
38
46
|
end
|
39
47
|
end
|
40
48
|
|
49
|
+
def tailoring_file_selector(form)
|
50
|
+
select_f form, :tailoring_file_id, ForemanOpenscap::TailoringFile.all.authorized(:view_tailoring_files), :id, :name,
|
51
|
+
{ :include_blank => _('Choose Tailoring File') },
|
52
|
+
{ :label => _('Tailoring File'),
|
53
|
+
:onchange => 'tailoring_file_selected(this)',
|
54
|
+
:'data-url' => method_path('tailoring_file_selected') }
|
55
|
+
end
|
56
|
+
|
57
|
+
def tailoring_file_profile_selector(form, tailoring_file)
|
58
|
+
if tailoring_file
|
59
|
+
select_f form, :tailoring_file_profile_id, tailoring_file.scap_content_profiles, :id, :title,
|
60
|
+
{ :selected => tailoring_file.scap_content_profiles.first.id },
|
61
|
+
{ :label => _("XCCDF Profile in Tailoring File"),
|
62
|
+
:help_inline => _("This profile will be used to override the one from scap content") }
|
63
|
+
else
|
64
|
+
# to make sure tailoring profile id is nil when tailoring file is deselected
|
65
|
+
form.hidden_field(:tailoring_file_profile_id, :value => nil)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
41
69
|
def submit_or_cancel_policy(form, overwrite = nil, args = { })
|
42
70
|
args[:cancel_path] ||= send("#{controller_name}_path")
|
43
71
|
content_tag(:div, :class => "clearfix") do
|
@@ -4,14 +4,24 @@ module ::ProxyAPI
|
|
4
4
|
@url = args[:url] + '/compliance/'
|
5
5
|
super args
|
6
6
|
@connect_params[:headers].merge!(:content_type => :xml)
|
7
|
+
@connect_params[:timeout] = timeout
|
7
8
|
end
|
8
9
|
|
9
10
|
def fetch_policies_for_scap_content(scap_file)
|
10
11
|
parse(post(scap_file, "scap_content/policies"))
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
parse(post(scap_file, "
|
14
|
+
def fetch_profiles_for_tailoring_file(scap_file)
|
15
|
+
parse(post(scap_file, "tailoring_file/profiles"))
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate_scap_file(scap_file, type)
|
19
|
+
parse(post(scap_file, "scap_file/validator/#{type}"))
|
20
|
+
rescue RestClient::RequestTimeout => e
|
21
|
+
raise ::ProxyAPI::ProxyException.new(url, e, N_("Request timed out. Please try increasing Settings -> proxy_request_timeout"))
|
22
|
+
rescue RestClient::ResourceNotFound => e
|
23
|
+
raise ::ProxyAPI::ProxyException.new(url, e,
|
24
|
+
N_("Could not validate %s. Please make sure you have appropriate proxy version to use this functionality") % scap_file.class)
|
15
25
|
end
|
16
26
|
|
17
27
|
def policy_html_guide(scap_file, policy)
|
@@ -46,5 +56,11 @@ module ::ProxyAPI
|
|
46
56
|
false
|
47
57
|
end
|
48
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def timeout
|
63
|
+
Setting[:proxy_request_timeout] && Setting[:proxy_request_timeout] > 120 ? Setting[:proxy_request_timeout] : 120
|
64
|
+
end
|
49
65
|
end
|
50
66
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ForemanOpenscap
|
2
|
+
module DataStreamContent
|
3
|
+
require 'digest/sha2'
|
4
|
+
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
validates :digest, :presence => true
|
9
|
+
validates :scap_file, :presence => true
|
10
|
+
|
11
|
+
validates_with ForemanOpenscap::DataStreamValidator
|
12
|
+
|
13
|
+
after_save :create_profiles
|
14
|
+
|
15
|
+
before_validation :redigest, :if => lambda { |ds_content| ds_content.persisted? && ds_content.scap_file_changed? }
|
16
|
+
before_destroy ActiveRecord::Base::EnsureNotUsedBy.new(:policies)
|
17
|
+
end
|
18
|
+
|
19
|
+
def proxy_url
|
20
|
+
@proxy_url ||= SmartProxy.with_features('Openscap').find do |proxy|
|
21
|
+
available = ProxyAPI::AvailableProxy.new(:url => proxy.url)
|
22
|
+
available.available?
|
23
|
+
end.try(:url)
|
24
|
+
@proxy_url
|
25
|
+
end
|
26
|
+
|
27
|
+
def digest
|
28
|
+
self[:digest] ||= Digest::SHA256.hexdigest(scap_file.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def redigest
|
34
|
+
self[:digest] = Digest::SHA256.hexdigest(scap_file.to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_profiles
|
38
|
+
fetch_profiles.each do |key, title|
|
39
|
+
ScapContentProfile.where(:profile_id => key, :title => title, "#{self.class.to_s.demodulize.underscore}_id".to_sym => id).first_or_create
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -67,7 +67,7 @@ module ForemanOpenscap
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def combined_policies
|
70
|
-
combined = self.hostgroup ? self.policies + self.hostgroup.policies : self.policies
|
70
|
+
combined = self.hostgroup ? self.policies + self.hostgroup.policies + self.hostgroup.inherited_policies : self.policies
|
71
71
|
combined.uniq
|
72
72
|
end
|
73
73
|
|
@@ -8,6 +8,14 @@ module ForemanOpenscap
|
|
8
8
|
has_many :policies, :through => :asset_policies, :class_name => "::ForemanOpenscap::Policy"
|
9
9
|
end
|
10
10
|
|
11
|
+
def inherited_policies
|
12
|
+
return [] unless parent
|
13
|
+
|
14
|
+
ancestors.inject([]) do |policies, hostgroup|
|
15
|
+
policies += hostgroup.policies
|
16
|
+
end.uniq
|
17
|
+
end
|
18
|
+
|
11
19
|
unless defined?(Katello::System)
|
12
20
|
private
|
13
21
|
|
@@ -6,6 +6,8 @@ module ForemanOpenscap
|
|
6
6
|
|
7
7
|
belongs_to :scap_content
|
8
8
|
belongs_to :scap_content_profile
|
9
|
+
belongs_to :tailoring_file
|
10
|
+
belongs_to :tailoring_file_profile, :class_name => ForemanOpenscap::ScapContentProfile
|
9
11
|
has_many :policy_arf_reports
|
10
12
|
has_many :arf_reports, :through => :policy_arf_reports, :dependent => :destroy
|
11
13
|
has_many :asset_policies
|
@@ -28,7 +30,7 @@ module ForemanOpenscap
|
|
28
30
|
validates :scap_content_id, presence: true, if: Proc.new { |policy| policy.should_validate?('SCAP Content') }
|
29
31
|
validates :scap_content_profile_id, presence: true, if: Proc.new { |policy| policy.should_validate?('SCAP Content') }
|
30
32
|
|
31
|
-
validate :valid_cron_line, :valid_weekday, :valid_day_of_month
|
33
|
+
validate :valid_cron_line, :valid_weekday, :valid_day_of_month, :valid_tailoring, :valid_tailoring_profile
|
32
34
|
|
33
35
|
after_save :assign_policy_to_hostgroups
|
34
36
|
# before_destroy - ensure that the policy has no hostgroups, or classes
|
@@ -166,9 +168,11 @@ module ForemanOpenscap
|
|
166
168
|
def to_enc
|
167
169
|
{
|
168
170
|
'id' => self.id,
|
169
|
-
'profile_id' =>
|
171
|
+
'profile_id' => profile_for_scan,
|
170
172
|
'content_path' => "/var/lib/openscap/content/#{self.scap_content.digest}.xml",
|
171
|
-
'
|
173
|
+
'tailoring_path' => tailoring_file ? "/var/lib/openscap/tailoring/#{self.tailoring_file.digest}.xml" : '',
|
174
|
+
'download_path' => "/compliance/policies/#{self.id}/content", # default to proxy path
|
175
|
+
'tailoring_download_path' => "/compliance/policies/#{self.id}/tailoring"
|
172
176
|
}.merge(period_enc)
|
173
177
|
end
|
174
178
|
|
@@ -273,6 +277,17 @@ module ForemanOpenscap
|
|
273
277
|
end
|
274
278
|
end
|
275
279
|
|
280
|
+
def valid_tailoring
|
281
|
+
errors.add(:tailoring_file_id, _("must be present when tailoring file profile present")) if tailoring_file_profile_id && !tailoring_file_id
|
282
|
+
errors.add(:tailoring_file_profile_id, _("must be present when tailoring file present")) if !tailoring_file_profile_id && tailoring_file_id
|
283
|
+
end
|
284
|
+
|
285
|
+
def valid_tailoring_profile
|
286
|
+
if tailoring_file && tailoring_file_profile && !ScapContentProfile.where(:tailoring_file_id => tailoring_file_id).include?(tailoring_file_profile)
|
287
|
+
errors.add(:tailoring_file_profile, _("does not come from selected tailoring file"))
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
276
291
|
def assign_policy_to_hostgroups
|
277
292
|
if hostgroups.any?
|
278
293
|
puppetclass = find_scap_puppetclass
|
@@ -283,6 +298,16 @@ module ForemanOpenscap
|
|
283
298
|
end
|
284
299
|
end
|
285
300
|
|
301
|
+
def profile_for_scan
|
302
|
+
if tailoring_file_profile
|
303
|
+
tailoring_file_profile.profile_id
|
304
|
+
elsif scap_content_profile
|
305
|
+
scap_content_profile.profile_id
|
306
|
+
else
|
307
|
+
''
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
286
311
|
def find_scap_puppetclass
|
287
312
|
Puppetclass.find_by_name(SCAP_PUPPET_CLASS)
|
288
313
|
end
|
@@ -1,56 +1,13 @@
|
|
1
|
-
require 'digest/sha2'
|
2
|
-
|
3
1
|
module ForemanOpenscap
|
4
|
-
class DataStreamValidator < ActiveModel::Validator
|
5
|
-
def validate(scap_content)
|
6
|
-
return unless scap_content.scap_file_changed?
|
7
|
-
|
8
|
-
unless SmartProxy.with_features('Openscap').any?
|
9
|
-
scap_content.errors.add(:base, _('No proxy with OpenSCAP features'))
|
10
|
-
return false
|
11
|
-
end
|
12
|
-
|
13
|
-
if scap_content.proxy_url.nil?
|
14
|
-
scap_content.errors.add(:base, _('No available proxy to validate SCAP content'))
|
15
|
-
return false
|
16
|
-
end
|
17
|
-
|
18
|
-
begin
|
19
|
-
api = ProxyAPI::Openscap.new(:url => scap_content.proxy_url)
|
20
|
-
errors = api.validate_scap_content(scap_content.scap_file)
|
21
|
-
if errors && errors['errors'].any?
|
22
|
-
errors['errors'].each { |error| scap_content.errors.add(:scap_file, _(error)) }
|
23
|
-
return false
|
24
|
-
end
|
25
|
-
rescue *ProxyAPI::AvailableProxy::HTTP_ERRORS => e
|
26
|
-
scap_content.errors.add(:base, _('No available proxy to validate. Returned with error: %s') % e)
|
27
|
-
return false
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
unless (scap_content.scap_content_profiles.map(&:profile_id) - scap_content.fetch_profiles.keys).empty?
|
32
|
-
scap_content.errors.add(:scap_file, _('Changed file does not include existing SCAP content profiles'))
|
33
|
-
return false
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
2
|
class ScapContent < ActiveRecord::Base
|
39
3
|
include Authorizable
|
40
4
|
include Taxonomix
|
5
|
+
include DataStreamContent
|
41
6
|
|
42
7
|
has_many :scap_content_profiles, :dependent => :destroy
|
43
8
|
has_many :policies
|
44
9
|
|
45
|
-
before_destroy EnsureNotUsedBy.new(:policies)
|
46
|
-
|
47
|
-
validates_with DataStreamValidator
|
48
10
|
validates :title, :presence => true, :length => { :maximum => 255 }
|
49
|
-
validates :digest, :presence => true
|
50
|
-
validates :scap_file, :presence => true
|
51
|
-
|
52
|
-
after_save :create_profiles
|
53
|
-
before_validation :redigest, :if => lambda { |scap_content| scap_content.persisted? && scap_content.scap_file_changed? }
|
54
11
|
|
55
12
|
scoped_search :on => :title, :complete_value => true
|
56
13
|
scoped_search :on => :original_filename, :complete_value => true, :rename => :filename
|
@@ -77,8 +34,9 @@ module ForemanOpenscap
|
|
77
34
|
title
|
78
35
|
end
|
79
36
|
|
80
|
-
def
|
81
|
-
|
37
|
+
def as_json(*args)
|
38
|
+
hash = super
|
39
|
+
hash["scap_file"] = scap_file.to_s.encode('utf-8', :invalid => :replace, :undef => :replace, :replace => '_')
|
82
40
|
end
|
83
41
|
|
84
42
|
def fetch_profiles
|
@@ -86,31 +44,5 @@ module ForemanOpenscap
|
|
86
44
|
profiles = api.fetch_policies_for_scap_content(scap_file)
|
87
45
|
profiles
|
88
46
|
end
|
89
|
-
|
90
|
-
def proxy_url
|
91
|
-
@proxy_url ||= SmartProxy.with_features('Openscap').find do |proxy|
|
92
|
-
available = ProxyAPI::AvailableProxy.new(:url => proxy.url)
|
93
|
-
available.available?
|
94
|
-
end.try(:url)
|
95
|
-
@proxy_url
|
96
|
-
end
|
97
|
-
|
98
|
-
def as_json(*args)
|
99
|
-
hash = super
|
100
|
-
hash["scap_file"] = scap_file.to_s.encode('utf-8', :invalid => :replace, :undef => :replace, :replace => '_')
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def create_profiles
|
106
|
-
profiles = fetch_profiles
|
107
|
-
profiles.each {|key, title|
|
108
|
-
scap_content_profiles.where(:profile_id => key, :title => title).first_or_create
|
109
|
-
}
|
110
|
-
end
|
111
|
-
|
112
|
-
def redigest
|
113
|
-
self[:digest] = Digest::SHA256.hexdigest "#{scap_file}"
|
114
|
-
end
|
115
47
|
end
|
116
48
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ForemanOpenscap
|
2
|
+
class TailoringFile < ActiveRecord::Base
|
3
|
+
include Authorizable
|
4
|
+
include Taxonomix
|
5
|
+
include DataStreamContent
|
6
|
+
|
7
|
+
has_many :policies
|
8
|
+
has_many :scap_content_profiles, :dependent => :destroy
|
9
|
+
validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 255 }
|
10
|
+
|
11
|
+
scoped_search :on => :name, :complete_value => true
|
12
|
+
scoped_search :on => :original_filename, :complete_value => true, :rename => :filename
|
13
|
+
|
14
|
+
def fetch_profiles
|
15
|
+
api = ProxyAPI::Openscap.new(:url => proxy_url)
|
16
|
+
api.fetch_profiles_for_tailoring_file(scap_file)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module ForemanOpenscap
|
2
|
+
class OpenscapProxyVersionCheck
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@versions = {}
|
6
|
+
@message = ''
|
7
|
+
@down = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
@versions = openscap_proxy_versions.select do |key, value|
|
12
|
+
Gem::Version.new(value) <= Gem::Version.new("0.6.1")
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def pass?
|
18
|
+
!any_outdated? && !any_unreachable?
|
19
|
+
end
|
20
|
+
|
21
|
+
def any_outdated?
|
22
|
+
!@versions.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def any_unreachable?
|
26
|
+
!@down.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def message
|
30
|
+
if pass?
|
31
|
+
@message
|
32
|
+
else
|
33
|
+
build_message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_message
|
40
|
+
@message = _('This feature is temporarily disabled. ')
|
41
|
+
@message << _('The following Smart Proxies need to be updated to unlock the feature: %s. ') % @versions.keys.to_sentence if any_outdated?
|
42
|
+
@message << _('The following proxies could not be reached: %s. Please make sure they are available so Foreman can check their versions.') % @down.to_sentence if any_unreachable?
|
43
|
+
@message
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_openscap_proxies
|
47
|
+
SmartProxy.with_features "Openscap"
|
48
|
+
end
|
49
|
+
|
50
|
+
def openscap_proxy_versions
|
51
|
+
get_openscap_proxies.inject({}) do |memo, proxy|
|
52
|
+
begin
|
53
|
+
status = ProxyStatus::Version.new(proxy).version
|
54
|
+
openscap_version = status["modules"]["openscap"]
|
55
|
+
memo[proxy.name] = openscap_version
|
56
|
+
rescue Foreman::WrappedException
|
57
|
+
@down << proxy.name
|
58
|
+
end
|
59
|
+
memo
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ForemanOpenscap
|
2
|
+
class DataStreamValidator < ActiveModel::Validator
|
3
|
+
def validate(data_stream_content)
|
4
|
+
return unless data_stream_content.scap_file_changed?
|
5
|
+
|
6
|
+
content_type = data_type(data_stream_content)
|
7
|
+
|
8
|
+
unless SmartProxy.with_features('Openscap').any?
|
9
|
+
data_stream_content.errors.add(:base, _('No proxy with OpenSCAP features'))
|
10
|
+
return false
|
11
|
+
end
|
12
|
+
|
13
|
+
if data_stream_content.proxy_url.nil?
|
14
|
+
data_stream_content.errors.add(:base, _('No available proxy to validate SCAP data stream file'))
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
api = ProxyAPI::Openscap.new(:url => data_stream_content.proxy_url)
|
20
|
+
errors = api.validate_scap_file(data_stream_content.scap_file, content_type)
|
21
|
+
if errors && errors['errors'].any?
|
22
|
+
errors['errors'].each { |error| data_stream_content.errors.add(:scap_file, _(error)) }
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
rescue *ProxyAPI::AvailableProxy::HTTP_ERRORS => e
|
26
|
+
data_stream_content.errors.add(:base, _('No available proxy to validate. Returned with error: %s') % e)
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
|
30
|
+
is_scap_content = content_type == 'scap_content'
|
31
|
+
|
32
|
+
if is_scap_content && !(data_stream_content.scap_content_profiles.map(&:profile_id) - data_stream_content.fetch_profiles.keys).empty?
|
33
|
+
data_stream_content.errors.add(:scap_file, _('Changed file does not include existing SCAP content profiles'))
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def data_type(data_stream_content)
|
41
|
+
data_stream_content.class.to_s.demodulize.underscore
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|