foreman_scap_client 0.4.7 → 0.5.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: 613e57e5fe5d504abb771c1924649c18d3a01869e3d75fbf33c4d2078647dcaa
4
- data.tar.gz: f5d061fd7061174a3ce2dd92348371a9cb672781b428950ccc7add94b1fa8b69
3
+ metadata.gz: 83d36963b277620c532c048595b0bc57f024918bcf0ee44073930bd0297b4b56
4
+ data.tar.gz: 9acaf0257a5c1b18ab6f096a2f4025e8d5732ee4e7a45ef195853fe70ab9dd55
5
5
  SHA512:
6
- metadata.gz: 6e7d76224ae9440cad7ba6592a0aee99909ec7be581e1da4bc9310b74161504127b9631148bd5371bc7616718eac76b64a6565c04250c0488ac24d2db5860104
7
- data.tar.gz: 2c6a1f7531f5a996847718255dca2e3bf4d1d5b091242402e71748450e3971ead373031217b3ce9b96d84aa568018374aacf37943786943db4becf068150d922
6
+ metadata.gz: 4d68a98ce43eb6ebae0f268a56c1ca87d2f84748e783c1bfda80ffbf170cf4443929b32543d9a30da85a6c554ff7b2952a275a90f98b521c63cae63ff562ebad
7
+ data.tar.gz: fc864752d527e1118ed4f4a147921ea4b5dd5c49f995e298a10a9400561f7df2bbf2a88bb8137a9c9262b781d791aad4fea672b652a1692d63e075aa3199e777
@@ -2,11 +2,22 @@
2
2
  require 'rubygems'
3
3
  require 'foreman_scap_client'
4
4
 
5
- if ARGV.size != 1
6
- puts "Usage: #{$0} policy_id"
7
- puts " where policy_id is a key used in config file"
8
- exit 2
5
+ if ARGV.last == '--skip-upload'
6
+ skip_upload = true
7
+ args = ARGV[0...-1]
9
8
  else
10
- ForemanScapClient::Client.new.run(ARGV[0].to_i)
9
+ skip_upload = false
10
+ args = ARGV
11
11
  end
12
12
 
13
+ if args.size == 1
14
+ ForemanScapClient::Client.new.run(args[0].to_i, skip_upload)
15
+ elsif args.size == 2 && args[0] == 'ds'
16
+ ForemanScapClient::Client.new.run(args[1].to_i, skip_upload)
17
+ elsif args.size == 2 && args[0] == 'oval'
18
+ ForemanScapClient::OvalClient.new.run(args[1].to_i, skip_upload)
19
+ else
20
+ puts "Usage: #{$0} [ds | oval] policy_id [--skip-upload]"
21
+ puts " where policy_id is a key used in config file"
22
+ exit 2
23
+ end
@@ -33,3 +33,7 @@
33
33
  2:
34
34
  :profile: 'xccdf_org.ssgproject.content_profile_common'
35
35
  :content_path: '/usr/share/xml/scap/ssg/fedora/ssg-fedora-ds.xml'
36
+
37
+ :oval:
38
+ 3:
39
+ :content_path: '/var/lib/openscap/oval_content/ansible-2.9.oval.xml.bz2'
@@ -1,2 +1,3 @@
1
1
  require "foreman_scap_client/version"
2
2
  require "foreman_scap_client/client"
