smart_proxy_openscap 0.8.1 → 0.9.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: 57a129c56c494eaf735088a59fedaaeddd7a0af1c8e4aed8424e76c94415e515
4
- data.tar.gz: 9e9b31ccd266403eae40237a47ab8852b1799ea520684a4facbc2229595e4566
3
+ metadata.gz: b4d1a52c4299cb9828c2cb492622a4cc13f9cd3d234fc6a9940dc9768840761b
4
+ data.tar.gz: bfa0d9e1444579127bec7bf5f32fe37d73577c99ab803dfd07b59c0ed6f1e15a
5
5
  SHA512:
6
- metadata.gz: dc046f2f2ff1d9f78a0bffbadb1c671b731e5ac0457eff5620d01dde5cf0a299cc0b0ba475abc02e70e64ad919edf721610a9c010aade74ff54ab0ff574241dd
7
- data.tar.gz: 20c7e65b5452fb3f1b5107e90522b7403c4ed00c2564969f85858a0ddaab14cc57aa41bd31de4e968dbee52e8756ec30c2f1c01ad19248b15d69f76db6df20c8
6
+ metadata.gz: 49c8ece151fb60cdf31a3c396b22df455d3f653648640f5e6d05505c67c386128bf09970bd9d08b82e94710d493c3ba8dd003d47d584e05819204cd32987ffc3
7
+ data.tar.gz: 18acfdafceecc4845da3fce3703f7e670d0c991ddda0d6cb542c00ccb6d399cd4090b63cf44dbeb2fef5aa99cfa0fb7710a2a54cf5b6d4b1678f98b70d01678b
@@ -0,0 +1,45 @@
1
+ require 'smart_proxy_openscap/fetch_file'
2
+
3
+ module Proxy::OpenSCAP
4
+ class FetchScapFile < FetchFile
5
+ def initialize(type)
6
+ raise "Expected one of the following symbols: #{allowed_types.join(', ')}, got: #{type}" unless allowed_types.include? type
7
+ @type = type
8
+ end
9
+
10
+ def fetch(policy_id, digest, content_dir)
11
+ store_dir = File.join(Proxy::OpenSCAP.fullpath(content_dir), policy_id.to_s)
12
+ scap_file = File.join(store_dir, file_name(policy_id, digest))
13
+
14
+ file_download_path = download_path.sub(':policy_id', policy_id)
15
+ create_store_dir store_dir
16
+ file = policy_content_file scap_file
17
+ clean_store_folder store_dir unless file
18
+ file ||= save_or_serve_scap_file scap_file, file_download_path
19
+ end
20
+
21
+ def download_path
22
+ case @type
23
+ when :scap_content
24
+ "api/v2/compliance/policies/:policy_id/content"
25
+ when :tailoring_file
26
+ "api/v2/compliance/policies/:policy_id/tailoring"
27
+ when :oval_content
28
+ "api/v2/compliance/oval_policies/:policy_id/oval_content"
29
+ end
30
+ end
31
+
32
+ def file_name(policy_id, digest)
33
+ case @type
34
+ when :scap_content, :tailoring_file
35
+ "#{policy_id}_#{digest}.xml"
36
+ when :oval_content
37
+ "#{digest}.oval.xml.bz2"
38
+ end
39
+ end
40
+
41
+ def allowed_types
42
+ [:scap_content, :tailoring_file, :oval_content]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,15 @@
1
+ require 'smart_proxy_openscap/foreman_forwarder'
2
+
3
+ module Proxy::OpenSCAP
4
+ class ForemanArfForwarder < ForemanForwarder
5
+ private
6
+
7
+ def parse_report(cname, policy_id, date, report_data)
8
+ Proxy::OpenSCAP::ArfParser.new(cname, policy_id, date).as_json(report_data)
9
+ end
10
+
11
+ def report_upload_path(cname, policy_id, date)
12
+ upload_path "arf_reports", cname, policy_id, date
13
+ end
14
+ end
15
+ end
@@ -4,26 +4,29 @@ module Proxy::OpenSCAP
4
4
  class ForemanForwarder < Proxy::HttpRequest::ForemanRequest
5
5
  include ::Proxy::Log
6
6
 
7
- def post_arf_report(cname, policy_id, date, data, timeout)
8
- begin
9
- foreman_api_path = upload_path(cname, policy_id, date)
10
- json = Proxy::OpenSCAP::ArfParser.new(cname, policy_id, date).as_json(data)
11
- response = send_request(foreman_api_path, json, timeout)
12
- # Raise an HTTP error if the response is not 2xx (success).
13
- response.value
14
- JSON.parse(response.body)
15
- rescue Net::HTTPServerException => e
16
- logger.debug "Received response: #{response.code} #{response.msg}"
17
- logger.debug response.body
18
- raise ReportUploadError, e.message if response.code.to_i == 422
19
- raise e
20
- end
7
+ def post_report(cname, policy_id, date, data, timeout)
8
+ foreman_api_path = report_upload_path(cname, policy_id, date)
9
+
10
+ json = parse_report(cname, policy_id, date, data)
11
+ response = send_request(foreman_api_path, json, timeout)
12
+ # Raise an HTTP error if the response is not 2xx (success).
13
+ response.value
14
+ JSON.parse(response.body)
15
+ rescue Net::HTTPServerException => e
16
+ logger.debug "Received response: #{response.code} #{response.msg}"
17
+ logger.debug response.body
18
+ raise ReportUploadError, e.message if response.code.to_i == 422
19
+ raise e
21
20
  end
