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