smart_proxy_openscap 0.6.4 → 0.6.5
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/Gemfile +1 -0
- data/bin/smart-proxy-parse-arf +7 -0
- data/lib/smart_proxy_openscap/arf_parser.rb +111 -0
- data/lib/smart_proxy_openscap/foreman_forwarder.rb +3 -7
- data/lib/smart_proxy_openscap/openscap_content_parser.rb +0 -2
- data/lib/smart_proxy_openscap/openscap_initializer.rb +21 -0
- data/lib/smart_proxy_openscap/openscap_plugin.rb +6 -0
- data/lib/smart_proxy_openscap/openscap_report_parser.rb +38 -101
- data/lib/smart_proxy_openscap/plugin_configuration.rb +13 -0
- data/lib/smart_proxy_openscap/storage_fs.rb +0 -1
- data/lib/smart_proxy_openscap/version.rb +1 -1
- data/test/get_report_xml_html_test.rb +2 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e666336bf02a0dc32630813e523d0af008006603
|
4
|
+
data.tar.gz: e5fbd577be166d0b2ca4d79841c7753a7b958577
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76bfca9428e45706fcd289da3dabea7c145c540a1a58bcce5a9ecdd016cabaf4192b1b563035cf142deeb97f5058b69b0e332bbbdfb28d7cda8b746dbd6b8b04
|
7
|
+
data.tar.gz: 021058331dd2a2ebd832e0ea59c58021cfa8a22fc3b36265ae5743a7d8a7478ed6793d614e0033d4374d6a601d14a57e91779bbec4dc59cc071cb6e60f94e441
|
data/Gemfile
CHANGED
@@ -0,0 +1,111 @@
|
|
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 ArfParser
|
15
|
+
def parse(file_in, file_out)
|
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
|
+
File.write file_out, report.to_json
|
30
|
+
ensure
|
31
|
+
cleanup test_result, benchmark, sds, arf
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def parse_results(items, results, arf_digest)
|
37
|
+
report = {}
|
38
|
+
report[:logs] = []
|
39
|
+
passed = 0
|
40
|
+
failed = 0
|
41
|
+
othered = 0
|
42
|
+
results.each do |rr_id, result|
|
43
|
+
next if result.result == 'notapplicable' || result.result == 'notselected'
|
44
|
+
# get rules and their results
|
45
|
+
rule_data = items[rr_id]
|
46
|
+
report[:logs] << populate_result_data(rr_id, result.result, rule_data)
|
47
|
+
# create metrics for the results
|
48
|
+
case result.result
|
49
|
+
when 'pass', 'fixed'
|
50
|
+
passed += 1
|
51
|
+
when 'fail'
|
52
|
+
failed += 1
|
53
|
+
else
|
54
|
+
othered += 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
report[:digest] = arf_digest
|
58
|
+
report[:metrics] = { :passed => passed, :failed => failed, :othered => othered }
|
59
|
+
report
|
60
|
+
end
|
61
|
+
|
62
|
+
def populate_result_data(result_id, rule_result, rule_data)
|
63
|
+
log = {}
|
64
|
+
log[:source] = ascii8bit_to_utf8(result_id)
|
65
|
+
log[:result] = ascii8bit_to_utf8(rule_result)
|
66
|
+
log[:title] = ascii8bit_to_utf8(rule_data.title)
|
67
|
+
log[:description] = ascii8bit_to_utf8(rule_data.description)
|
68
|
+
log[:rationale] = ascii8bit_to_utf8(rule_data.rationale)
|
69
|
+
log[:references] = hash_a8b(rule_data.references.map(&:to_hash))
|
70
|
+
log[:fixes] = hash_a8b(rule_data.fixes.map(&:to_hash))
|
71
|
+
log[:severity] = ascii8bit_to_utf8(rule_data.severity)
|
72
|
+
log
|
73
|
+
end
|
74
|
+
|
75
|
+
def cleanup(*args)
|
76
|
+
args.compact.map(&:destroy)
|
77
|
+
::OpenSCAP.oscap_cleanup
|
78
|
+
end
|
79
|
+
|
80
|
+
# Unfortunately openscap in ruby 1.9.3 outputs data in Ascii-8bit.
|
81
|
+
# We transform it to UTF-8 for easier json integration.
|
82
|
+
|
83
|
+
# :invalid ::
|
84
|
+
# If the value is invalid, #encode replaces invalid byte sequences in
|
85
|
+
# +str+ with the replacement character. The default is to raise the
|
86
|
+
# Encoding::InvalidByteSequenceError exception
|
87
|
+
# :undef ::
|
88
|
+
# If the value is undefined, #encode replaces characters which are
|
89
|
+
# undefined in the destination encoding with the replacement character.
|
90
|
+
# The default is to raise the Encoding::UndefinedConversionError.
|
91
|
+
# :replace ::
|
92
|
+
# Sets the replacement string to the given value. The default replacement
|
93
|
+
# string is "\uFFFD" for Unicode encoding forms, and "?" otherwise.
|
94
|
+
def ascii8bit_to_utf8(string)
|
95
|
+
return ascii8bit_to_utf8_legacy(string) if RUBY_VERSION.start_with? '1.8'
|
96
|
+
string.to_s.encode('utf-8', :invalid => :replace, :undef => :replace, :replace => '_')
|
97
|
+
end
|
98
|
+
|
99
|
+
# String#encode appeared first in 1.9, so we need a workaround for 1.8
|
100
|
+
def ascii8bit_to_utf8_legacy(string)
|
101
|
+
Iconv.conv('UTF-8//IGNORE', 'UTF-8', string.to_s)
|
102
|
+
end
|
103
|
+
|
104
|
+
def hash_a8b(ary)
|
105
|
+
ary.map do |hash|
|
106
|
+
Hash[hash.map { |key, value| [ascii8bit_to_utf8(key), ascii8bit_to_utf8(value)] }]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -3,23 +3,19 @@ module Proxy::OpenSCAP
|
|
3
3
|
include ::Proxy::Log
|
4
4
|
|
5
5
|
def post_arf_report(cname, policy_id, date, data)
|
6
|
-
parser = Proxy::OpenSCAP::Parse.new(data)
|
7
6
|
begin
|
8
7
|
foreman_api_path = upload_path(cname, policy_id, date)
|
9
|
-
|
8
|
+
json = Proxy::OpenSCAP::Parse.new(cname, policy_id, date).as_json(data)
|
9
|
+
raise OpenSCAP::OpenSCAPError, "Failed to parse report" if json.nil? || json.empty?
|
10
|
+
response = send_request(foreman_api_path, json)
|
10
11
|
# Raise an HTTP error if the response is not 2xx (success).
|
11
12
|
response.value
|
12
13
|
res = JSON.parse(response.body)
|
13
14
|
raise StandardError, "Received response: #{response.code} #{response.msg}" unless res['result'] == 'OK'
|
14
|
-
rescue OpenSCAP::OpenSCAPError => e
|
15
|
-
logger.debug e.backtrace.join("\n\t")
|
16
|
-
raise e
|
17
15
|
rescue StandardError => e
|
18
16
|
logger.debug response.body if response
|
19
17
|
logger.debug e.backtrace.join("\n\t")
|
20
18
|
raise e
|
21
|
-
ensure
|
22
|
-
parser.cleanup
|
23
19
|
end
|
24
20
|
res
|
25
21
|
end
|
@@ -6,14 +6,12 @@ require 'openscap/xccdf/tailoring'
|
|
6
6
|
module Proxy::OpenSCAP
|
7
7
|
class ContentParser
|
8
8
|
def initialize(scap_file, type = 'scap_content')
|
9
|
-
OpenSCAP.oscap_init
|
10
9
|
@source = OpenSCAP::Source.new(:content => scap_file)
|
11
10
|
@type = type
|
12
11
|
end
|
13
12
|
|
14
13
|
def cleanup
|
15
14
|
@source.destroy if @source
|
16
|
-
OpenSCAP.oscap_cleanup
|
17
15
|
end
|
18
16
|
|
19
17
|
def allowed_types
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'openscap'
|
2
|
+
|
3
|
+
module Proxy::OpenSCAP
|
4
|
+
class OpenscapInitializer
|
5
|
+
include ::Proxy::Log
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@mutex = Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def start
|
12
|
+
logger.debug "Initializing openscap component"
|
13
|
+
@mutex.synchronize { OpenSCAP.oscap_init }
|
14
|
+
end
|
15
|
+
|
16
|
+
def stop
|
17
|
+
logger.debug "Stopping openscap component"
|
18
|
+
@mutex.synchronize { OpenSCAP.oscap_cleanup }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -9,6 +9,7 @@
|
|
9
9
|
#
|
10
10
|
|
11
11
|
require 'smart_proxy_openscap/version'
|
12
|
+
require 'smart_proxy_openscap/plugin_configuration'
|
12
13
|
|
13
14
|
module Proxy::OpenSCAP
|
14
15
|
class Plugin < ::Proxy::Plugin
|
@@ -23,5 +24,10 @@ module Proxy::OpenSCAP
|
|
23
24
|
:reportsdir => File.join(APP_ROOT, 'openscap/reports'),
|
24
25
|
:failed_dir => File.join(APP_ROOT, 'openscap/failed'),
|
25
26
|
:tailoring_dir => File.join(APP_ROOT, 'openscap/tailoring')
|
27
|
+
|
28
|
+
load_classes ::Proxy::OpenSCAP::PluginConfiguration
|
29
|
+
load_dependency_injection_wirings ::Proxy::OpenSCAP::PluginConfiguration
|
30
|
+
|
31
|
+
start_services :openscap_initializer
|
26
32
|
end
|
27
33
|
end
|
@@ -1,110 +1,47 @@
|
|
1
1
|
# encoding=utf-8
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
OpenSCAP.oscap_init
|
16
|
-
size = arf_data.size
|
17
|
-
@arf_digest = Digest::SHA256.hexdigest(arf_data)
|
18
|
-
@arf = OpenSCAP::DS::Arf.new(:content => arf_data, :path => 'arf.xml.bz2', :length => size)
|
19
|
-
@test_result = @arf.test_result
|
20
|
-
|
21
|
-
@results = @test_result.rr
|
22
|
-
@sds = @arf.report_request
|
23
|
-
bench_source = @sds.select_checklist!
|
24
|
-
@benchmark = OpenSCAP::Xccdf::Benchmark.new(bench_source)
|
25
|
-
@items = @benchmark.items
|
26
|
-
end
|
27
|
-
|
28
|
-
def cleanup
|
29
|
-
@test_result.destroy if @test_result
|
30
|
-
@benchmark.destroy if @benchmark
|
31
|
-
@sds.destroy if @sds
|
32
|
-
@arf.destroy if @arf
|
33
|
-
OpenSCAP.oscap_cleanup
|
34
|
-
end
|
35
|
-
|
36
|
-
def as_json
|
37
|
-
parse_report.to_json
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module Proxy
|
5
|
+
module OpenSCAP
|
6
|
+
class Parse
|
7
|
+
include ::Proxy::Log
|
8
|
+
include ::Proxy::Util
|
9
|
+
|
10
|
+
def initialize(cname, policy_id, date)
|
11
|
+
@cname = cname
|
12
|
+
@policy_id = policy_id
|
13
|
+
@date = date
|
14
|
+
end
|
41
15
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
othered += 1
|
16
|
+
def as_json(arf_data)
|
17
|
+
in_file = Tempfile.new("#{filename}json-", "/var/tmp")
|
18
|
+
json_file = Tempfile.new(filename, "/var/tmp")
|
19
|
+
begin
|
20
|
+
in_file.write arf_data
|
21
|
+
command = "#{script_location} #{in_file.path} #{json_file.path}"
|
22
|
+
logger.debug "Executing: #{command}"
|
23
|
+
`#{command}`
|
24
|
+
json_file.read
|
25
|
+
rescue => e
|
26
|
+
logger.debug "Failure when running script which parses reports"
|
27
|
+
logger.debug e.backtrace.join("\n\t")
|
28
|
+
return nil
|
29
|
+
ensure
|
30
|
+
in_file.close
|
31
|
+
in_file.unlink
|
32
|
+
json_file.close
|
33
|
+
json_file.unlink
|
61
34
|
end
|
62
35
|
end
|
63
|
-
report[:digest] = @arf_digest
|
64
|
-
report[:metrics] = { :passed => passed, :failed => failed, :othered => othered }
|
65
|
-
report
|
66
|
-
end
|
67
|
-
|
68
|
-
def populate_result_data(result_id, rule_result, rule_data)
|
69
|
-
log = {}
|
70
|
-
log[:source] = ascii8bit_to_utf8(result_id)
|
71
|
-
log[:result] = ascii8bit_to_utf8(rule_result)
|
72
|
-
log[:title] = ascii8bit_to_utf8(rule_data.title)
|
73
|
-
log[:description] = ascii8bit_to_utf8(rule_data.description)
|
74
|
-
log[:rationale] = ascii8bit_to_utf8(rule_data.rationale)
|
75
|
-
log[:references] = hash_a8b(rule_data.references.map(&:to_hash))
|
76
|
-
log[:fixes] = hash_a8b(rule_data.fixes.map(&:to_hash))
|
77
|
-
log[:severity] = ascii8bit_to_utf8(rule_data.severity)
|
78
|
-
log
|
79
|
-
end
|
80
|
-
|
81
|
-
# Unfortunately openscap in ruby 1.9.3 outputs data in Ascii-8bit.
|
82
|
-
# We transform it to UTF-8 for easier json integration.
|
83
36
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
# Encoding::InvalidByteSequenceError exception
|
88
|
-
# :undef ::
|
89
|
-
# If the value is undefined, #encode replaces characters which are
|
90
|
-
# undefined in the destination encoding with the replacement character.
|
91
|
-
# The default is to raise the Encoding::UndefinedConversionError.
|
92
|
-
# :replace ::
|
93
|
-
# Sets the replacement string to the given value. The default replacement
|
94
|
-
# string is "\uFFFD" for Unicode encoding forms, and "?" otherwise.
|
95
|
-
def ascii8bit_to_utf8(string)
|
96
|
-
return ascii8bit_to_utf8_legacy(string) if RUBY_VERSION.start_with? '1.8'
|
97
|
-
string.to_s.encode('utf-8', :invalid => :replace, :undef => :replace, :replace => '_')
|
98
|
-
end
|
99
|
-
|
100
|
-
# String#encode appeared first in 1.9, so we need a workaround for 1.8
|
101
|
-
def ascii8bit_to_utf8_legacy(string)
|
102
|
-
Iconv.conv('UTF-8//IGNORE', 'UTF-8', string.to_s)
|
103
|
-
end
|
37
|
+
def filename
|
38
|
+
"#{@cname}-#{@policy_id}-#{@date}-"
|
39
|
+
end
|
104
40
|
|
105
|
-
|
106
|
-
|
107
|
-
|
41
|
+
def script_location
|
42
|
+
path = File.join(File.dirname(File.expand_path(__FILE__)), '../..','bin/smart-proxy-parse-arf')
|
43
|
+
return path if File.exist? path
|
44
|
+
"smart-proxy-parse-arf"
|
108
45
|
end
|
109
46
|
end
|
110
47
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Proxy::OpenSCAP
|
2
|
+
class PluginConfiguration
|
3
|
+
def load_dependency_injection_wirings(container, settings)
|
4
|
+
container.singleton_dependency :openscap_initializer, ( lambda do
|
5
|
+
::Proxy::OpenSCAP::OpenscapInitializer.new
|
6
|
+
end)
|
7
|
+
end
|
8
|
+
|
9
|
+
def load_classes
|
10
|
+
require 'smart_proxy_openscap/openscap_initializer'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -39,7 +39,9 @@ class OpenSCAPGetArfTest < Test::Unit::TestCase
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_get_html_arf
|
42
|
+
OpenSCAP.oscap_init
|
42
43
|
get "/arf/#{@arf_id}/#{@cname}/#{@date}/#{@filename}/html"
|
44
|
+
OpenSCAP.oscap_cleanup
|
43
45
|
assert(last_response.successful?, "Should return OK")
|
44
46
|
assert(last_response.body.start_with?('<!DOCTYPE'), 'File should start with html')
|
45
47
|
end
|
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.6.
|
4
|
+
version: 0.6.5
|
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: 2017-
|
13
|
+
date: 2017-07-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
@@ -98,10 +98,12 @@ files:
|
|
98
98
|
- README.md
|
99
99
|
- Rakefile
|
100
100
|
- bin/smart-proxy-openscap-send
|
101
|
+
- bin/smart-proxy-parse-arf
|
101
102
|
- bundler.d/openscap.rb
|
102
103
|
- extra/rubygem-smart_proxy_openscap.spec
|
103
104
|
- extra/smart-proxy-openscap-send.cron
|
104
105
|
- lib/smart_proxy_openscap.rb
|
106
|
+
- lib/smart_proxy_openscap/arf_parser.rb
|
105
107
|
- lib/smart_proxy_openscap/fetch_file.rb
|
106
108
|
- lib/smart_proxy_openscap/fetch_scap_content.rb
|
107
109
|
- lib/smart_proxy_openscap/fetch_tailoring_file.rb
|
@@ -111,9 +113,11 @@ files:
|
|
111
113
|
- lib/smart_proxy_openscap/openscap_content_parser.rb
|
112
114
|
- lib/smart_proxy_openscap/openscap_exception.rb
|
113
115
|
- lib/smart_proxy_openscap/openscap_import_api.rb
|
116
|
+
- lib/smart_proxy_openscap/openscap_initializer.rb
|
114
117
|
- lib/smart_proxy_openscap/openscap_lib.rb
|
115
118
|
- lib/smart_proxy_openscap/openscap_plugin.rb
|
116
119
|
- lib/smart_proxy_openscap/openscap_report_parser.rb
|
120
|
+
- lib/smart_proxy_openscap/plugin_configuration.rb
|
117
121
|
- lib/smart_proxy_openscap/spool_forwarder.rb
|
118
122
|
- lib/smart_proxy_openscap/storage.rb
|
119
123
|
- lib/smart_proxy_openscap/storage_fs.rb
|
@@ -157,8 +161,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
161
|
version: '0'
|
158
162
|
requirements: []
|
159
163
|
rubyforge_project:
|
160
|
-
rubygems_version: 2.4.
|
164
|
+
rubygems_version: 2.4.6
|
161
165
|
signing_key:
|
162
166
|
specification_version: 4
|
163
167
|
summary: OpenSCAP plug-in for Foreman's smart-proxy.
|
164
168
|
test_files: []
|
169
|
+
has_rdoc:
|