22
21
 
23
22
  private
24
23
 
25
- def upload_path(cname, policy_id, date)
26
- "/api/v2/compliance/arf_reports/#{cname}/#{policy_id}/#{date}"
24
+ def upload_path(resource, cname, policy_id, date)
25
+ "/api/v2/compliance/#{resource}/#{cname}/#{policy_id}/#{date}"
26
+ end
27
+
28
+ def parse_report(cname, policy_id, date, data)
29
+ raise NotImplementedError
27
30
  end
28
31
 
29
32
  def send_request(path, body, timeout)
@@ -0,0 +1,19 @@
1
+ require 'smart_proxy_openscap/foreman_forwarder'
2
+
3
+ module Proxy::OpenSCAP
4
+ class ForemanOvalForwarder < ForemanForwarder
5
+ private
6
+
7
+ def parse_report(cname, policy_id, date, report_data)
8
+ {
9
+ :oval_results => OvalReportParser.new.parse_cves(report_data),
10
+ :oval_policy_id => policy_id,
11
+ :cname => cname
12
+ }.to_json
13
+ end
14
+
15
+ def report_upload_path(cname, policy_id, date)
16
+ upload_path "oval_reports", cname, policy_id, date
17
+ end
18
+ end
19
+ end
@@ -33,35 +33,37 @@ module Proxy::OpenSCAP
33
33
  do_authorize_with_trusted_hosts
34
34
  end
35
35
 
36
- post "/arf/:policy" do
37
- # first let's verify client's certificate
36
+ before '(/arf/*|/oval_reports/*)' do
38
37
  begin
39
- cn = Proxy::OpenSCAP::common_name request
38
+ @cn = Proxy::OpenSCAP::common_name request
40
39
  rescue Proxy::Error::Unauthorized => e
41
40
  log_halt 403, "Client authentication failed: #{e.message}"
42
41
  end
43
- date = Time.now.to_i
42
+ @reported_at = Time.now.to_i
43
+ end
44
+
45
+ post "/arf/:policy" do
44
46
  policy = params[:policy]
45
47
 
46
48
  begin
47
- post_to_foreman = ForemanForwarder.new.post_arf_report(cn, policy, date, request.body.string, Proxy::OpenSCAP::Plugin.settings.timeout)
48
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, cn, post_to_foreman['id'], date).store_archive(request.body.string)
49
+ post_to_foreman = ForemanArfForwarder.new.post_report(@cn, policy, @reported_at, request.body.string, Proxy::OpenSCAP::Plugin.settings.timeout)
50
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, @cn, post_to_foreman['id'], @reported_at).store_archive(request.body.string)
49
51
  post_to_foreman.to_json
50
52
  rescue Proxy::OpenSCAP::StoreReportError => e
51
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.failed_dir, cn, post_to_foreman['id'], date).store_failed(request.body.string)
53
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.failed_dir, @cn, post_to_foreman['id'], @reported_at).store_failed(request.body.string)
52
54
  logger.error "Failed to save Report in reports directory (#{Proxy::OpenSCAP::Plugin.settings.reportsdir}). Failed with: #{e.message}.
53
55
  Saving file in #{Proxy::OpenSCAP::Plugin.settings.failed_dir}. Please copy manually to #{Proxy::OpenSCAP::Plugin.settings.reportsdir}"
54
56
  { :result => 'Storage failure on proxy, see proxy logs for details' }.to_json
55
57
  rescue Nokogiri::XML::SyntaxError => e
56
58
  error = "Failed to parse Arf Report, moving to #{Proxy::OpenSCAP::Plugin.settings.corrupted_dir}"
57
59
  logger.error error
58
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.corrupted_dir, cn, policy, date).store_corrupted(request.body.string)
60
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.corrupted_dir, @cn, policy, @reported_at).store_corrupted(request.body.string)
59
61
  { :result => (error << ' on proxy') }.to_json
60
62
  rescue *HTTP_ERRORS => e
61
63
  ### If the upload to foreman fails then store it in the spooldir
62
64
  msg = "Failed to upload to Foreman, saving in spool. Failed with: #{e.message}"
63
65
  logger.error msg
64
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.spooldir, cn, policy, date).store_spool(request.body.string)
66
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.spooldir, @cn, policy, @reported_at).store_spool(request.body.string)
65
67
  { :result => msg }.to_json
66
68
  rescue Proxy::OpenSCAP::StoreSpoolError => e
67
69
  log_halt 500, e.message
@@ -70,10 +72,26 @@ module Proxy::OpenSCAP
70
72
  end
71
73
  end
72
74
 
