smart_proxy_openscap 0.7.2

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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +41 -0
  3. data/.rubocop_todo.yml +111 -0
  4. data/.travis.yml +14 -0
  5. data/COPYING +674 -0
  6. data/Gemfile +14 -0
  7. data/README.md +107 -0
  8. data/Rakefile +16 -0
  9. data/bin/smart-proxy-arf-html +7 -0
  10. data/bin/smart-proxy-arf-json +7 -0
  11. data/bin/smart-proxy-openscap-send +61 -0
  12. data/bin/smart-proxy-policy-guide +7 -0
  13. data/bin/smart-proxy-scap-profiles +7 -0
  14. data/bin/smart-proxy-scap-validation +7 -0
  15. data/bundler.d/openscap.rb +6 -0
  16. data/extra/rubygem-smart_proxy_openscap.spec +101 -0
  17. data/extra/smart-proxy-openscap-send.cron +2 -0
  18. data/lib/smart_proxy_openscap.rb +14 -0
  19. data/lib/smart_proxy_openscap/arf_html.rb +22 -0
  20. data/lib/smart_proxy_openscap/arf_json.rb +114 -0
  21. data/lib/smart_proxy_openscap/arf_parser.rb +39 -0
  22. data/lib/smart_proxy_openscap/content_parser.rb +30 -0
  23. data/lib/smart_proxy_openscap/fetch_file.rb +60 -0
  24. data/lib/smart_proxy_openscap/fetch_scap_content.rb +17 -0
  25. data/lib/smart_proxy_openscap/fetch_tailoring_file.rb +17 -0
  26. data/lib/smart_proxy_openscap/foreman_forwarder.rb +40 -0
  27. data/lib/smart_proxy_openscap/http_config.ru +20 -0
  28. data/lib/smart_proxy_openscap/openscap_api.rb +187 -0
  29. data/lib/smart_proxy_openscap/openscap_exception.rb +9 -0
  30. data/lib/smart_proxy_openscap/openscap_html_generator.rb +38 -0
  31. data/lib/smart_proxy_openscap/openscap_import_api.rb +32 -0
  32. data/lib/smart_proxy_openscap/openscap_lib.rb +67 -0
  33. data/lib/smart_proxy_openscap/openscap_plugin.rb +27 -0
  34. data/lib/smart_proxy_openscap/policy_guide.rb +23 -0
  35. data/lib/smart_proxy_openscap/policy_parser.rb +33 -0
  36. data/lib/smart_proxy_openscap/profiles_parser.rb +32 -0
  37. data/lib/smart_proxy_openscap/scap_profiles.rb +52 -0
  38. data/lib/smart_proxy_openscap/scap_validation.rb +35 -0
  39. data/lib/smart_proxy_openscap/shell_wrapper.rb +77 -0
  40. data/lib/smart_proxy_openscap/spool_forwarder.rb +79 -0
  41. data/lib/smart_proxy_openscap/storage.rb +47 -0
  42. data/lib/smart_proxy_openscap/storage_fs.rb +102 -0
  43. data/lib/smart_proxy_openscap/version.rb +15 -0
  44. data/settings.d/openscap.yml.example +33 -0
  45. data/smart_proxy_openscap.gemspec +23 -0
  46. data/test/data/arf_report +0 -0
  47. data/test/data/corrupted_arf_report +0 -0
  48. data/test/data/spool/cleanup_spool/arf/2c101b95-033f-4b15-b490-f50bf9090dae/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
  49. data/test/data/spool/cleanup_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
  50. data/test/data/spool/corrupted_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/a4dfba5db27b21795e6fa401b8dce7a70faeb25b7963891f07f6f4baaf052afb +0 -0
  51. data/test/data/spool/corrupted_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
  52. data/test/data/spool/valid_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
  53. data/test/data/spool/valid_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
  54. data/test/data/ssg-rhel7-ds.xml +20271 -0
  55. data/test/data/tailoring.xml +31 -0
  56. data/test/fetch_scap_api_test.rb +73 -0
  57. data/test/fetch_tailoring_api_test.rb +37 -0
  58. data/test/get_report_xml_html_test.rb +58 -0
  59. data/test/post_report_api_test.rb +86 -0
  60. data/test/scap_content_parser_api_test.rb +69 -0
  61. data/test/script_class_test.rb +96 -0
  62. data/test/spool_forwarder_test.rb +84 -0
  63. data/test/test_helper.rb +13 -0
  64. metadata +180 -0
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :development do
5
+ gem 'test-unit'
6
+ gem 'pry'
7
+ gem 'rubocop'
8
+ gem 'rack', '~> 1.6.8' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2')
9
+ gem 'smart_proxy', :github => "theforeman/smart-proxy", :branch => 'develop'
10
+ end
11
+
12
+ # load local gemfile
13
+ local_gemfile = File.join(File.dirname(__FILE__), 'Gemfile.local.rb')
14
+ self.instance_eval(Bundler.read_file(local_gemfile)) if File.exist?(local_gemfile)
@@ -0,0 +1,107 @@
1
+ # OpenSCAP plug-in for Foreman Proxy
2
+
3
+ A plug-in to the Foreman Proxy which receives bzip2ed ARF files
4
+ and forwards them as JSON to the Foreman.
5
+ smart_proxy_openscap plugin is required for the normal operation of OpenSCAP in the Foreman.
6
+
7
+ ## How it works
8
+
9
+ Incoming ARF files are authenticated using either puppet certificate or Katello certificate of
10
+ the client machine. The ARF files are parsed on the proxy and posted to the Foreman as JSON reports
11
+ and the ARF files are saved in a reports directory, where they can be accessed for full HTML report or
12
+ downloaded as bzip2ed xml report.
13
+ If posting is failed, the ARF files are saved in queue for later retry.
14
+
15
+ Learn more about [Foreman-OpenSCAP](https://github.com/theforeman/foreman_openscap) workflow.
16
+
17
+ ## Installation from RPMs
18
+
19
+ - Install smart_proxy_openscap
20
+
21
+ ```
22
+ # yum install rubygem-smart_proxy_openscap
23
+ ```
24
+
25
+ ## Installation from upstream git
26
+ - Add smart_proxy_openscap to your smart proxy `bundler.d/openscap.rb` gemfile:
27
+
28
+ ```
29
+ ~$ gem 'smart_proxy_openscap', :git => 'https://github.com/theforeman/smart_proxy_openscap.git'
30
+ ```
31
+
32
+ If you don't install through RPM and you are using bundler, you may need to create
33
+ /var/spool/foreman-proxy & /usr/share/foreman-proxy/openscap directories manually and
34
+ set it's owner to the user under which foreman-proxy runs.
35
+
36
+ ## Configuration
37
+
38
+ ```
39
+ cp /etc/foreman-proxy/settings.d/openscap.yml{.example,}
40
+ ```
41
+ Configure the following parameters so it would look like:
42
+
43
+ ```
44
+ ---
45
+ :enabled: true
46
+
47
+ # Log file for the forwarding script.
48
+ :openscap_send_log_file: /var/log/foreman-proxy/openscap-send.log
49
+
50
+ # Directory where OpenSCAP audits are stored
51
+ # before they are forwarded to Foreman
52
+ :spooldir: /var/spool/foreman-proxy/openscap
53
+
54
+ # Directory where OpenSCAP content XML are stored
55
+ # So we will not request the XML from Foreman each time
56
+ :contentdir: /var/lib/openscap/content
57
+ # Directory where OpenSCAP report XML are stored
58
+ # So Foreman can request arf xml reports
59
+ :reportsdir: /usr/share/foreman-proxy/openscap/content
60
+ ```
61
+
62
+ - Deploy
63
+
64
+ ```
65
+ ~# service foreman-proxy restart
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ![Openscap design](http://shlomizadok.github.io/foreman_openscap/static/images/reports_design.png)
71
+
72
+ ### Exposed APIs
73
+
74
+ * POST "/compliance/arf/:policy" - API to recieve ARF files, parse them and post to the Foreman. `:policy` is the policy ID from Foreman. expects ARF bzip2 file as POST body
75
+
76
+ * GET "/compliance/arf/:id/:cname/:date/:digest/xml" - API to download bizped2 ARF file. `:id` - ArfReport id, `:cname` - Host name, `:date` - Report date, `:digest` - Digest of the Arf file
77
+
78
+ * GET "/compliance/arf/:id/:cname/:date/:digest/html" - API to fetch full HTML report. `:id` - ArfReport id, `:cname` - Host name, `:date` - Report date, `:digest` - Digest of the Arf file
79
+
80
+ * GET "/compliance/policies/:policy_id/content" - API to download and serve SCAP content file for policy. `:policy_id` - Policy id from Foreman
81
+
82
+ * POST "/compliance/scap_content/policies" - API to extract policies from SCAP content. expects SCAP content posted as the POST body
83
+
84
+ * POST "/compliance/scap_content/validator" - API to validate SCAP content. expects SCAP content posted as the POST body
85
+
86
+ * POST "/compliance/scap_content/guide/:policy" - API to return Policy's HTML guide. `:policy` - policy name. expects SCAP content posted as the POST body
87
+
88
+ ### Binaries
89
+
90
+ * `smart_proxy_openscap_send` - Sends failed ARF files to Foreman (in case first try failed). When installed with RPM, a cron jobs is configured to run every 30 minutes.
91
+
92
+ ## Copyright
93
+
94
+ Copyright (c) 2014--2015 Red Hat, Inc.
95
+
96
+ This program is free software: you can redistribute it and/or modify
97
+ it under the terms of the GNU General Public License as published by
98
+ the Free Software Foundation, either version 3 of the License, or
99
+ (at your option) any later version.
100
+
101
+ This program is distributed in the hope that it will be useful,
102
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
103
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
104
+ GNU General Public License for more details.
105
+
106
+ You should have received a copy of the GNU General Public License
107
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,16 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Test the Smart Proxy OpenSCAP.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << '.'
12
+ t.libs << 'lib'
13
+ t.libs << 'test'
14
+ t.test_files = FileList['test/**/*_test.rb']
15
+ t.verbose = true
16
+ end
@@ -0,0 +1,7 @@
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_html'
6
+
7
+ Proxy::OpenSCAP::ArfHtml.new.generate_html ARGV[0], ARGV[1]
@@ -0,0 +1,7 @@
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]
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2014--2015 Red Hat Inc.
4
+ #
5
+ # This software is licensed to you under the GNU General Public License,
6
+ # version 3 (GPLv3). There is NO WARRANTY for this software, express or
7
+ # implied, including the implied warranties of MERCHANTABILITY or FITNESS
8
+ # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
9
+ # along with this software; if not, see http://www.gnu.org/licenses/gpl.txt
10
+ #
11
+
12
+ $LOAD_PATH.unshift '/usr/share/foreman-proxy/lib'
13
+ $LOAD_PATH.unshift '/usr/share/foreman-proxy/modules'
14
+
15
+ require 'smart_proxy'
16
+ require 'smart_proxy_main'
17
+ require 'smart_proxy_openscap'
18
+ require 'smart_proxy_openscap/openscap_lib'
19
+
20
+ loaded_settings = Proxy::OpenSCAP.plugin_settings
21
+
22
+ # Don't run if OpenSCAP plugin is disabled or settings are missing.
23
+ if !loaded_settings.enabled || loaded_settings.nil? || loaded_settings.empty?
24
+ exit 436
25
+ end
26
+
27
+ module Proxy
28
+ module Log
29
+ @@logger = ::Logger.new(Proxy::OpenSCAP.fullpath(Proxy::OpenSCAP.plugin_settings.openscap_send_log_file), 6, 1024*1024*10)
30
+ @@logger.level = ::Logger.const_get(Proxy::SETTINGS.log_level.upcase)
31
+ end
32
+ end
33
+ include Proxy::Log
34
+
35
+ if !Proxy::SETTINGS.foreman_url
36
+ logger.error "Foreman URL not configured"
37
+ exit 437
38
+ end
39
+
40
+ lockfile = File.join(loaded_settings.spooldir, "spool.lock")
41
+
42
+ Signal.trap("TERM") {
43
+ FileUtils.rm(lockfile) if File.exist?(lockfile)
44
+ exit
45
+ }
46
+
47
+ if File.exist? lockfile
48
+ logger.debug "Lock file #{lockfile} for openscap spool exists, not sending spool to server"
49
+ exit
50
+ end
51
+
52
+ begin
53
+ FileUtils.touch lockfile
54
+ Proxy::OpenSCAP::send_spool_to_foreman(loaded_settings)
55
+ rescue StandardError => e
56
+ logger.error e
57
+ puts "#{e} See #{Proxy::OpenSCAP.fullpath(loaded_settings.openscap_send_log_file)}"
58
+ exit 438
59
+ ensure
60
+ FileUtils.rm lockfile
61
+ end
@@ -0,0 +1,7 @@
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/policy_guide'
6
+
7
+ Proxy::OpenSCAP::PolicyGuide.new.generate_guide *ARGV
@@ -0,0 +1,7 @@
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]
@@ -0,0 +1,7 @@
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]
@@ -0,0 +1,6 @@
1
+ # Drop this file into bundler.d/ in foreman-proxy root
2
+ gem 'smart_proxy_openscap'
3
+
4
+ group :openscap do
5
+ # plugin dependencies go here
6
+ end
@@ -0,0 +1,101 @@
1
+ %global gem_name smart_proxy_openscap
2
+
3
+ %global foreman_proxy_bundlerd_dir /usr/share/foreman-proxy/bundler.d
4
+ %global foreman_proxy_pluginconf_dir /etc/foreman-proxy/settings.d
5
+ %global spool_dir /var/spool/foreman-proxy/openscap
6
+ %global proxy_user foreman-proxy
7
+
8
+ Name: rubygem-%{gem_name}
9
+ Version: 0.3.0
10
+ Release: 1%{?dist}
11
+ Summary: OpenSCAP plug-in for Foreman's smart-proxy.
12
+ Group: Applications/Internet
13
+ License: GPLv2+
14
+ URL: http://github.com/openscap/smart_proxy_openscap
15
+ Source0: https://rubygems.org/gems/%{gem_name}-%{version}.gem
16
+ #Requires: ruby(release)
17
+ Requires: ruby(rubygems)
18
+ Requires: foreman-proxy >= 1.7.0-0.develop.201410221520
19
+ Requires: crontabs
20
+ #BuildRequires: ruby(release)
21
+ BuildRequires: rubygems-devel
22
+ BuildRequires: ruby
23
+ BuildArch: noarch
24
+ Provides: rubygem(%{gem_name}) = %{version}
25
+ Obsoletes: rubygem-foreman-proxy_openscap
26
+
27
+ %description
28
+ A plug-in to the Foreman's smart-proxy which receives bzip2ed ARF files
29
+ and forwards them to the Foreman.
30
+
31
+ %prep
32
+ gem unpack %{SOURCE0}
33
+ %setup -q -D -T -n %{gem_name}-%{version}
34
+ gem spec %{SOURCE0} -l --ruby > %{gem_name}.gemspec
35
+
36
+ %build
37
+ # Create the gem as gem install only works on a gem file
38
+ gem build %{gem_name}.gemspec
39
+
40
+ # %%gem_install compiles any C extensions and installs the gem into ./%gem_dir
41
+ # by default, so that we can move it into the buildroot in %%install
42
+ %gem_install
43
+
44
+ %install
45
+ mkdir -p %{buildroot}%{gem_dir}
46
+ cp -a .%{gem_dir}/* \
47
+ %{buildroot}%{gem_dir}/
48
+ mv %{buildroot}%{gem_instdir}/%{gem_name}.gemspec %{buildroot}/%{gem_spec}
49
+ rm %{buildroot}%{gem_instdir}/extra/*.spec # this specfile
50
+
51
+ # executables
52
+ mkdir -p %{buildroot}%{_bindir}
53
+ mv %{buildroot}%{gem_instdir}/bin/* \
54
+ %{buildroot}%{_bindir}
55
+
56
+ # bundler file
57
+ mkdir -p %{buildroot}%{foreman_proxy_bundlerd_dir}
58
+ mv %{buildroot}%{gem_instdir}/bundler.d/openscap.rb \
59
+ %{buildroot}%{foreman_proxy_bundlerd_dir}
60
+
61
+ # sample config
62
+ mkdir -p %{buildroot}%{foreman_proxy_pluginconf_dir}
63
+ mv %{buildroot}%{gem_instdir}/settings.d/openscap.yml.example \
64
+ %{buildroot}%{foreman_proxy_pluginconf_dir}/
65
+
66
+ # crontab
67
+ mkdir -p %{buildroot}%{_sysconfdir}/cron.d/
68
+ mv %{buildroot}%{gem_instdir}/extra/smart-proxy-openscap-send.cron \
69
+ %{buildroot}%{_sysconfdir}/cron.d/%{name}
70
+
71
+ # create spool directory
72
+ mkdir -p %{buildroot}%{spool_dir}
73
+
74
+ %files
75
+ %dir %{gem_instdir}
76
+ %{gem_libdir}
77
+ %exclude %{gem_cache}
78
+ %{gem_spec}
79
+
80
+ %attr(-,%{proxy_user},%{proxy_user}) %{spool_dir}
81
+ %{foreman_proxy_bundlerd_dir}/openscap.rb
82
+ %{_bindir}/smart-proxy-openscap-send
83
+ %doc %{foreman_proxy_pluginconf_dir}/openscap.yml.example
84
+ %config(noreplace) %attr(0644, root, root) %{_sysconfdir}/cron.d/%{name}
85
+
86
+ %{gem_docdir}
87
+ %{gem_instdir}/README.md
88
+ %{gem_instdir}/COPYING
89
+
90
+ %changelog
91
+ * Tue Jan 20 2015 Šimon Lukašík <slukasik@redhat.com> - 0.3.0-1
92
+ - new upstream release
93
+
94
+ * Tue Jan 20 2015 Šimon Lukašík <slukasik@redhat.com> - 0.1.0-2
95
+ - renamed to smart_proxy_openscap
96
+
97
+ * Fri Oct 24 2014 Šimon Lukašík <slukasik@redhat.com> - 0.1.0-1
98
+ - rebuilt
99
+
100
+ * Fri Jul 18 2014 Šimon Lukašík <slukasik@redhat.com> - 0.0.1-1
101
+ - Initial package
@@ -0,0 +1,2 @@
1
+ # Send all collected OpenSCAP reports once every 30 minutes
2
+ */30 * * * * foreman-proxy smart-proxy-openscap-send >> /var/log/foreman-proxy/cron.log
@@ -0,0 +1,14 @@
1
+ #
2
+ # Copyright (c) 2014 Red Hat Inc.
3
+ #
4
+ # This software is licensed to you under the GNU General Public License,
5
+ # version 3 (GPLv3). There is NO WARRANTY for this software, express or
6
+ # implied, including the implied warranties of MERCHANTABILITY or FITNESS
7
+ # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
8
+ # along with this software; if not, see http://www.gnu.org/licenses/gpl.txt
9
+ #
10
+
11
+ require 'smart_proxy_openscap/openscap_plugin'
12
+
13
+ module Proxy::OpenSCAP
14
+ end
@@ -0,0 +1,22 @@
1
+ require 'openscap'
2
+ require 'openscap/ds/arf'
3
+
4
+ module Proxy
5
+ module OpenSCAP
6
+ class ArfHtml
7
+ def generate_html(file_in, file_out)
8
+ ::OpenSCAP.oscap_init
9
+ File.write file_out, get_arf_html(file_in)
10
+ ensure
11
+ ::OpenSCAP.oscap_cleanup
12
+ end
13
+
14
+ def get_arf_html(file_in)
15
+ arf_object = ::OpenSCAP::DS::Arf.new(file_in)
16
+ # @TODO: Drop this when support for 1.8.7 ends
17
+ return arf_object.html if RUBY_VERSION.start_with? '1.8'
18
+ arf_object.html.force_encoding('UTF-8')
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,114 @@
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