3
+ require "foreman_scap_client/oval_client"
@@ -0,0 +1,240 @@
1
+ require 'rubygems' if RUBY_VERSION.start_with? '1.8'
2
+ require 'yaml'
3
+ require 'tmpdir'
4
+ require 'net/http'
5
+ require 'net/https'
6
+ require 'uri'
7
+ require 'open-uri'
8
+ require 'open3'
9
+ require 'json'
10
+
11
+ module ForemanScapClient
12
+ class BaseClient
13
+ attr_reader :policy_id, :config
14
+
15
+ CONFIG_FILE = '/etc/foreman_scap_client/config.yaml'
16
+
17
+ def run(policy_id, skip_upload = false)
18
+ @policy_id = policy_id
19
+ load_config
20
+ ensure_scan_files
21
+ run_in_tmpdir skip_upload
22
+ end
23
+
24
+ private
25
+
26
+ def ensure_scan_files
27
+ raise NotImplementedError
28
+ end
29
+
30
+ def policy_namespace
31
+ raise NotImplementedError
32
+ end
33
+
34
+ def upload_uri
35
+ raise NotImplementedError
36
+ end
37
+
38
+ def scan_command
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def run_in_tmpdir(skip_upload)
43
+ if skip_upload
44
+ @tmp_dir = Dir.mktmpdir
45
+ scan
46
+ bzip
47
+ else
48
+ Dir.mktmpdir do |dir|
49
+ @tmp_dir = dir
50
+ scan
51
+ bzip
52
+ upload
53
+ end
54
+ end
55
+ end
56
+
57
+ def policy_from_config
58
+ config && config[policy_namespace] && config[policy_namespace][@policy_id]
59
+ end
60
+
61
+ def load_config
62
+ @config ||= YAML.load_file(CONFIG_FILE)
63
+ ensure_policy_exists
64
+ rescue => e
65
+ puts 'Config file could not be loaded'
66
+ puts e.message
67
+ exit(1)
68
+ end
69
+
70
+ def scan
71
+ puts "DEBUG: running: " + scan_command
72
+ puts "with ENV vars: #{scan_command_env_vars}" unless scan_command_env_vars.empty?
73
+
74
+ if RUBY_VERSION.start_with? '1.8'
75
+ legacy_run_scan
76
+ else
77
+ run_scan
78
+ end
79
+ end
80
+
81
+ def run_scan
82
+ stdout_str, error_str, result = Open3.capture3(scan_command_env_vars, scan_command)
83
+ if result.success? || result.exitstatus == 2
84
+ puts error_str.split("\n").select { |item| item.start_with?('WARNING:') || item.start_with?('Downloading') }.join("\n")
85
+ @report = results_path
86
+ else
87
+ puts 'Scan failed'
88
+ puts stdout_str
89
+ puts error_str
90
+ exit(2)
91
+ end
92
+ end
93
+
94
+ def legacy_run_scan
95
+ warn_proxy_not_supported
96
+ result = `#{scan_command}`
97
+
98
+ if $?.success? || $?.exitstatus == 2
99
+ @report = results_path
100
+ else
101
+ puts 'Scan failed'
102
+ puts result
103
+ exit(2)
104
+ end
105
+ end
106
+
107
+ def scan_command_env_vars
108
+ if http_proxy_uri
109
+ {
110
+ 'HTTP_PROXY' => http_proxy_uri,
111
+ 'HTTPS_PROXY' => http_proxy_uri
112
+ }
113
+ else
114
+ {}
115
+ end
116
+ end
117
+
118
+ def http_proxy_uri
119
+ return nil unless config[:http_proxy_server] && config[:http_proxy_port]
120
+ http_proxy_server = config[:http_proxy_server]
121
+ http_proxy_port = config[:http_proxy_port]
122
+ "http://#{http_proxy_server}:#{http_proxy_port}"
123
+ end
124
+
125
+ def results_path
126
+ "#{@tmp_dir}/results.xml"
127
+ end
128
+
129
+ def results_bzip_path
130
+ "#{results_path}.bz2"
131
+ end
132
+
133
+ def warn_proxy_not_supported
134
+ puts 'Configuration for HTTP(S) proxy found but not supported for ruby 1.8' if http_proxy_uri
135
+ end
136
+
137
+ def bzip_command
138
+ "/usr/bin/env bzip2 #{results_path}"
139
+ end
140
+
141
+ def bzip
142
+ puts 'DEBUG: running: ' + bzip_command
143
+ result = `#{bzip_command}`
144
+ if !$?.success?
145
+ puts 'bzip failed'
146
+ puts results
147
+ exit(2)
148
+ end
149
+ end
150
+
151
+ def upload
152
+ uri = URI.parse(upload_uri)
153
+ puts "Uploading results to #{uri}"
154
+ https = generate_https_object(uri)
155
+ https.read_timeout = config[:timeout] if config[:timeout]
156
+ request = Net::HTTP::Post.new uri.path
157
+ request.body = File.read(results_bzip_path)
158
+ request['Content-Type'] = 'text/xml'
159
+ request['Content-Encoding'] = 'x-bzip2'
160
+ begin
161
+ res = https.request(request)
162
+ value = res.value
163
+ foreman_upload_result res
164
+ rescue StandardError => e
165
+ puts res.body if res
166
+ puts "Upload failed: #{e.message}"
167
+ exit(4)
168
+ end
169
+ end
170
+
171
+ def foreman_proxy_uri
172
+ foreman_proxy_fqdn = config[:server]
173
+ foreman_proxy_port = config[:port]
174
+ "https://#{foreman_proxy_fqdn}:#{foreman_proxy_port}"
175
+ end
176
+
177
+ def generate_https_object(uri)
178
+ https = Net::HTTP.new(uri.host, uri.port)
179
+ https.use_ssl = true
180
+ https.ciphers = config[:ciphers] if config[:ciphers]
181
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
182
+ https.ca_file = config[:ca_file]
183
+ begin
184
+ https.cert = OpenSSL::X509::Certificate.new File.read(config[:host_certificate])
185
+ https.key = OpenSSL::PKey::RSA.new File.read(config[:host_private_key])
186
+ rescue StandardError => e
187
+ puts 'Unable to load certs'
188
+ puts e.message
189
+ exit(3)
190
+ end
191
+ https
192
+ end
193
+
194
+ def ensure_policy_exists
195
+ if policy_from_config.nil?
196
+ puts "Policy id #{@policy_id} not found."
197
+ exit(1)
198
+ end
199
+ end
200
+
201
+ def ensure_file(dir, download_path, type_humanized)
202
+ return if File.exist?(policy_from_config[dir])
203
+ puts "File #{policy_from_config[dir]} is missing. Downloading it from proxy."
204
+ begin
205
+ FileUtils.mkdir_p(File.dirname(policy_from_config[dir]))
206
+ uri = URI.parse(download_uri(policy_from_config[download_path]))
207
+ puts "Download #{type_humanized} xml from: #{uri}"
208
+ request = generate_https_object(uri).get(uri.path)
209
+ request.value
210
+ content_xml = request.body
211
+ open(policy_from_config[dir], 'wb') do |file|
212
+ file << content_xml
213
+ end
214
+ rescue StandardError => e
215
+ puts "#{type_humanized} is missing and download failed with error: #{e.message}"
216
+ exit(5)
217
+ end
218
+ end
219
+
220
+ def download_uri(download_path)
221
+ foreman_proxy_uri + "#{download_path}"
222
+ end
223
+
224
+ def foreman_upload_result(response)
225
+ begin
226
+ print_upload_result JSON.parse(response.body)
227
+ rescue StandardError => e
228
+ # rescue and print nothing if older proxy version does not respond with json we expect
229
+ end
230
+ end
231
+
232
+ def print_upload_result(parsed)
233
+ if parsed['id']
234
+ puts "Report uploaded, report id: #{parsed['id']}"
235
+ else
236
+ puts "Report not uploaded from proxy to Foreman server, cause: #{parsed['result']}"
237
+ end
238
+ end
239
+ end
240
+ end
@@ -1,109 +1,28 @@
1
- require 'rubygems' if RUBY_VERSION.start_with? '1.8'
2
- require 'yaml'
3
- require 'tmpdir'
4
- require 'net/http'
5
- require 'net/https'
6
- require 'uri'
7
- require 'open-uri'
8
- require 'open3'
9
- require 'json'
1
+ require 'foreman_scap_client/base_client'
10
2
 