75
+ post "/oval_reports/:oval_policy_id" do
76
+ ForemanOvalForwarder.new.post_report(@cn, params[:oval_policy_id], @reported_at, request.body.string, Plugin.settings.timeout)
77
+
78
+ { :reported_at => Time.at(@reported_at) }.to_json
79
+ rescue *HTTP_ERRORS => e
80
+ msg = "Failed to upload to Foreman, failed with: #{e.message}"
81
+ logger.error e
82
+ { :result => msg }.to_json
83
+ rescue Nokogiri::XML::SyntaxError => e
84
+ logger.error e
85
+ { :result => 'Failed to parse OVAL report, see proxy logs for details' }.to_json
86
+ rescue Proxy::OpenSCAP::ReportUploadError, Proxy::OpenSCAP::ReportDecompressError => e
87
+ { :result => e.message }.to_json
88
+ end
89
+
90
+
73
91
  get "/arf/:id/:cname/:date/:digest/xml" do
74
92
  content_type 'application/x-bzip2'
75
93
  begin
76
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, params[:cname], params[:id], params[:date]).get_arf_xml(params[:digest])
94
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, params[:cname], params[:id], params[:date]).get_arf_xml(params[:digest])
77
95
  rescue FileNotFound => e
78
96
  log_halt 500, "Could not find requested file, #{e.message}"
79
97
  end
@@ -81,7 +99,7 @@ module Proxy::OpenSCAP
81
99
 
82
100
  delete "/arf/:id/:cname/:date/:digest" do
83
101
  begin
84
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, params[:cname], params[:id], params[:date]).delete_arf_file
102
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, params[:cname], params[:id], params[:date]).delete_arf_file
85
103
  rescue FileNotFound => e
86
104
  logger.debug "Could not find requested file, #{e.message} - Assuming deleted"
87
105
  end
@@ -100,32 +118,34 @@ module Proxy::OpenSCAP
100
118
  get "/policies/:policy_id/content/:digest" do
101
119
  content_type 'application/xml'
102
120
  begin
103
- Proxy::OpenSCAP::FetchScapContent.new.get_policy_content(params[:policy_id], params[:digest])
121
+ Proxy::OpenSCAP::FetchScapFile.new(:scap_content)
122
+ .fetch(params[:policy_id], params[:digest], Proxy::OpenSCAP::Plugin.settings.contentdir)
104
123
  rescue *HTTP_ERRORS => e
105
- log_halt e.response.code.to_i, "File not found on Foreman. Wrong policy id?"
124
+ log_halt e.response.code.to_i, file_not_found_msg
106
125
  rescue StandardError => e
107
126
  log_halt 500, "Error occurred: #{e.message}"
108
127
  end
109
128
  end
110
129
 
111
- get "/policies/:policy_id/content" do
130
+ get "/policies/:policy_id/tailoring/:digest" do
112
131
  content_type 'application/xml'
113
- logger.warn 'DEPRECATION WARNING: /policies/:policy_id/content/:digest should be used, please update foreman_openscap'
114
132
  begin
115
- Proxy::OpenSCAP::FetchScapContent.new.get_policy_content(params[:policy_id], 'scap_content')
133
+ Proxy::OpenSCAP::FetchScapFile.new(:tailoring_file)
134
+ .fetch(params[:policy_id], params[:digest], Proxy::OpenSCAP::Plugin.settings.tailoring_dir)
116
135
  rescue *HTTP_ERRORS => e
117
- log_halt e.response.code.to_i, "File not found on Foreman. Wrong policy id?"
136
+ log_halt e.response.code.to_i, file_not_found_msg
118
137
  rescue StandardError => e
119
138
  log_halt 500, "Error occurred: #{e.message}"
120
139
  end
121
140
  end
122
141
 
123
- get "/policies/:policy_id/tailoring/:digest" do
124
- content_type 'application/xml'
142
+ get "/oval_policies/:oval_policy_id/oval_content/:digest" do
143
+ content_type 'application/x-bzip2'
125
144
  begin
126
- Proxy::OpenSCAP::FetchTailoringFile.new.get_tailoring_file(params[:policy_id], params[:digest])
127
- rescue *HTTP_ERRORS => e
128
- log_halt e.response.code.to_i, "File not found on Foreman. Wrong policy id?"
145
+ Proxy::OpenSCAP::FetchScapFile.new(:oval_content)
146
+ .fetch(params[:oval_policy_id], params[:digest], Proxy::OpenSCAP::Plugin.settings.oval_content_dir)
147
+ rescue *HTTP => e
148
+ log_halt e.response.code.to_i, file_not_found_msg
129
149
  rescue StandardError => e
130
150
  log_halt 500, "Error occurred: #{e.message}"
131
151
  end
@@ -173,7 +193,7 @@ module Proxy::OpenSCAP
173
193
 
174
194
  get "/spool_errors" do
175
195
  begin
176
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.corrupted_dir, nil, nil, nil).spool_errors.to_json
196
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.corrupted_dir, nil, nil, nil).spool_errors.to_json
177
197
  rescue StandardError => e
178
198
  log_halt 500, "Error occurred: #{e.message}"
179
199
  end
@@ -190,5 +210,9 @@ module Proxy::OpenSCAP
190
210
  log_halt 500, "Error occurred: #{e.message}"
