smart_proxy_openscap 0.7.5 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00056a49674ba03472d6826481526c4ea1c46de925c815023bfcfd1332c57f78
4
- data.tar.gz: 89ce04958b0e9cf5443d26ed135ec4f875d4be78d6c58b422c0ce52e3f96e108
3
+ metadata.gz: 385df2070cb04d103c5a01adaafe76ad62e2e11d45b0f9dd8cf9b8ee85a398b8
4
+ data.tar.gz: e715e8f29c68228523b9960a9940941a911cc6d917d9e422e745994c0976f7b6
5
5
  SHA512:
6
- metadata.gz: cfdb8cbb7f73e95e419fdf6dd3e737242f42ebe9f81d86c3f97ec634a450715718a541ce95096c54b9d625d7bff24a8934fbaf6730c1010ea39926d8b5e79927
7
- data.tar.gz: abe8e00cd38c8c422fe05c9c53c19821d9755614698f4741b96ff49d30bd236a3489f76ca55253dd4a5e5297aca9e3db35d22694e981b8e2162c5dc6934d5d5e
6
+ metadata.gz: 544dfb94c425239d852f31d4e32a840b4fc3bc1891cde91d78b24ca43ae8d17220e79dcd1eba96e1f8a147d368795b3f9da8062eac92c62a3a01608d4d0ce3d2
7
+ data.tar.gz: ad70eb12bc8f21f208de39af555efb0646fa2e56bd1e20bb193d4fae70be78d56b1862047de183322e63c12bd9a04edc86e4304f5c31257a9c431da59c701a26
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ gemspec
4
4
  group :development do
5
5
  gem 'test-unit'
6
6
  gem 'pry'
7
+ gem 'pry-byebug'
7
8
  gem 'rubocop'
8
9
  gem 'rack', '~> 1.6.8' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2')
9
10
  gem 'smart_proxy', :github => "theforeman/smart-proxy", :branch => 'develop'
@@ -1,38 +1,95 @@
1
- require 'smart_proxy_openscap/shell_wrapper'
1
+ require 'openscap_parser/test_result_file'
2
+ require 'smart_proxy_openscap/openscap_exception'
2
3
 
3
4
  module Proxy
4
5
  module OpenSCAP
5
- class ArfParser < ShellWrapper
6
+ class ArfParser
7
+ include Proxy::Log
6
8
 
7
9
  def initialize(cname, policy_id, date)
8
10
  @cname = cname
9
11
  @policy_id = policy_id
10
12
  @date = date
11
- @script_name = 'smart-proxy-arf-json'
12
13
  end
13
14
 
14
15
  def as_json(arf_data)
15
- execute_shell_command arf_data
16
- end
16
+ begin
17
+ file = Tempfile.new
18
+ file.write(arf_data)
19
+ file.rewind
20
+ decompressed = `bunzip2 -dc #{file.path}`
21
+ rescue => e
22
+ logger.error e
23
+ raise Proxy::OpenSCAP::ReportDecompressError, "Failed to decompress received report bzip, cause: #{e.message}"
24
+ ensure
25
+ file.close
26
+ file.unlink
27
+ end
28
+ arf_file = ::OpenscapParser::TestResultFile.new(decompressed)
29
+ rules = arf_file.benchmark.rules.reduce({}) do |memo, rule|
30
+ memo[rule.id] = rule
31
+ memo
32
+ end
17
33
 
18
- def in_filename
19
- "#{super}-#{@cname}-#{@policy_id}-#{@date}-"
34
+ arf_digest = Digest::SHA256.hexdigest(arf_data)
35
+ report = parse_results(rules, arf_file.test_result, arf_digest)
36
+ report[:openscap_proxy_name] = Proxy::OpenSCAP::Plugin.settings.registered_proxy_name
37
+ report[:openscap_proxy_url] = Proxy::OpenSCAP::Plugin.settings.registered_proxy_url
38
+ report.to_json
20
39
  end