11
3
  module ForemanScapClient
12
- CONFIG_FILE = '/etc/foreman_scap_client/config.yaml'
13
-
14
- class Client
15
- attr_reader :config, :policy_id, :tailored
16
-
17
- def run(policy_id)
18
- @policy_id = policy_id
19
- load_config
20
- ensure_scan_file
21
- ensure_tailoring_file
22
- Dir.mktmpdir do |dir|
23
- @tmp_dir = dir
24
- scan
25
- bzip
26
- upload
27
- end
28
- end
4
+ class Client < BaseClient
5
+ attr_reader :tailored
29
6
 
30
7
  private
31
8
 
32
- def warn_proxy_not_supported
33
- puts 'Configuration for HTTP(S) proxy found but not supported for ruby 1.8' if http_proxy_uri
34
- end
35
-
36
- def load_config
37
- @config ||= YAML.load_file(CONFIG_FILE)
38
- ensure_policy_exist
39
- @tailored = @config[policy_id][:tailoring_path] && !@config[policy_id][:tailoring_path].empty?
40
- rescue => e
41
- puts 'Config file could not be loaded'
42
- puts e.message
43
- exit(1)
9
+ def policy_namespace
10
+ :ds
44
11
  end
45
12
 
46
- def scan
47
- puts "DEBUG: running: " + scan_command
48
- puts "with ENV vars: #{scan_command_env_vars}" unless scan_command_env_vars.empty?
49
-
50
- if RUBY_VERSION.start_with? '1.8'
51
- legacy_run_scan
52
- else
53
- run_scan
54
- end
13
+ # remove when we have made changes to puppet module/ansible role to start namespacing existing ds policies in config
14
+ def policy_from_config
15
+ super || @config[policy_id]
55
16
  end