191
211
  end
192
212
  end
213
+
214
+ def file_not_found_msg
215
+ "File not found on Foreman. Wrong policy id?"
216
+ end
193
217
  end
194
218
  end
@@ -30,7 +30,7 @@ module Proxy
30
30
 
31
31
  def file_path_in_storage
32
32
  path_to_dir = Proxy::OpenSCAP::Plugin.settings.reportsdir
33
- storage = Proxy::OpenSCAP::StorageFS.new(path_to_dir, @cname, @id, @date)
33
+ storage = Proxy::OpenSCAP::StorageFs.new(path_to_dir, @cname, @id, @date)
34
34
  storage.get_path(@digest)
35
35
  end
36
36
  end
@@ -14,15 +14,15 @@ module Proxy::OpenSCAP
14
14
 
15
15
  post_to_foreman = ForemanForwarder.new.post_arf_report(cn, policy, date, request.body.string, Proxy::OpenSCAP::Plugin.settings.timeout)
16
16
  begin
17
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, cn, post_to_foreman['id'], date).store_archive(request.body.string)
17
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.reportsdir, cn, post_to_foreman['id'], date).store_archive(request.body.string)
18
18
  rescue Proxy::OpenSCAP::StoreReportError => e
19
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.failed_dir, cn, post_to_foreman['id'], date).store_failed(request.body.string)
19
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.failed_dir, cn, post_to_foreman['id'], date).store_failed(request.body.string)
20
20
  logger.error "Failed to save Report in reports directory (#{Proxy::OpenSCAP::Plugin.settings.reportsdir}). Failed with: #{e.message}.
21
21
  Saving file in #{Proxy::OpenSCAP::Plugin.settings.failed_dir}. Please copy manually to #{Proxy::OpenSCAP::Plugin.settings.reportsdir}"
22
22
  rescue *HTTP_ERRORS => e
23
23
  ### If the upload to foreman fails then store it in the spooldir
24
24
  logger.error "Failed to upload to Foreman, saving in spool. Failed with: #{e.message}"
25
- Proxy::OpenSCAP::StorageFS.new(Proxy::OpenSCAP::Plugin.settings.spooldir, cn, policy, date).store_spool(request.body.string)
25
+ Proxy::OpenSCAP::StorageFs.new(Proxy::OpenSCAP::Plugin.settings.spooldir, cn, policy, date).store_spool(request.body.string)
26
26
  rescue Proxy::OpenSCAP::StoreSpoolError => e
27
27
  log_halt 500, e.message
28
28
  end
@@ -16,16 +16,18 @@ require 'proxy/error'
16
16
  require 'yaml'
17
17
  require 'ostruct'
18
18
  require 'proxy/request'
19
- require 'smart_proxy_openscap/fetch_scap_content'
20
- require 'smart_proxy_openscap/foreman_forwarder'
19
+ require 'smart_proxy_openscap/foreman_arf_forwarder'
20
+ require 'smart_proxy_openscap/foreman_oval_forwarder'
21
21
  require 'smart_proxy_openscap/content_parser'
22
22
  require 'smart_proxy_openscap/openscap_exception'
23
23
  require 'smart_proxy_openscap/arf_parser'
24
24
  require 'smart_proxy_openscap/spool_forwarder'
25
25
  require 'smart_proxy_openscap/openscap_html_generator'
26
- require 'smart_proxy_openscap/fetch_tailoring_file'
27
26
  require 'smart_proxy_openscap/policy_parser'
28
27
  require 'smart_proxy_openscap/profiles_parser'
28
+ require 'smart_proxy_openscap/oval_report_storage_fs'
29
+ require 'smart_proxy_openscap/oval_report_parser'
30
+ require 'smart_proxy_openscap/fetch_scap_file'
29
31
 
30
32
  module Proxy::OpenSCAP
31
33
  extend ::Proxy::Log
@@ -22,6 +22,7 @@ module Proxy::OpenSCAP
22
22
  :contentdir => File.join(APP_ROOT, 'openscap/content'),
23
23
  :reportsdir => File.join(APP_ROOT, 'openscap/reports'),
24
24
  :failed_dir => File.join(APP_ROOT, 'openscap/failed'),
25
- :tailoring_dir => File.join(APP_ROOT, 'openscap/tailoring')
25
+ :tailoring_dir => File.join(APP_ROOT, 'openscap/tailoring'),
26
+ :oval_content_dir => File.join(APP_ROOT, 'openscap/oval_content')
26
27
  end
27
28
  end