21
40
 
22
- def out_filename
23
- "#{in_filename}json-"
41
+ private
42
+
43
+ def parse_results(rules, test_result, arf_digest)
44
+ results = test_result.rule_results
45
+ set_values = test_result.set_values
46
+ report = {}
47
+ report[:logs] = []
48
+ passed = 0
49
+ failed = 0
50
+ othered = 0
51
+ results.each do |result|
52
+ next if result.result == 'notapplicable' || result.result == 'notselected'
53
+ # get rules and their results
54
+ rule_data = rules[result.id]
55
+ report[:logs] << populate_result_data(result.id, result.result, rule_data, set_values)
56
+ # create metrics for the results
57
+ case result.result
58
+ when 'pass', 'fixed'
59
+ passed += 1
60
+ when 'fail'
61
+ failed += 1
62
+ else
63
+ othered += 1
64
+ end
65
+ end
66
+ report[:digest] = arf_digest
67
+ report[:metrics] = { :passed => passed, :failed => failed, :othered => othered }
68
+ report[:score] = test_result.score
69
+ report
24
70
  end
25
71
 
26
- def failure_message
27
- "Failure when running script which parses reports"
72
+ def populate_result_data(result_id, rule_result, rule_data, set_values)
73
+ log = {}
74
+ log[:source] = result_id
75
+ log[:result] = rule_result
76
+ log[:title] = rule_data.title
77
+ log[:description] = rule_data.description
78
+ log[:rationale] = rule_data.rationale
79
+ log[:references] = rule_data.references.map { |ref| { :href => ref.href, :title => ref.label }}
80
+ log[:fixes] = populate_fixes rule_data.fixes, set_values
81
+ log[:severity] = rule_data.severity
82
+ log
28
83
  end
29
84
 
30
- def command(in_file, out_file)
31
- "#{script_location} " <<
32
- "#{in_file.path} " <<
33
- "#{out_file.path} " <<
34
- "#{Proxy::OpenSCAP::Plugin.settings.registered_proxy_name} " <<
35
- "#{Proxy::OpenSCAP::Plugin.settings.registered_proxy_url}"
85
+ def populate_fixes(fixes, set_values)
86
+ fixes.map do |fix|
87
+ {
88
+ :id => fix.id,
89
+ :system => fix.system,
90
+ :full_text => fix.full_text(set_values)
91
+ }
92
+ end
36
93
  end
37
94
  end
38
95
  end
@@ -1,30 +1,24 @@
1
- require 'smart_proxy_openscap/shell_wrapper'
1
+ require 'openscap_parser/datastream_file'
2
+ require 'openscap_parser/tailoring_file'
2
3
 
3
4
  module Proxy::OpenSCAP
4
- class ContentParser < ShellWrapper
5
- def initialize(type)
6
- @type = type
7
- @script_name = 'smart-proxy-scap-validation'
8
- end
9
-
10
- def validate(scap_file)
11
- execute_shell_command scap_file
12
- end
13
-
14
- def out_filename
15
- "#{in_filename}json-"
16
- end
17
-
18
- def in_filename
19
- "#{super}-#{@type}-validate-"
20
- end
21
-
22
- def failure_message
23
- "Failure when running script which validates scap files"
24
- end
25
-
26
- def command(in_file, out_file)
27
- "#{script_location} #{in_file.path} #{out_file.path} #{@type}"
5
+ class ContentParser
6
+ def validate(file_type, scap_file)
7
+ msg = 'Invalid SCAP file type'
8
+ errors = []
9
+ file = nil
10
+ begin
11
+ case file_type
12
+ when 'scap_content'
13
+ file = ::OpenscapParser::DatastreamFile.new(scap_file)
14
+ when 'tailoring_file'
15
+ file = ::OpenscapParser::TailoringFile.new(scap_file)
16
+ end
17
+ errors << msg unless file.valid?
18
+ rescue Nokogiri::XML::SyntaxError => e
19
+ errors << msg
20
+ end
21
+ { errors: errors }
28
22
  end