56
17
 
57
- def run_scan
58
- stdout_str, error_str, result = Open3.capture3(scan_command_env_vars, scan_command)
59
- if result.success? || result.exitstatus == 2
60
- puts error_str.split("\n").select { |item| item.start_with?('WARNING:') || item.start_with?('Downloading') }.join("\n")
61
- @report = results_path
62
- else
63
- puts 'Scan failed'
64
- puts stdout_str
65
- puts error_str
66
- exit(2)
67
- end
18
+ def ensure_policy_exists
19
+ super
20
+ @tailored = policy_from_config[:tailoring_path] && !policy_from_config[:tailoring_path].empty?
68
21
  end
69
22
 
70
- def legacy_run_scan
71
- warn_proxy_not_supported
72
- result = `#{scan_command}`
73
-
74
- if $?.success? || $?.exitstatus == 2
75
- @report = results_path
76
- else
77
- puts 'Scan failed'
78
- puts result
79
- exit(2)
80
- end
81
- end
82
-
83
- def scan_command_env_vars
84
- if http_proxy_uri
85
- {
86
- 'HTTP_PROXY' => http_proxy_uri,
87
- 'HTTPS_PROXY' => http_proxy_uri
88
- }
89
- else
90
- {}
91
- end
92
- end
93
-
94
- def http_proxy_uri
95
- return nil unless config[:http_proxy_server] && config[:http_proxy_port]
96
- http_proxy_server = config[:http_proxy_server]
97
- http_proxy_port = config[:http_proxy_port]
98
- "http://#{http_proxy_server}:#{http_proxy_port}"
99
- end
100
-
101
- def results_path
102
- "#{@tmp_dir}/results.xml"
103
- end
104
-
105
- def results_bzip_path
106
- "#{results_path}.bz2"
23
+ def ensure_scan_files
24
+ ensure_scan_file
25
+ ensure_tailoring_file if tailored
107
26
  end
108
27
 
109
28
  def scan_command
@@ -124,120 +43,17 @@ module ForemanScapClient
124
43
  tailored ? "--tailoring-file #{config[policy_id][:tailoring_path]}" : ""
125
44
  end
126
45
 
127
- def bzip_command
128
- "/usr/bin/env bzip2 #{results_path}"
129
- end
130
-
131
- def bzip
132
- puts 'DEBUG: running: ' + bzip_command
133
- result = `#{bzip_command}`
134
- if !$?.success?
135
- puts 'bzip failed'
136
- puts results
137
- exit(2)
138
- end
139
- end
140
-
141
- def upload
142
- uri = URI.parse(upload_uri)
143
- puts "Uploading results to #{uri}"
144
- https = generate_https_object(uri)
145
- https.read_timeout = config[:timeout] if config[:timeout]
146
- request = Net::HTTP::Post.new uri.path
147
- request.body = File.read(results_bzip_path)
148
- request['Content-Type'] = 'text/xml'
149
- request['Content-Encoding'] = 'x-bzip2'
150
- begin
151
- res = https.request(request)
152
- value = res.value
153
- foreman_upload_result res
154
- rescue StandardError => e
155
- puts res.body if res
156
- puts "Upload failed: #{e.message}"
157
- exit(4)
158
- end
159
- end
160
46
 
161
47
  def upload_uri
162
48
  foreman_proxy_uri + "/compliance/arf/#{@policy_id}"
163
49
  end
164
50
 
