Top Level Namespace
Defined Under Namespace
Modules: CemAcpt Classes: IO, RunLogs
Constant Summary collapse
- CONFIG_PATH =
'/opt/cem_acpt/scan/scan_config.json'- REPORT_DIR =
'/opt/cem_acpt/scan/reports'
Instance Method Summary collapse
- #load_config ⇒ Object
- #parse_ciscat_json(path) ⇒ Object
- #parse_openscap_xml(path) ⇒ Object
- #perform_scan ⇒ Object
- #run_ciscat(profile, benchmark) ⇒ Object
- #run_openscap(profile, datastream) ⇒ Object
Instance Method Details
#load_config ⇒ Object
25 26 27 28 29 |
# File 'lib/terraform/gcp/linux/scan/scan_service.rb', line 25 def load_config JSON.parse(File.read(CONFIG_PATH)) rescue StandardError => e { 'error' => "Cannot read #{CONFIG_PATH}: #{e.class}: #{e.}" } end |
#parse_ciscat_json(path) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/terraform/gcp/linux/scan/scan_service.rb', line 94 def parse_ciscat_json(path) return { 'error' => "Result file missing: #{path}" } unless File.exist?(path) raw = JSON.parse(File.read(path)) results = (raw['rules'] || []).map do |r| { 'id' => r['rule-id'], 'result' => r['result'], } end score = (raw['score'] || 0.0).to_f counts = results.group_by { |r| (r['result'] || '').to_s.downcase }.transform_values(&:size) { 'score' => score, 'passed_count' => counts['pass'] || 0, 'failed_count' => counts['fail'] || 0, 'not_applicable_count' => (counts['notchecked'] || 0) + (counts['notapplicable'] || 0), 'error_count' => (counts['error'] || 0) + (counts['informational'] || 0), 'rules' => results, } end |
#parse_openscap_xml(path) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/terraform/gcp/linux/scan/scan_service.rb', line 50 def parse_openscap_xml(path) return { 'error' => "Result file missing: #{path}" } unless File.exist?(path) doc = REXML::Document.new(File.read(path)) results = REXML::XPath.match(doc, '//rule-result').map do |r| { 'id' => r.attributes['idref'], 'severity' => r.attributes['severity'], 'result' => REXML::XPath.first(r, 'result')&.text, } end score_el = REXML::XPath.first(doc, '//score') score = score_el ? score_el.text.to_f : 0.0 counts = results.group_by { |r| r['result'] }.transform_values(&:size) { 'score' => score, 'passed_count' => counts['pass'] || 0, 'failed_count' => counts['fail'] || 0, 'not_applicable_count' => (counts['notapplicable'] || 0) + (counts['notselected'] || 0), 'error_count' => (counts['error'] || 0) + (counts['unknown'] || 0), 'rules' => results, } end |
#perform_scan ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/terraform/gcp/linux/scan/scan_service.rb', line 116 def perform_scan cfg = load_config return cfg if cfg['error'] case cfg['scanner'] when 'openscap' run_openscap(cfg['profile'], cfg['datastream']) when 'ciscat' run_ciscat(cfg['profile'], cfg['benchmark']) else { 'error' => "Unknown scanner '#{cfg['scanner']}'" } end end |
#run_ciscat(profile, benchmark) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/terraform/gcp/linux/scan/scan_service.rb', line 74 def run_ciscat(profile, benchmark) json_out = File.join(REPORT_DIR, 'ciscat-results.json') cmd = [ 'sudo', '/opt/cis-cat-pro/Assessor-CLI.sh', '-rd', REPORT_DIR, '-rp', 'ciscat-results', '-nts', '-json', '-p', profile, ] cmd += ['-b', "/opt/cis-cat-pro/benchmarks/#{benchmark}"] if benchmark _stdout, stderr, status = Open3.capture3(*cmd) parsed = parse_ciscat_json(json_out) unless status.success? || File.exist?(json_out) assessor_msg = "Assessor-CLI exited #{status.exitstatus}: #{stderr.strip}" parsed['error'] = parsed['error'] ? "#{assessor_msg}; #{parsed['error']}" : assessor_msg end parsed end |
#run_openscap(profile, datastream) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/terraform/gcp/linux/scan/scan_service.rb', line 31 def run_openscap(profile, datastream) xml_out = File.join(REPORT_DIR, 'openscap-results.xml') html_out = File.join(REPORT_DIR, 'openscap-results.html') cmd = [ 'sudo', 'oscap', 'xccdf', 'eval', '--profile', profile, '--results', xml_out, '--report', html_out, datastream, ] _stdout, stderr, status = Open3.capture3(*cmd) parsed = parse_openscap_xml(xml_out) unless status.success? || File.exist?(xml_out) oscap_msg = "oscap exited #{status.exitstatus}: #{stderr.strip}" parsed['error'] = parsed['error'] ? "#{oscap_msg}; #{parsed['error']}" : oscap_msg end parsed end |