foreman_openscap 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|