29
23
  end
30
24
  end
@@ -25,13 +25,6 @@ module Proxy::OpenSCAP
25
25
  include ::Proxy::Log
26
26
  helpers ::Proxy::Helpers
27
27
  authorize_with_ssl_client
28
- CLIENT_PATHS = Regexp.compile(%r{^(/arf/\d+|/policies/\d+/content/|/policies/\d+/tailoring/)})
29
-
30
- # authorize via trusted hosts but let client paths in without such authorization
31
- before do
32
- pass if request.path_info =~ CLIENT_PATHS
33
- do_authorize_with_trusted_hosts
34
- end
35
28
 
36
29
  post "/arf/:policy" do
37
30
  # first let's verify client's certificate
@@ -52,7 +45,7 @@ module Proxy::OpenSCAP
52
45
  logger.error "Failed to save Report in reports directory (#{Proxy::OpenSCAP::Plugin.settings.reportsdir}). Failed with: #{e.message}.
53
46
  Saving file in #{Proxy::OpenSCAP::Plugin.settings.failed_dir}. Please copy manually to #{Proxy::OpenSCAP::Plugin.settings.reportsdir}"
54
47
  { :result => 'Storage failure on proxy, see proxy logs for details' }.to_json
55
- rescue Proxy::OpenSCAP::OpenSCAPException => e
48
+ rescue Nokogiri::XML::SyntaxError => e
56
49
  error = "Failed to parse Arf Report, moving to #{Proxy::OpenSCAP::Plugin.settings.corrupted_dir}"
57
50
  logger.error error
58
51
  Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.corrupted_dir, cn, policy, date).store_corrupted(request.body.string)
@@ -65,7 +58,7 @@ module Proxy::OpenSCAP
65
58
  { :result => msg }.to_json
66
59
  rescue Proxy::OpenSCAP::StoreSpoolError => e
67
60
  log_halt 500, e.message
68
- rescue Proxy::OpenSCAP::ReportUploadError => e
61
+ rescue Proxy::OpenSCAP::ReportUploadError, Proxy::OpenSCAP::ReportDecompressError => e
69
62
  { :result => e.message }.to_json
70
63
  end
71
64
  end
@@ -133,7 +126,7 @@ module Proxy::OpenSCAP
133
126
 
134
127
  post "/scap_content/policies" do
135
128
  begin
136
- Proxy::OpenSCAP::ProfilesParser.new('scap_content').profiles(request.body.string)
129
+ Proxy::OpenSCAP::ProfilesParser.new.profiles('scap_content', request.body.string)
137
130
  rescue *HTTP_ERRORS => e
138
131
  log_halt 500, e.message
139
132
  rescue StandardError => e
@@ -143,7 +136,7 @@ module Proxy::OpenSCAP
143
136
 
144
137
  post "/tailoring_file/profiles" do
145
138
  begin
146
- Proxy::OpenSCAP::ProfilesParser.new('tailoring_file').profiles(request.body.string)
139
+ Proxy::OpenSCAP::ProfilesParser.new.profiles('tailoring_file', request.body.string)
147
140
  rescue *HTTP_ERRORS => e
148
141
  log_halt 500, e.message
149
142
  rescue StandardError => e
@@ -183,7 +176,7 @@ module Proxy::OpenSCAP
183
176
 
184
177
  def validate_scap_file(params)
185
178
  begin
186
- Proxy::OpenSCAP::ContentParser.new(params[:type]).validate(request.body.string)
179
+ Proxy::OpenSCAP::ContentParser.new.validate(params[:type], request.body.string).to_json
187
180
  rescue *HTTP_ERRORS => e
188
181
  log_halt 500, e.message
189
182
  rescue StandardError => e
@@ -6,4 +6,5 @@ module Proxy::OpenSCAP
6
6
  class FileNotFound < StandardError; end
7
7
  class StoreCorruptedError < StandardError; end
8
8
  class ReportUploadError < StandardError; end
9
+ class ReportDecompressError < StandardError; end
9
10
  end
@@ -1,31 +1,30 @@
1
- require 'smart_proxy_openscap/shell_wrapper'
1
+ require 'openscap_parser/datastream_file'
2
+ require 'openscap_parser/tailoring_file'
2
3
 
3
4
  module Proxy
4
5
  module OpenSCAP
5
- class ProfilesParser < ShellWrapper
6
- def initialize(type)
7
- @type = type
8
- @script_name = 'smart-proxy-scap-profiles'
9
- end
10
-
11
- def profiles(scap_file)
12
- execute_shell_command scap_file
13
- end
14
-
15
- def out_filename
16
- "#{in_filename}json-"
17
- end
18
-
19
- def in_filename
20
- "#{super}-#{@type}-profiles-"
21
- end
6
+ class ProfilesParser
7
+ def profiles(file_type, scap_file)
8
+ profiles = []
9
+ error_msg = 'Failed to parse profiles'
10
+ begin
11
+ case file_type
12
+ when 'scap_content'
13
+ profiles = ::OpenscapParser::DatastreamFile.new(scap_file).benchmark.profiles
14
+ when 'tailoring_file'
15
+ profiles = ::OpenscapParser::TailoringFile.new(scap_file).tailoring.profiles
16
+ else
17
+ raise OpenSCAPException, "Unknown file type, expected 'scap_content' or 'tailoring_file'"
18
+ end
19
+ rescue Nokogiri::XML::SyntaxError
20
+ raise OpenSCAPException, error_msg
21
+ end
22
22
 
23
- def failure_message
24
- "Failure when running script which extracts profiles from scap file"
25
- end
23
+ raise OpenSCAPException, error_msg if profiles.empty?
26
24
 
27
- def command(in_file, out_file)
28
- "#{script_location} #{in_file.path} #{out_file.path} #{@type}"
25
+ result = profiles.reduce({}) do |memo, profile|
26
+ memo.tap { |acc| acc[profile.id] = profile.title }
27
+ end.to_json
29
28
  end
30
29
  end
31
30
  end
@@ -55,7 +55,7 @@ module Proxy::OpenSCAP
55
55
  post_to_foreman = ForemanForwarder.new.post_arf_report(cname, policy_id, date, data, @loaded_settings.timeout)
56
56
  Proxy::OpenSCAP::StorageFS.new(@loaded_settings.reportsdir, cname, post_to_foreman['id'], date).store_archive(data)
57
57
  File.delete arf_file_path
58
- rescue Proxy::OpenSCAP::OpenSCAPException => e
58
+ rescue Nokogiri::XML::SyntaxError, Proxy::OpenSCAP::ReportDecompressError => e
59
59
  logger.error "Failed to parse Arf Report at #{arf_file_path}, moving to #{@loaded_settings.corrupted_dir}"
60
60
 
61
61
  Proxy::OpenSCAP::StorageFS.new(@loaded_settings.corrupted_dir, cname, policy_id, date).
@@ -10,6 +10,6 @@
10
10
 
11
11
  module Proxy
12
12
  module OpenSCAP
13
- VERSION = '0.7.5'
13
+ VERSION = '0.8.0'
14
14
  end
15
15
  end
@@ -14,10 +14,13 @@ Gem::Specification.new do |s|
14
14
 
15
15
  s.files = `git ls-files`.split("\n") - ['.gitignore']
16
16
  s.executables = ['smart-proxy-openscap-send']
17
+ s.requirements = 'bzip2'
17
18
 
18
19
  s.add_development_dependency('rake')
19
20
  s.add_development_dependency('rack-test')
20
21
  s.add_development_dependency('mocha')
21
22
  s.add_development_dependency('webmock')
22
23
  s.add_dependency 'openscap', '~> 0.4.7'
24
+
25
+ s.add_dependency 'openscap_parser', '~> 1.0.1'
23
26
  end
@@ -37,7 +37,7 @@ class ScapContentParserApiTest < Test::Unit::TestCase
37
37
 
38
38
  def test_invalid_scap_content_policies
39
39
  post '/scap_content/policies', '<xml>blah</xml>', 'CONTENT_TYPE' => 'text/xml'
40
- assert(last_response.body.include?('Failure when running script which extracts profiles from scap file'))
40
+ assert(last_response.body.include?('Failed to parse profiles'))
41
41
  end
42
42
 
43
43
  def test_scap_content_validator
@@ -1,10 +1,6 @@
1
1
  require 'test_helper'
2
2
  require 'smart_proxy_openscap/arf_html'
3
- require 'smart_proxy_openscap/arf_json'
4
3
  require 'smart_proxy_openscap/policy_guide'
5
- require 'smart_proxy_openscap/scap_profiles'
6
- require 'smart_proxy_openscap/arf_json'
7
- require 'smart_proxy_openscap/scap_validation'
8
4
 
9
5
  class ScriptClassTest < Test::Unit::TestCase
10
6
  def test_arf_generate_html
@@ -15,17 +11,6 @@ class ScriptClassTest < Test::Unit::TestCase
15
11
  end
16
12
  end
17
13
 
18
- def test_arf_as_json
19
- carry_out do |tmp|
20
- Proxy::OpenSCAP::ArfJson.new.as_json("#{Dir.getwd}/test/data/arf_report", tmp.path, 'my-proxy', 'http://test-proxy.org')
21
- json = read_json tmp
22
- refute_empty json['logs']
23
- refute_empty json['metrics']
24
- refute_empty json['openscap_proxy_name']
25
- refute_empty json['openscap_proxy_url']
26
- end
27
- end
28
-
29
14
  def test_policy_guide
30
15
  carry_out do |tmp|
31
16
  profile = "xccdf_org.ssgproject.content_profile_rht-ccp"
@@ -35,49 +20,6 @@ class ScriptClassTest < Test::Unit::TestCase
35
20
  end
36
21
  end
37
22
 
38
- def test_scap_file_profiles
39
- carry_out do |tmp|
40
- Proxy::OpenSCAP::ScapProfiles.new.profiles("#{Dir.getwd}/test/data/ssg-rhel7-ds.xml", tmp.path, 'scap_content')
41
- profiles = read_json tmp
42
- refute_empty profiles
43
- assert profiles["xccdf_org.ssgproject.content_profile_standard"]
44
- end
45
- end
46
-
47
- def test_tailoring_file_profiles
48
- carry_out do |tmp|
49
- Proxy::OpenSCAP::ScapProfiles.new.profiles("#{Dir.getwd}/test/data/tailoring.xml", tmp.path, 'tailoring_file')
50
- profiles = read_json tmp
51
- refute_empty profiles
52
- assert profiles["xccdf_org.ssgproject.content_profile_stig-firefox-upstream_customized"]
53
- end
54
- end
55
-
56
- def test_arf_json
57
- carry_out do |tmp|
58
- Proxy::OpenSCAP::ArfJson.new.as_json("#{Dir.getwd}/test/data/arf_report", tmp.path, 'my-proxy', 'http://test-proxy.org')
59
- json = read_json tmp
60
- refute_empty json['logs']
61
- refute_empty json['metrics']
62
- end
63
- end
64
-
65
- def test_scap_content_validation
66
- carry_out do |tmp|
67
- Proxy::OpenSCAP::ScapValidation.new.validate("#{Dir.getwd}/test/data/ssg-rhel7-ds.xml", tmp.path, 'scap_content')
68
- res = read_json tmp
69
- assert_empty res['errors']
70
- end
71
- end
72
-
73
- def test_tailoring_file_validation
74
- carry_out do |tmp|
75
- Proxy::OpenSCAP::ScapValidation.new.validate("#{Dir.getwd}/test/data/tailoring.xml", tmp.path, 'tailoring_file')
76
- res = read_json tmp
77
- assert_empty res['errors']
78
- end
79
- end
80
-
81
23
  private
82
24
 
83
25
  def carry_out
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_openscap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.5
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Šimon Lukašík
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-04-22 00:00:00.000000000 Z
13
+ date: 2021-03-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake
@@ -82,6 +82,20 @@ dependencies:
82
82
  - - "~>"
83
83
  - !ruby/object:Gem::Version
84
84
  version: 0.4.7
85
+ - !ruby/object:Gem::Dependency
86
+ name: openscap_parser
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: 1.0.1
92
+ type: :runtime
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: 1.0.1
85
99
  description: |-
86
100
  A plug-in to the Foreman's smart-proxy which receives
87
101
  bzip2ed ARF files and forwards them to the Foreman.
@@ -99,18 +113,14 @@ files:
99
113
  - README.md
100
114
  - Rakefile
101
115
  - bin/smart-proxy-arf-html
102
- - bin/smart-proxy-arf-json
103
116
  - bin/smart-proxy-openscap-send
104
117
  - bin/smart-proxy-openscap-send-inner
105
118
  - bin/smart-proxy-policy-guide
106
- - bin/smart-proxy-scap-profiles
107
- - bin/smart-proxy-scap-validation
108
119
  - bundler.d/openscap.rb
109
120
  - extra/rubygem-smart_proxy_openscap.spec
110
121
  - extra/smart-proxy-openscap-send.cron
111
122
  - lib/smart_proxy_openscap.rb
112
123
  - lib/smart_proxy_openscap/arf_html.rb
113
- - lib/smart_proxy_openscap/arf_json.rb
114
124
  - lib/smart_proxy_openscap/arf_parser.rb
115
125
  - lib/smart_proxy_openscap/content_parser.rb
116
126
  - lib/smart_proxy_openscap/fetch_file.rb
@@ -127,8 +137,6 @@ files:
127
137
  - lib/smart_proxy_openscap/policy_guide.rb
128
138
  - lib/smart_proxy_openscap/policy_parser.rb
129
139
  - lib/smart_proxy_openscap/profiles_parser.rb
130
- - lib/smart_proxy_openscap/scap_profiles.rb
131
- - lib/smart_proxy_openscap/scap_validation.rb
132
140
  - lib/smart_proxy_openscap/shell_wrapper.rb
133
141
  - lib/smart_proxy_openscap/spool_forwarder.rb
134
142
  - lib/smart_proxy_openscap/storage.rb
@@ -172,7 +180,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
180
  - - ">="
173
181
  - !ruby/object:Gem::Version
174
182
  version: '0'
175
- requirements: []
183
+ requirements:
184
+ - bzip2
176
185
  rubygems_version: 3.1.2
177
186
  signing_key:
178
187
  specification_version: 4
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
- path = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'lib')
3
- $:.unshift(path) if File.exist? path
4
-
5
- require 'smart_proxy_openscap/arf_json'
6
-
7
- Proxy::OpenSCAP::ArfJson.new.as_json ARGV[0], ARGV[1], ARGV[2], ARGV[3]
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
- path = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'lib')
3
- $:.unshift(path) if File.exist? path
4
-
5
- require 'smart_proxy_openscap/scap_profiles'
6
-
7
- Proxy::OpenSCAP::ScapProfiles.new.profiles ARGV[0], ARGV[1], ARGV[2]
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
- path = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'lib')
3
- $:.unshift(path) if File.exist? path
4
-
5
- require 'smart_proxy_openscap/scap_validation'
6
-
7
- Proxy::OpenSCAP::ScapValidation.new.validate ARGV[0], ARGV[1], ARGV[2]
@@ -1,114 +0,0 @@
1
- # encoding=utf-8
2
- require 'openscap'
3
- require 'openscap/ds/arf'
4
- require 'openscap/xccdf/testresult'
5
- require 'openscap/xccdf/ruleresult'
6
- require 'openscap/xccdf/rule'
7
- require 'openscap/xccdf/fix'
8
- require 'openscap/xccdf/benchmark'
9
- require 'json'
10
- require 'digest'
11
-
12
- module Proxy
13
- module OpenSCAP
14
- class ArfJson
15
- def as_json(file_in, file_out, proxy_name, proxy_url)
16
- ::OpenSCAP.oscap_init
17
- arf_digest = Digest::SHA256.hexdigest(File.read(file_in))
18
-
19
- arf = ::OpenSCAP::DS::Arf.new(file_in)
20
- test_result = arf.test_result
21
-
22
- results = test_result.rr
23
- sds = arf.report_request
24
- bench_source = sds.select_checklist!
25
- benchmark = ::OpenSCAP::Xccdf::Benchmark.new(bench_source)
26
- items = benchmark.items
27
-
28
- report = parse_results(items, results, arf_digest)
29
- report[:openscap_proxy_name] = proxy_name
30
- report[:openscap_proxy_url] = proxy_url
31
-
32
- File.write file_out, report.to_json
33
- ensure
34
- cleanup test_result, benchmark, sds, arf
35
- end
36
-
37
- private
38
-
39
- def parse_results(items, results, arf_digest)
40
- report = {}
41
- report[:logs] = []
42
- passed = 0
43
- failed = 0
44
- othered = 0
45
- results.each do |rr_id, result|
46
- next if result.result == 'notapplicable' || result.result == 'notselected'
47
- # get rules and their results
48
- rule_data = items[rr_id]
49
- report[:logs] << populate_result_data(rr_id, result.result, rule_data)
50
- # create metrics for the results
51
- case result.result
52
- when 'pass', 'fixed'
53
- passed += 1
54
- when 'fail'
55
- failed += 1
56
- else
57
- othered += 1
58
- end
59
- end
60
- report[:digest] = arf_digest
61
- report[:metrics] = { :passed => passed, :failed => failed, :othered => othered }
62
- report
63
- end
64
-
65
- def populate_result_data(result_id, rule_result, rule_data)
66
- log = {}
67
- log[:source] = ascii8bit_to_utf8(result_id)
68
- log[:result] = ascii8bit_to_utf8(rule_result)
69
- log[:title] = ascii8bit_to_utf8(rule_data.title)
70
- log[:description] = ascii8bit_to_utf8(rule_data.description)
71
- log[:rationale] = ascii8bit_to_utf8(rule_data.rationale)
72
- log[:references] = hash_a8b(rule_data.references.map(&:to_hash))
73
- log[:fixes] = hash_a8b(rule_data.fixes.map(&:to_hash))
74
- log[:severity] = ascii8bit_to_utf8(rule_data.severity)
75
- log
76
- end
77
-
78
- def cleanup(*args)
79
- args.compact.map(&:destroy)
80
- ::OpenSCAP.oscap_cleanup
81
- end
82
-
83
- # Unfortunately openscap in ruby 1.9.3 outputs data in Ascii-8bit.
84
- # We transform it to UTF-8 for easier json integration.
85
-
86
- # :invalid ::
87
- # If the value is invalid, #encode replaces invalid byte sequences in
88
- # +str+ with the replacement character. The default is to raise the
89
- # Encoding::InvalidByteSequenceError exception
90
- # :undef ::
91
- # If the value is undefined, #encode replaces characters which are
92
- # undefined in the destination encoding with the replacement character.
93
- # The default is to raise the Encoding::UndefinedConversionError.
94
- # :replace ::
95
- # Sets the replacement string to the given value. The default replacement
96
- # string is "\uFFFD" for Unicode encoding forms, and "?" otherwise.
97
- def ascii8bit_to_utf8(string)
98
- return ascii8bit_to_utf8_legacy(string) if RUBY_VERSION.start_with? '1.8'
99
- string.to_s.encode('utf-8', :invalid => :replace, :undef => :replace, :replace => '_')
100
- end
101
-
102
- # String#encode appeared first in 1.9, so we need a workaround for 1.8
103
- def ascii8bit_to_utf8_legacy(string)
104
- Iconv.conv('UTF-8//IGNORE', 'UTF-8', string.to_s)
105
- end
106
-
107
- def hash_a8b(ary)
108
- ary.map do |hash|
109
- Hash[hash.map { |key, value| [ascii8bit_to_utf8(key), ascii8bit_to_utf8(value)] }]
110
- end
111
- end
112
- end
113
- end
114
- end
@@ -1,52 +0,0 @@
1
- require 'openscap'
2
- require 'openscap/ds/sds'
3
- require 'openscap/source'
4
- require 'openscap/xccdf/benchmark'
5
- require 'openscap/xccdf/tailoring'
6
- require 'json'
7
-
8
- module Proxy
9
- module OpenSCAP
10
- class ScapProfiles
11
- def profiles(in_file, out_file, type)
12
- ::OpenSCAP.oscap_init
13
- source = ::OpenSCAP::Source.new(in_file)
14
- json = type == 'scap_content' ? scap_content_profiles(source) : tailoring_profiles(source)
15
- File.write out_file, json
16
- ensure
17
- source.destroy if source
18
- ::OpenSCAP.oscap_cleanup
19
- end
20
-
21
- def scap_content_profiles(source)
22
- bench = benchmark_profiles source
23
- profiles = collect_profiles bench
24
- profiles.to_json
25
- ensure
26
- bench.destroy if bench
27
- end
28
-
29
- def tailoring_profiles(source)
30
- tailoring = ::OpenSCAP::Xccdf::Tailoring.new(source, nil)
31
- profiles = collect_profiles tailoring
32
- profiles.to_json
33
- ensure
34
- tailoring.destroy if tailoring
35
- end
36
-
37
- def collect_profiles(profile_source)
38
- profile_source.profiles.inject({}) do |memo, (key, profile)|
39
- memo.tap { |hash| hash[key] = profile.title.strip }
40
- end
41
- end
42
-
43
- def benchmark_profiles(source)
44
- sds = ::OpenSCAP::DS::Sds.new(source)
45
- bench_source = sds.select_checklist!
46
- ::OpenSCAP::Xccdf::Benchmark.new(bench_source)
47
- ensure
48
- sds.destroy if sds
49
- end
50
- end
51
- end
52
- end
@@ -1,35 +0,0 @@
1
- require 'json'
2
- require 'openscap'
3
- require 'openscap/source'
4
-
5
- module Proxy
6
- module OpenSCAP
7
- class ScapValidation
8
- def allowed_types
9
- {
10
- 'tailoring_file' => 'XCCDF Tailoring',
11
- 'scap_content' => 'SCAP Source Datastream'
12
- }
13
- end
14
-
15
- def validate(in_file, out_file, type)
16
- errors = []
17
- ::OpenSCAP.oscap_init
18
- source = ::OpenSCAP::Source.new(in_file)
19
- if source.type != allowed_types[type]
20
- errors << "Uploaded file is #{source.type}, unexpected file type"
21
- end
22
-
23
- begin
24
- source.validate!
25
- rescue ::OpenSCAP::OpenSCAPError
26
- errors << "Invalid SCAP file type"
27
- end
28
- File.write out_file, { :errors => errors }.to_json
29
- ensure
30
- source.destroy if source
31
- ::OpenSCAP.oscap_cleanup
32
- end
33
- end
34
- end
35
- end