165
- def foreman_proxy_uri
166
- foreman_proxy_fqdn = config[:server]
167
- foreman_proxy_port = config[:port]
168
- "https://#{foreman_proxy_fqdn}:#{foreman_proxy_port}"
169
- end
170
-
171
- def generate_https_object(uri)
172
- https = Net::HTTP.new(uri.host, uri.port)
173
- https.use_ssl = true
174
- https.ciphers = config[:ciphers] if config[:ciphers]
175
- https.verify_mode = OpenSSL::SSL::VERIFY_PEER
176
- https.ca_file = config[:ca_file]
177
- begin
178
- https.cert = OpenSSL::X509::Certificate.new File.read(config[:host_certificate])
179
- https.key = OpenSSL::PKey::RSA.new File.read(config[:host_private_key])
180
- rescue StandardError => e
181
- puts 'Unable to load certs'
182
- puts e.message
183
- exit(3)
184
- end
185
- https
186
- end
187
-
188
- def ensure_policy_exist
189
- if config[@policy_id].nil?
190
- puts "Policy id #{@policy_id} not found."
191
- exit(1)
192
- end
193
- end
194
-
195
- def ensure_file(dir, download_path, type_humanized)
196
- return if File.exist?(config[policy_id][dir])
197
- puts "File #{config[policy_id][dir]} is missing. Downloading it from proxy."
198
- begin
199
- FileUtils.mkdir_p(File.dirname(config[policy_id][dir]))
200
- uri = URI.parse(download_uri(config[policy_id][download_path]))
201
- puts "Download #{type_humanized} xml from: #{uri}"
202
- request = generate_https_object(uri).get(uri.path)
203
- request.value
204
- ds_content_xml = request.body
205
- open(config[policy_id][dir], 'wb') do |file|
206
- file << ds_content_xml
207
- end
208
- rescue StandardError => e
209
- puts "#{type_humanized} is missing and download failed with error: #{e.message}"
210
- exit(5)
211
- end
212
- end
213
-
214
51
  def ensure_scan_file
215
52
  ensure_file :content_path, :download_path, "SCAP content"
216
53
  end
217
54
 
218
55
  def ensure_tailoring_file
219
- return unless tailored
220
56
  ensure_file :tailoring_path, :tailoring_download_path, "Tailoring file"
221
57
  end
222
-
223
- def download_uri(download_path)
224
- foreman_proxy_uri + "#{download_path}"
225
- end
226
-
227
- def foreman_upload_result(response)
228
- begin
229
- print_upload_result JSON.parse(response.body)
230
- rescue StandardError => e
231
- # rescue and print nothing if older proxy version does not respond with json we expect
232
- end
233
- end
234
-
235
- def print_upload_result(parsed)
236
- if parsed['id']
237
- puts "Report uploaded, report id: #{parsed['id']}"
238
- else
239
- puts "Report not uploaded from proxy to Foreman server, cause: #{parsed['result']}"
240
- end
241
- end
242
58
  end
243
59
  end
@@ -0,0 +1,31 @@
1
+ require 'foreman_scap_client/base_client'
2
+
3
+ module ForemanScapClient
4
+ class OvalClient < BaseClient
5
+ private
6
+
7
+ def policy_namespace
8
+ :oval
9
+ end
10
+
11
+ def ensure_scan_files
12
+ ensure_file :content_path, :download_path, "OVAL content"
13
+ end
14
+
15
+ def upload_uri
16
+ foreman_proxy_uri + "/compliance/oval_reports/#{@policy_id}"
17
+ end
18
+
19
+ def scan_command
20
+ "oscap oval eval --results #{results_path} #{policy_from_config[:content_path]}"
21
+ end
22
+
23
+ def print_upload_result(parsed)
24
+ if parsed['reported_at']
25
+ puts "Report successfully uploaded at #{parsed['reported_at']}"
26
+ else
27
+ puts "Report not uploaded, cause: #{parsed['result']}"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module ForemanScapClient
2
- VERSION = "0.4.7"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_scap_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marek Hulan
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-07-17 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: bundler
@@ -56,7 +56,9 @@ files:
56
56
  - bin/foreman_scap_client
57
57
  - config/config.yaml.example
58
58
  - lib/foreman_scap_client.rb
59
+ - lib/foreman_scap_client/base_client.rb
59
60
  - lib/foreman_scap_client/client.rb
61
+ - lib/foreman_scap_client/oval_client.rb
60
62
  - lib/foreman_scap_client/version.rb
61
63
  homepage: https://github.com/openscap/foreman_scap_client
62
64
  licenses: