smart_proxy_openscap 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +41 -0
- data/.rubocop_todo.yml +111 -0
- data/.travis.yml +14 -0
- data/COPYING +674 -0
- data/Gemfile +14 -0
- data/README.md +107 -0
- data/Rakefile +16 -0
- data/bin/smart-proxy-arf-html +7 -0
- data/bin/smart-proxy-arf-json +7 -0
- data/bin/smart-proxy-openscap-send +61 -0
- data/bin/smart-proxy-policy-guide +7 -0
- data/bin/smart-proxy-scap-profiles +7 -0
- data/bin/smart-proxy-scap-validation +7 -0
- data/bundler.d/openscap.rb +6 -0
- data/extra/rubygem-smart_proxy_openscap.spec +101 -0
- data/extra/smart-proxy-openscap-send.cron +2 -0
- data/lib/smart_proxy_openscap.rb +14 -0
- data/lib/smart_proxy_openscap/arf_html.rb +22 -0
- data/lib/smart_proxy_openscap/arf_json.rb +114 -0
- data/lib/smart_proxy_openscap/arf_parser.rb +39 -0
- data/lib/smart_proxy_openscap/content_parser.rb +30 -0
- data/lib/smart_proxy_openscap/fetch_file.rb +60 -0
- data/lib/smart_proxy_openscap/fetch_scap_content.rb +17 -0
- data/lib/smart_proxy_openscap/fetch_tailoring_file.rb +17 -0
- data/lib/smart_proxy_openscap/foreman_forwarder.rb +40 -0
- data/lib/smart_proxy_openscap/http_config.ru +20 -0
- data/lib/smart_proxy_openscap/openscap_api.rb +187 -0
- data/lib/smart_proxy_openscap/openscap_exception.rb +9 -0
- data/lib/smart_proxy_openscap/openscap_html_generator.rb +38 -0
- data/lib/smart_proxy_openscap/openscap_import_api.rb +32 -0
- data/lib/smart_proxy_openscap/openscap_lib.rb +67 -0
- data/lib/smart_proxy_openscap/openscap_plugin.rb +27 -0
- data/lib/smart_proxy_openscap/policy_guide.rb +23 -0
- data/lib/smart_proxy_openscap/policy_parser.rb +33 -0
- data/lib/smart_proxy_openscap/profiles_parser.rb +32 -0
- data/lib/smart_proxy_openscap/scap_profiles.rb +52 -0
- data/lib/smart_proxy_openscap/scap_validation.rb +35 -0
- data/lib/smart_proxy_openscap/shell_wrapper.rb +77 -0
- data/lib/smart_proxy_openscap/spool_forwarder.rb +79 -0
- data/lib/smart_proxy_openscap/storage.rb +47 -0
- data/lib/smart_proxy_openscap/storage_fs.rb +102 -0
- data/lib/smart_proxy_openscap/version.rb +15 -0
- data/settings.d/openscap.yml.example +33 -0
- data/smart_proxy_openscap.gemspec +23 -0
- data/test/data/arf_report +0 -0
- data/test/data/corrupted_arf_report +0 -0
- data/test/data/spool/cleanup_spool/arf/2c101b95-033f-4b15-b490-f50bf9090dae/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
- data/test/data/spool/cleanup_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
- data/test/data/spool/corrupted_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/a4dfba5db27b21795e6fa401b8dce7a70faeb25b7963891f07f6f4baaf052afb +0 -0
- data/test/data/spool/corrupted_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
- data/test/data/spool/valid_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
- data/test/data/spool/valid_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1 +0 -0
- data/test/data/ssg-rhel7-ds.xml +20271 -0
- data/test/data/tailoring.xml +31 -0
- data/test/fetch_scap_api_test.rb +73 -0
- data/test/fetch_tailoring_api_test.rb +37 -0
- data/test/get_report_xml_html_test.rb +58 -0
- data/test/post_report_api_test.rb +86 -0
- data/test/scap_content_parser_api_test.rb +69 -0
- data/test/script_class_test.rb +96 -0
- data/test/spool_forwarder_test.rb +84 -0
- data/test/test_helper.rb +13 -0
- 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)
|
data/README.md
ADDED
@@ -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/>.
|
data/Rakefile
ADDED
@@ -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,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,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,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
|