@@ -0,0 +1,54 @@
1
+ require 'smart_proxy_openscap/openscap_exception'
2
+ require 'openscap_parser/oval_report'
3
+
4
+ module Proxy::OpenSCAP
5
+ class OvalReportParser
6
+ include Proxy::Log
7
+
8
+ def parse_cves(report_data)
9
+ report = oval_report report_data
10
+ results = report.definition_results.reduce({}) do |memo, result|
11
+ memo.tap { |acc| acc[result.definition_id] = parse_cve_res result }
12
+ end
13
+
14
+ report.definitions.map do |definition|
15
+ results[definition.id].merge(parse_cve_def definition)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def parse_cve_def(definition)
22
+ refs = definition.references.reduce([]) do |memo, ref|
23
+ memo.tap { |acc| acc << { :ref_id => ref.ref_id, :ref_url => ref.ref_url } }
24
+ end
25
+
26
+ { :references => refs, :definition_id => definition.id }
27
+ end
28
+
29
+ def parse_cve_res(result)
30
+ { :result => result.result }
31
+ end
32
+
33
+ def oval_report(report_data)
34
+ decompressed = decompress report_data
35
+ ::OpenscapParser::OvalReport.new(decompressed)
36
+ end
37
+
38
+ def decompress(report_data)
39
+ begin
40
+ file = Tempfile.new
41
+ file.write report_data
42
+ file.rewind
43
+ decompressed = `bunzip2 -dc #{file.path}`
44
+ rescue => e
45
+ logger.error e
46
+ raise Proxy::OpenSCAP::ReportDecompressError, "Failed to decompress received report bzip, cause: #{e.message}"
47
+ ensure
48
+ file.close
49
+ file.unlink
50
+ end
51
+ decompressed
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,26 @@
1
+ require 'smart_proxy_openscap/storage_fs_common'
2
+ require 'smart_proxy_openscap/openscap_exception'
3
+
4
+ module Proxy::OpenSCAP
5
+ class OvalReportStorageFs
6
+ include StorageFsCommon
7
+
8
+ def initialize(path_to_dir, oval_policy_id, cname, reported_at)
9
+ @namespace = 'oval'
10
+ @reported_at = reported_at
11
+ @path = "#{path_to_dir}/#{@namespace}/#{oval_policy_id}/#{cname}/"
12
+ end
13
+
14
+ def store_report(report_data)
15
+ store(report_data, StoreReportError)
16
+ end
17
+
18
+ private
19
+
20
+ def store_file(path_to_store, report_data)
21
+ target_path = "#{path_to_store}#{@reported_at}"
22
+ File.open(target_path, 'w') { |f| f.write(report_data) }
23
+ target_path
24
+ end
25
+ end
26
+ end
@@ -52,13 +52,13 @@ module Proxy::OpenSCAP
52
52
 
53
53
  def forward_arf_file(cname, policy_id, date, arf_file_path)
54
54
  data = File.open(arf_file_path, 'rb') { |io| io.read }
55
- post_to_foreman = ForemanForwarder.new.post_arf_report(cname, policy_id, date, data, @loaded_settings.timeout)
56
- Proxy::OpenSCAP::StorageFS.new(@loaded_settings.reportsdir, cname, post_to_foreman['id'], date).store_archive(data)
55
+ post_to_foreman = ForemanArfForwarder.new.post_report(cname, policy_id, date, data, @loaded_settings.timeout)
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
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
- Proxy::OpenSCAP::StorageFS.new(@loaded_settings.corrupted_dir, cname, policy_id, date).
61
+ Proxy::OpenSCAP::StorageFs.new(@loaded_settings.corrupted_dir, cname, policy_id, date).
62
62
  move_corrupted(arf_file_path.split('/').last, @loaded_settings.spooldir)
63
63
  rescue Proxy::OpenSCAP::ReportUploadError => e
64
64
  logger.error "Failed to upload Arf Report at #{arf_file_path}, cause: #{e.message}, the report will be deleted."
@@ -2,8 +2,6 @@ require 'smart_proxy_openscap/openscap_exception'
2
2
 
3
3
  module Proxy::OpenSCAP
4
4
  class Storage
5
- include ::Proxy::Log
6
-
7
5
  def initialize(path_to_dir, cname, id, date)
8
6
  @namespace = 'arf'
9
7
  @cname = cname
@@ -1,8 +1,11 @@
1
1
  require 'pathname'
2
2
  require 'smart_proxy_openscap/storage'
3
+ require 'smart_proxy_openscap/storage_fs_common'
3
4
 
4
5
  module Proxy::OpenSCAP
5
- class StorageFS < Storage
6
+ class StorageFs < Storage
7
+ include StorageFsCommon
8
+
6
9
  def store_archive(data)
7
10
  store(data, StoreReportError)
8
11
  end
@@ -57,9 +60,9 @@ module Proxy::OpenSCAP
57
60
 
58
61
  private
59
62
 
60
- def store_arf(spool_arf_dir, data)
63
+ def store_file(path_to_store, data)
61
64
  filename = Digest::SHA256.hexdigest data
62
- target_path = spool_arf_dir + filename
65
+ target_path = path_to_store + filename
63
66
  File.open(target_path,'w') { |f| f.write(data) }
64
67
  target_path
65
68
  end
@@ -91,7 +94,7 @@ module Proxy::OpenSCAP
91
94
  end
92
95
 
93
96
  begin
94
- target_path = store_arf(@path, data)
97
+ target_path = store_file(@path, data)
95
98
  rescue StandardError => e
96
99
  raise error_type, "Could not store file: #{e.message}"
97
100
  end
@@ -0,0 +1,42 @@
1
+ module Proxy::OpenSCAP
2
+ module StorageFsCommon
3
+ include ::Proxy::Log
4
+
5
+ private
6
+
7
+ def create_directory
8
+ begin
9
+ FileUtils.mkdir_p @path
10
+ rescue StandardError => e
11
+ logger.error "Could not create '#{@path}' directory: #{e.message}"
12
+ raise e
13
+ end
14
+ @path
15
+ end
16
+
17
+ def move(source, error_type)
18
+ begin
19
+ create_directory
20
+ FileUtils.mv source, @path
21
+ rescue StandardError => e
22
+ raise error_type, "Could not move file: #{e.message}"
23
+ end
24
+ end
25
+
26
+ def store(data, error_type)
27
+ begin
28
+ create_directory
29
+ rescue StandardError => e
30
+ raise error_type, "Could not fulfill request: #{e.message}"
31
+ end
32
+
33
+ begin
34
+ target_path = store_file(@path, data)
35
+ rescue StandardError => e
36
+ raise error_type, "Could not store file: #{e.message}"
37
+ end
38
+
39
+ logger.debug "File #{target_path} stored in reports dir."
40
+ end
41
+ end
42
+ end
@@ -10,6 +10,6 @@
10
10
 
11
11
  module Proxy
12
12
  module OpenSCAP
13
- VERSION = '0.8.1'
13
+ VERSION = '0.9.0'
14
14
  end
15
15
  end
@@ -31,3 +31,6 @@
31
31
  # Affects sending reports to Foreman (directly and from spool) and fetching scap content or tailoring file
32
32
  # for distribution to clients
33
33
  #:timeout: 60
34
+
35
+ # Directory where OpenSCAP OVAL content bzipped XML are stored
36
+ #:oval_content_dir: /var/lib/openscap/oval_content
@@ -21,6 +21,5 @@ Gem::Specification.new do |s|
21
21
  s.add_development_dependency('mocha')
22
22
  s.add_development_dependency('webmock')
23
23
  s.add_dependency 'openscap', '~> 0.4.7'
24
-
25
- s.add_dependency 'openscap_parser', '~> 1.0.1'
24
+ s.add_dependency 'openscap_parser', '~> 1.0.2'
26
25
  end
Binary file
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+ require 'smart_proxy_openscap'
3
+ require 'smart_proxy_openscap/openscap_api'
4
+
5
+ ENV['RACK_ENV'] = 'test'
6
+
7
+ class FetchOvalContentApiTest < Test::Unit::TestCase
8
+ include Rack::Test::Methods
9
+
10
+ def setup
11
+ @foreman_url = 'https://foreman.example.com'
12
+ @fixture_path = "/test/data/rhel-7-including-unpatched.oval.xml.bz2"
13
+ @fixture_full_path = File.join(Dir.getwd, @fixture_path)
14
+ Proxy::SETTINGS.stubs(:foreman_url).returns(@foreman_url)
15
+ @results_path = ("#{Dir.getwd}/test/test_run_files")
16
+ FileUtils.mkdir_p(@results_path)
17
+ Proxy::OpenSCAP::Plugin.settings.stubs(:oval_content_dir).returns(@results_path)
18
+ @oval_content = File.new(@fixture_full_path).read
19
+ @digest = Digest::SHA256.hexdigest @oval_content
20
+ @policy_id = 1
21
+ end
22
+
23
+ def teardown
24
+ FileUtils.rm_rf(Dir.glob("#{@results_path}/*"))
25
+ end
26
+
27
+ def app
28
+ ::Proxy::OpenSCAP::Api.new
29
+ end
30
+
31
+ def test_get_oval_content_from_file
32
+ FileUtils.mkdir("#{@results_path}/#{@policy_id}")
33
+ FileUtils.cp(@fixture_full_path, "#{@results_path}/#{@policy_id}/#{@digest}.oval.xml.bz2")
34
+ get "/oval_policies/#{@policy_id}/oval_content/#{@digest}"
35
+ assert_equal("application/x-bzip2", last_response.header["Content-Type"], "Response header should be application/x-bzip2")
36
+ assert(last_response.successful?, "Response should be success")
37
+ end
38
+ end
@@ -54,7 +54,7 @@ class FetchScapApiTest < Test::Unit::TestCase
54
54
  end
55
55
 
56
56
  def test_get_scap_content_permissions
57
- Proxy::OpenSCAP::FetchScapContent.any_instance.stubs(:get_policy_content).raises(Errno::EACCES)
57
+ Proxy::OpenSCAP::FetchScapFile.any_instance.stubs(:fetch).raises(Errno::EACCES)
58
58
  stub_request(:get, "#{@foreman_url}/api/v2/compliance/policies/#{@policy_id}/content").to_return(:body => @scap_content)
59
59
  get "/policies/#{@policy_id}/content/#{@digest}"
60
60
  assert_equal(500, last_response.status, "No permissions should raise error 500")
@@ -0,0 +1,14 @@
1
+ require 'test_helper'
2
+ require 'smart_proxy_openscap'
3
+ require 'smart_proxy_openscap/oval_report_parser'
4
+
5
+ class OvalReportParserTest < Test::Unit::TestCase
6
+
7
+ def test_oval_report_parsing
8
+ oval_report = File.open("#{Dir.getwd}/test/data/oval-results.xml.bz2").read
9
+ res = Proxy::OpenSCAP::OvalReportParser.new.parse_cves oval_report
10
+ refute res.empty?
11
+ assert res.first[:result]
12
+ refute res.first[:references].empty?
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+ require 'smart_proxy_openscap'
3
+ require 'smart_proxy_openscap/openscap_api'
4
+
5
+ ENV['RACK_ENV'] = 'test'
6
+
7
+ class PostOvalReportApiTest < Test::Unit::TestCase
8
+ include Rack::Test::Methods
9
+
10
+ setup do
11
+ @foreman_url = 'https://foreman.example.com'
12
+ Proxy::SETTINGS.stubs(:foreman_url).returns(@foreman_url)
13
+ @oval_report = File.open("#{Dir.getwd}/test/data/oval-results.xml.bz2").read
14
+ @cname = 'node.example.org'
15
+ @date = Time.now.to_i
16
+ @policy_id = 1
17
+ Proxy::OpenSCAP.stubs(:common_name).returns(@cname)
18
+ end
19
+
20
+ def app
21
+ ::Proxy::OpenSCAP::Api.new
22
+ end
23
+
24
+ def test_post_oval_report_to_foreman
25
+ stub_request(:post, "#{@foreman_url}/api/v2/compliance/oval_reports/#{@cname}/#{@policy_id}/#{@date}")
26
+ .to_return(:status => 200, :body => '{ "result": "ok" }')
27
+ post "/oval_reports/#{@policy_id}", @oval_report, 'CONTENT_TYPE' => 'text/xml', 'CONTENT_ENCODING' => 'x-bzip2'
28
+ assert(last_response.successful?, "Should be a success")
29
+ end
30
+ end
@@ -58,7 +58,7 @@ class OpenSCAPApiTest < Test::Unit::TestCase
58
58
  def test_fail_save_file_should_raise_error
59
59
  @policy_id = 2
60
60
  stub_request(:post, "#{@foreman_url}/api/v2/compliance/arf_reports/#{@cname}/#{@policy_id}/#{@date}").to_return(:status => 500, :body => "{\"result\":\"server error\"}")
61
- Proxy::OpenSCAP::StorageFS.any_instance.stubs(:create_directory).raises(StandardError)
61
+ Proxy::OpenSCAP::StorageFs.any_instance.stubs(:create_directory).raises(StandardError)
62
62
  post "/arf/#{@policy_id}", @arf_report, 'CONTENT_TYPE' => 'text/xml', 'CONTENT_ENCODING' => 'x-bzip2'
63
63
  assert(last_response.server_error?, "Should return 500")
64
64
  refute(File.file?("#{@results_path}/spool/arf/#{@cname}/#{@policy_id}/#{@date}/#{@filename}"), "File should be saved in spool directory")
@@ -67,7 +67,7 @@ class OpenSCAPApiTest < Test::Unit::TestCase
67
67
  def test_success_post_fail_save_should_save_spool
68
68
  stub_request(:post, "#{@foreman_url}/api/v2/compliance/arf_reports/#{@cname}/#{@policy_id}/#{@date}")
69
69
  .to_return(:status => 200, :body => "{\"result\":\"OK\",\"id\":\"#{@arf_id}\"}")
70
- Proxy::OpenSCAP::StorageFS.any_instance.stubs(:store_archive).raises(Proxy::OpenSCAP::StoreReportError)
70
+ Proxy::OpenSCAP::StorageFs.any_instance.stubs(:store_archive).raises(Proxy::OpenSCAP::StoreReportError)
71
71
  post "/arf/#{@policy_id}", @arf_report, 'CONTENT_TYPE' => 'text/xml', 'CONTENT_ENCODING' => 'x-bzip2'
72
72
  refute(File.file?("#{@results_path}/spool/arf/#{@cname}/#{@policy_id}/#{@date}/#{@filename}"), "File should not be in spool directory")
73
73
  refute(File.file?("#{@results_path}/reports/arf/#{@cname}/#{@arf_id}/#{@date}/#{@filename}"), "File should not be in Reports directory")
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.8.1
4
+ version: 0.9.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-05-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake
@@ -88,14 +88,14 @@ dependencies:
88
88
  requirements:
89
89
  - - "~>"
90
90
  - !ruby/object:Gem::Version
91
- version: 1.0.1
91
+ version: 1.0.2
92
92
  type: :runtime
93
93
  prerelease: false
94
94
  version_requirements: !ruby/object:Gem::Requirement
95
95
  requirements:
96
96
  - - "~>"
97
97
  - !ruby/object:Gem::Version
98
- version: 1.0.1
98
+ version: 1.0.2
99
99
  description: |-
100
100
  A plug-in to the Foreman's smart-proxy which receives
101
101
  bzip2ed ARF files and forwards them to the Foreman.
@@ -124,9 +124,10 @@ files:
124
124
  - lib/smart_proxy_openscap/arf_parser.rb
125
125
  - lib/smart_proxy_openscap/content_parser.rb
126
126
  - lib/smart_proxy_openscap/fetch_file.rb
127
- - lib/smart_proxy_openscap/fetch_scap_content.rb
128
- - lib/smart_proxy_openscap/fetch_tailoring_file.rb
127
+ - lib/smart_proxy_openscap/fetch_scap_file.rb
128
+ - lib/smart_proxy_openscap/foreman_arf_forwarder.rb
129
129
  - lib/smart_proxy_openscap/foreman_forwarder.rb
130
+ - lib/smart_proxy_openscap/foreman_oval_forwarder.rb
130
131
  - lib/smart_proxy_openscap/http_config.ru
131
132
  - lib/smart_proxy_openscap/openscap_api.rb
132
133
  - lib/smart_proxy_openscap/openscap_exception.rb
@@ -134,6 +135,8 @@ files:
134
135
  - lib/smart_proxy_openscap/openscap_import_api.rb
135
136
  - lib/smart_proxy_openscap/openscap_lib.rb
136
137
  - lib/smart_proxy_openscap/openscap_plugin.rb
138
+ - lib/smart_proxy_openscap/oval_report_parser.rb
139
+ - lib/smart_proxy_openscap/oval_report_storage_fs.rb
137
140
  - lib/smart_proxy_openscap/policy_guide.rb
138
141
  - lib/smart_proxy_openscap/policy_parser.rb
139
142
  - lib/smart_proxy_openscap/profiles_parser.rb
@@ -141,11 +144,14 @@ files:
141
144
  - lib/smart_proxy_openscap/spool_forwarder.rb
142
145
  - lib/smart_proxy_openscap/storage.rb
143
146
  - lib/smart_proxy_openscap/storage_fs.rb
147
+ - lib/smart_proxy_openscap/storage_fs_common.rb
144
148
  - lib/smart_proxy_openscap/version.rb
145
149
  - settings.d/openscap.yml.example
146
150
  - smart_proxy_openscap.gemspec
147
151
  - test/data/arf_report
148
152
  - test/data/corrupted_arf_report
153
+ - test/data/oval-results.xml.bz2
154
+ - test/data/rhel-7-including-unpatched.oval.xml.bz2
149
155
  - test/data/spool/cleanup_spool/arf/2c101b95-033f-4b15-b490-f50bf9090dae/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1
150
156
  - test/data/spool/cleanup_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1
151
157
  - test/data/spool/corrupted_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484309984/a4dfba5db27b21795e6fa401b8dce7a70faeb25b7963891f07f6f4baaf052afb
@@ -154,9 +160,12 @@ files:
154
160
  - test/data/spool/valid_spool/arf/e20b9695-f655-401a-9dda-8cca7a47a8c0/1/1484313035/fa2f68ffb944c917332a284dc63ec7f8fa76990cb815ddcad3318b5d9457f8a1
155
161
  - test/data/ssg-rhel7-ds.xml
156
162
  - test/data/tailoring.xml
163
+ - test/fetch_oval_content_api_test.rb
157
164
  - test/fetch_scap_api_test.rb
158
165
  - test/fetch_tailoring_api_test.rb
159
166
  - test/get_report_xml_html_test.rb
167
+ - test/oval_report_parser_test.rb
168
+ - test/post_oval_report_api_test.rb
160
169
  - test/post_report_api_test.rb
161
170
  - test/scap_content_parser_api_test.rb
162
171
  - test/script_class_test.rb
@@ -1,17 +0,0 @@
1
- require 'smart_proxy_openscap/fetch_file'
2
-
3
- module Proxy::OpenSCAP
4
- class FetchScapContent < FetchFile
5
- def get_policy_content(policy_id, digest)
6
- policy_store_dir = File.join(Proxy::OpenSCAP.fullpath(Proxy::OpenSCAP::Plugin.settings.contentdir), policy_id.to_s)
7
- policy_scap_file = File.join(policy_store_dir, "#{policy_id}_#{digest}.xml")
8
- file_download_path = "api/v2/compliance/policies/#{policy_id}/content"
9
-
10
- create_store_dir policy_store_dir
11
-
12
- scap_file = policy_content_file(policy_scap_file)
13
- clean_store_folder(policy_store_dir) unless scap_file
14
- scap_file ||= save_or_serve_scap_file(policy_scap_file, file_download_path)
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'smart_proxy_openscap/fetch_file'
2
-
3
- module Proxy::OpenSCAP
4
- class FetchTailoringFile < FetchFile
5
- def get_tailoring_file(policy_id, digest)
6
- store_dir = File.join(Proxy::OpenSCAP.fullpath(Proxy::OpenSCAP::Plugin.settings.tailoring_dir), policy_id.to_s)
7
- policy_tailoring_file = File.join(store_dir, "#{policy_id}_#{digest}.xml")
8
- file_download_path = "api/v2/compliance/policies/#{policy_id}/tailoring"
9
-
10
- create_store_dir store_dir
11
-
12
- scap_file = policy_content_file(policy_tailoring_file)
13
- clean_store_folder(store_dir) unless scap_file
14
- scap_file ||= save_or_serve_scap_file(policy_tailoring_file, file_download_path)
15
- end
16
- end
17
- end