foreman_cve_scanner 0.0.2 → 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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -16
  3. data/Rakefile +2 -0
  4. data/app/controllers/api/v2/cve_scans_controller.rb +66 -0
  5. data/app/lib/actions/foreman_cve_scanner/cve_scanner_job.rb +3 -18
  6. data/app/models/concerns/foreman_cve_scanner/host_extensions.rb +16 -0
  7. data/app/models/foreman_cve_scanner/cve_scan.rb +15 -0
  8. data/app/models/host_status/cve_status.rb +71 -0
  9. data/app/services/foreman_cve_scanner/cve_report_scanner.rb +37 -35
  10. data/app/services/foreman_cve_scanner/scan_importer.rb +105 -0
  11. data/app/views/api/v2/cve_scans/base.json.rabl +5 -0
  12. data/app/views/api/v2/cve_scans/index.json.rabl +5 -0
  13. data/app/views/api/v2/cve_scans/latest.json.rabl +5 -0
  14. data/app/views/api/v2/cve_scans/main.json.rabl +7 -0
  15. data/app/views/api/v2/cve_scans/show.json.rabl +5 -0
  16. data/app/views/foreman_cve_scanner/job_templates/run_cve_scanner.erb +4 -2
  17. data/config/routes.rb +20 -0
  18. data/db/migrate/20260221000000_create_foreman_cve_scanner_cve_scans.rb +22 -0
  19. data/db/seeds.d/75_job_templates.rb +17 -0
  20. data/lib/foreman_cve_scanner/engine.rb +25 -3
  21. data/lib/foreman_cve_scanner/version.rb +3 -1
  22. data/lib/foreman_cve_scanner.rb +4 -1
  23. data/lib/tasks/foreman_cve_scanner_seeds.rake +12 -0
  24. data/lib/tasks/rubocop.rake +33 -0
  25. data/package.json +48 -0
  26. data/test/actions/foreman_cve_scanner/cve_scanner_job_test.rb +54 -0
  27. data/test/controllers/api/v2/cve_scans_controller_test.rb +78 -0
  28. data/test/models/host_status/cve_status_test.rb +65 -0
  29. data/test/services/foreman_cve_scanner/cve_report_scanner_test.rb +45 -17
  30. data/test/services/foreman_cve_scanner/scan_importer_test.rb +85 -0
  31. data/test/test_plugin_helper.rb +2 -0
  32. data/webpack/components/CveDetailsCard.js +258 -0
  33. data/webpack/components/CveFindingsModal.js +274 -0
  34. data/webpack/components/CveHistoryTable.js +58 -0
  35. data/webpack/components/CveOverviewCard.js +67 -0
  36. data/webpack/components/CveScansTab.js +192 -0
  37. data/webpack/components/CveSummaryCell.js +72 -0
  38. data/webpack/components/SeverityIcon.js +56 -0
  39. data/webpack/components/__tests__/CveDetailsCard.test.js +126 -0
  40. data/webpack/components/__tests__/CveFindingsModal.test.js +78 -0
  41. data/webpack/components/__tests__/CveScansTab.test.js +76 -0
  42. data/webpack/components/__tests__/cve_helpers.test.js +42 -0
  43. data/webpack/components/cve_helpers.js +35 -0
  44. data/webpack/components/cve_scans.scss +200 -0
  45. data/webpack/fills.js +1 -0
  46. data/webpack/fills_index.js +38 -0
  47. data/webpack/index.js +1 -0
  48. metadata +49 -5
@@ -1,21 +1,43 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'foreman_remote_execution'
2
4
 
3
5
  module ForemanCveScanner
6
+ # Rails engine for the Foreman CVE Scanner plugin.
4
7
  class Engine < ::Rails::Engine
5
8
  engine_name 'foreman_cve_scanner'
6
9
 
7
- initializer 'foreman_cve_scanner.register_plugin', :before => :finisher_hook do |app|
10
+ initializer 'foreman_cve_scanner.load_app_instance_data' do |app|
11
+ ForemanCveScanner::Engine.paths['db/migrate'].existent.each do |path|
12
+ app.config.paths['db/migrate'] << path
13
+ end
14
+ end
15
+
16
+ initializer 'foreman_cve_scanner.register_plugin', before: :finisher_hook do |app|
8
17
  app.reloader.to_prepare do
9
18
  Foreman::Plugin.register :foreman_cve_scanner do
10
19
  requires_foreman '>= 3.13'
11
- register_report_scanner ForemanCveScanner::CveReportScanner
12
- register_report_origin 'CveScanner', 'ConfigReport'
20
+ register_global_js_file 'fills'
21
+
22
+ apipie_documented_controllers ["#{ForemanCveScanner::Engine.root}/app/controllers/api/v2/*.rb"]
23
+
24
+ security_block :foreman_cve_scanner do
25
+ permission :view_cve_scans,
26
+ { 'api/v2/cve_scans': %i[index latest show destroy] },
27
+ resource_type: 'Host'
28
+ end
29
+
30
+ add_all_permissions_to_default_roles
13
31
  end
14
32
  end
15
33
  end
16
34
 
17
35
  # Include concerns in this config.to_prepare block
18
36
  config.to_prepare do
37
+ require_dependency 'foreman_cve_scanner/host_extensions'
38
+ Host::Managed.include ForemanCveScanner::HostExtensions
39
+ require_dependency 'host_status/cve_status'
40
+ HostStatus.status_registry.add(HostStatus::CveStatus)
19
41
  ForemanCveScanner::Engine.register_rex_features
20
42
  end
21
43
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanCveScanner
2
- VERSION = '0.0.2'.freeze
4
+ VERSION = '0.5.0'
3
5
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'foreman_cve_scanner/engine'
2
4
 
3
- module ForemanPluginTemplate
5
+ # Foreman CVE Scanner plugin namespace.
6
+ module ForemanCveScanner
4
7
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :foreman_cve_scanner do
4
+ desc 'Seed Foreman CVE Scanner job templates'
5
+ task seed_job_templates: :environment do
6
+ require Rails.root.join('lib/seed_helper')
7
+ require 'foreman_remote_execution'
8
+ paths = Dir["#{ForemanCveScanner::Engine.root}/app/views/foreman_cve_scanner/job_templates/*.erb"]
9
+ SeedHelper.import_templates(paths, 'ForemanCveScanner')
10
+ puts "Seeded #{paths.size} Foreman CVE Scanner job templates"
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'rubocop/rake_task'
5
+
6
+ test_patterns = [
7
+ "#{ForemanCveScanner::Engine.root}/*.gemspec",
8
+ "#{ForemanCveScanner::Engine.root}/*.rb",
9
+ "#{ForemanCveScanner::Engine.root}/app/**/*.rb",
10
+ "#{ForemanCveScanner::Engine.root}/config/**/*.rb",
11
+ "#{ForemanCveScanner::Engine.root}/db/**/*.rb",
12
+ "#{ForemanCveScanner::Engine.root}/lib/**/*.rake",
13
+ "#{ForemanCveScanner::Engine.root}/lib/**/*.rb",
14
+ "#{ForemanCveScanner::Engine.root}/test/**/*.rb",
15
+ ]
16
+
17
+ namespace :foreman_cve_scanner do
18
+ desc 'Runs Rubocop style checker'
19
+ RuboCop::RakeTask.new(:rubocop) do |task|
20
+ task.patterns = test_patterns
21
+ end
22
+
23
+ desc 'Runs Rubocop style checker with xml output for Jenkins'
24
+ RuboCop::RakeTask.new('rubocop:jenkins') do |task|
25
+ task.patterns = test_patterns
26
+ task.requires = ['rubocop/formatter/checkstyle_formatter']
27
+ task.formatters = ['RuboCop::Formatter::CheckstyleFormatter']
28
+ task.options = ['--no-color', '--out', 'rubocop.xml']
29
+ end
30
+ end
31
+ rescue LoadError
32
+ # 'Rubocop not loaded.'
33
+ end
data/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "foreman_cve_scanner",
3
+ "version": "0.5.0",
4
+ "description": "Run CVE scan on host and collect report",
5
+ "main": "webpack/index.js",
6
+ "directories": {
7
+ "lib": "lib",
8
+ "test": "test"
9
+ },
10
+ "scripts": {
11
+ "lint": "tfm-lint --plugin -d /webpack",
12
+ "test": "tfm-test --plugin",
13
+ "create-react-component": "yo react-domain"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+ssh://git@github.com/ATIX-AG/foreman_cve_scanner.git"
18
+ },
19
+ "peerDependencies": {
20
+ "@theforeman/vendor": ">= 8.16.0"
21
+ },
22
+ "devDependencies": {
23
+ "@babel/core": "^7.7.0",
24
+ "@theforeman/builder": "^15.0.0",
25
+ "@theforeman/eslint-plugin-foreman": "^15.0.0",
26
+ "@theforeman/find-foreman": "^15.0.0",
27
+ "@theforeman/vendor-dev": "^15.0.0",
28
+ "babel-eslint": ">= 10.0.3",
29
+ "eslint": "^6.7.2",
30
+ "eslint-plugin-react": ">= 7.27.1",
31
+ "eslint-plugin-react-hooks": ">= 4.3.0",
32
+ "eslint-plugin-spellcheck": ">= 0.0.17",
33
+ "prettier": "^1.19.1"
34
+ },
35
+ "keywords": [
36
+ "CVE",
37
+ "Trivy",
38
+ "Grype",
39
+ "security",
40
+ "Foreman"
41
+ ],
42
+ "author": "ATIX AG",
43
+ "license": "GPL-3.0",
44
+ "bugs": {
45
+ "url": "https://github.com/ATIX-AG/foreman_cve_scanner/issues"
46
+ },
47
+ "homepage": "https://github.com/ATIX-AG/foreman_cve_scanner#readme"
48
+ }
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ module ForemanCveScanner
6
+ class CveScannerJobTest < ActiveSupport::TestCase
7
+ def setup
8
+ @host = FactoryBot.create(:host)
9
+ end
10
+
11
+ test 'format_output parses json between markers across proxy output entries' do
12
+ job_output = {
13
+ 'proxy_output' => {
14
+ 'result' => [
15
+ { 'output_type' => 'stdout', 'output' => "===START\n{\"key\":" },
16
+ { 'output_type' => 'stdout', 'output' => "1}\n===END\n" },
17
+ ],
18
+ },
19
+ }
20
+
21
+ importer = ForemanCveScanner::ScanImporter.new(job_output)
22
+ parsed = importer.send(:format_output, job_output)
23
+
24
+ assert_equal({ 'key' => 1 }, parsed)
25
+ end
26
+
27
+ test 'persist_scan! stores scan and metrics' do
28
+ scan_json = JSON.parse(
29
+ File.read(File.join(ForemanCveScanner::Engine.root, 'test/fixtures/trivy.json'))
30
+ )
31
+
32
+ importer = ForemanCveScanner::ScanImporter.new('')
33
+ scan = importer.send(:persist_scan!, @host, 'trivy', scan_json)
34
+
35
+ assert scan.persisted?
36
+ assert scan.total.positive?
37
+ assert_equal @host.id, scan.host_id
38
+ end
39
+
40
+ test 'import_for_host! creates scan from rex output' do
41
+ output = [
42
+ '===START',
43
+ File.read(File.join(ForemanCveScanner::Engine.root, 'test/fixtures/trivy.json')),
44
+ '===END',
45
+ ].join("\n")
46
+
47
+ importer = ForemanCveScanner::ScanImporter.new(output)
48
+ scan = importer.import_for_host!(@host)
49
+
50
+ assert scan.persisted?
51
+ assert_equal @host.id, scan.host_id
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ module Api
6
+ module V2
7
+ class CveScansControllerTest < ActionController::TestCase
8
+ def setup
9
+ @host = FactoryBot.create(:host)
10
+ @scan_old = create_scan(created_at: 2.hours.ago, total: 1, low: 1)
11
+ @scan_new = create_scan(created_at: 1.hour.ago, total: 2, high: 2)
12
+ end
13
+
14
+ test 'index returns scans for host' do
15
+ get :index, params: { host_id: @host.id }
16
+ assert_response :success
17
+ body = ActiveSupport::JSON.decode(@response.body)
18
+ assert_not_nil body['results']
19
+ assert_equal 2, body['results'].size
20
+ end
21
+
22
+ test 'latest returns most recent scan' do
23
+ get :latest, params: { host_id: @host.id }
24
+ assert_response :success
25
+ body = ActiveSupport::JSON.decode(@response.body)
26
+ assert_equal @scan_new.id, body['id']
27
+ end
28
+
29
+ test 'show returns scan by id' do
30
+ get :show, params: { host_id: @host.id, id: @scan_old.id }
31
+ assert_response :success
32
+ body = ActiveSupport::JSON.decode(@response.body)
33
+ assert_equal @scan_old.id, body['id']
34
+ end
35
+
36
+ test 'index returns not found for unknown host' do
37
+ get :index, params: { host_id: 'does-not-exist' }
38
+ assert_response :not_found
39
+ end
40
+
41
+ test 'latest returns no content when no scans exist' do
42
+ ForemanCveScanner::CveScan.delete_all
43
+
44
+ get :latest, params: { host_id: @host.id }
45
+ assert_response :no_content
46
+ end
47
+
48
+ private
49
+
50
+ # rubocop:disable Metrics/MethodLength
51
+ def create_scan(options = {})
52
+ defaults = {
53
+ created_at: Time.now.utc,
54
+ total: 0,
55
+ critical: 0,
56
+ high: 0,
57
+ medium: 0,
58
+ low: 0,
59
+ }
60
+ options = defaults.merge(options)
61
+ ForemanCveScanner::CveScan.create!(
62
+ host: @host,
63
+ scanner: 'trivy',
64
+ created_at: options[:created_at],
65
+ raw: { 'dummy' => true },
66
+ summary: { 'worst' => 'low' },
67
+ findings: [{ 'id' => 'CVE-0000-0000' }],
68
+ total: options[:total],
69
+ critical: options[:critical],
70
+ high: options[:high],
71
+ medium: options[:medium],
72
+ low: options[:low]
73
+ )
74
+ end
75
+ # rubocop:enable Metrics/MethodLength
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ module HostStatus
6
+ class CveStatusTest < ActiveSupport::TestCase
7
+ def setup
8
+ @host = FactoryBot.create(:host)
9
+ end
10
+
11
+ test 'no scans returns warning status' do
12
+ status = @host.get_status(HostStatus::CveStatus)
13
+ assert_equal 'No CVE scans', status.to_label
14
+ assert_equal HostStatus::Global::WARN, status.to_global
15
+ assert_equal 0, status.to_status
16
+ end
17
+
18
+ test 'critical or high scan returns error status' do
19
+ create_scan(critical: 1, high: 0, medium: 0, low: 0)
20
+ status = @host.get_status(HostStatus::CveStatus)
21
+ assert_equal 'Critical or high CVEs', status.to_label
22
+ assert_equal HostStatus::Global::ERROR, status.to_global
23
+ assert_equal 3, status.to_status
24
+ end
25
+
26
+ test 'medium scan returns warn status' do
27
+ create_scan(critical: 0, high: 0, medium: 2, low: 0)
28
+ status = @host.get_status(HostStatus::CveStatus)
29
+ assert_equal 'Medium CVEs', status.to_label
30
+ assert_equal HostStatus::Global::WARN, status.to_global
31
+ assert_equal 2, status.to_status
32
+ end
33
+
34
+ test 'low scan returns ok status' do
35
+ create_scan(critical: 0, high: 0, medium: 0, low: 1)
36
+ status = @host.get_status(HostStatus::CveStatus)
37
+ assert_equal 'Low CVEs', status.to_label
38
+ assert_equal HostStatus::Global::OK, status.to_global
39
+ assert_equal 1, status.to_status
40
+ end
41
+
42
+ test 'status is registered in registry' do
43
+ assert_includes HostStatus.status_registry, HostStatus::CveStatus
44
+ end
45
+
46
+ private
47
+
48
+ def create_scan(critical:, high:, medium:, low:)
49
+ total = critical + high + medium + low
50
+ ForemanCveScanner::CveScan.create!(
51
+ host: @host,
52
+ scanner: 'trivy',
53
+ created_at: Time.now.utc,
54
+ raw: { 'dummy' => true },
55
+ summary: { 'worst' => 'low' },
56
+ findings: [{ 'id' => 'CVE-0000-0000' }],
57
+ total: total,
58
+ critical: critical,
59
+ high: high,
60
+ medium: medium,
61
+ low: low
62
+ )
63
+ end
64
+ end
65
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_plugin_helper'
2
4
 
3
5
  module ForemanCveScanner
@@ -5,9 +7,9 @@ module ForemanCveScanner
5
7
  test 'should identify as cve scan' do
6
8
  raw = {
7
9
  'reporter' => 'cve_scan',
8
- 'scan' => JSON.parse(File.read(File.join(ForemanCveScanner::Engine.root, 'test/fixtures/grype.json')))
10
+ 'scan' => JSON.parse(File.read(File.join(ForemanCveScanner::Engine.root, 'test/fixtures/grype.json'))),
9
11
  }
10
- assert_equal ForemanCveScanner::CveReportScanner.identify_origin(raw), 'CveScanner'
12
+ assert_equal('CveScanner', ForemanCveScanner::CveReportScanner.identify_origin(raw))
11
13
  end
12
14
 
13
15
  test 'should raise an exception if invalid report' do
@@ -18,26 +20,52 @@ module ForemanCveScanner
18
20
 
19
21
  test 'trivy scan has valid data' do
20
22
  data = JSON.parse(File.read(File.join(ForemanCveScanner::Engine.root, 'test/fixtures/trivy.json')))
21
- raw = {
22
- 'reporter' => 'cve_scan',
23
- 'scan' => data
24
- }
25
- ForemanCveScanner::CveReportScanner.add_reporter_data(nil, raw)
26
- assert_equal raw['logs'].count, 10
27
- assert_equal raw['logs'][0]['log']['level'], 'info'
28
- assert_equal raw['logs'][0]['log']['messages']['message'], 'CVE-2020-12762: json-c, libfastjson: integer overflow and out-of-bounds write via a large JSON file # url: https://avd.aquasec.com/nvd/cve-2020-12762'
23
+ scanner = ForemanCveScanner::CveReportScanner.new('scan' => data)
24
+ scanner.generate
25
+ assert_equal(10, scanner.logs.count)
26
+ assert_equal('info', scanner.logs[0]['log']['level'])
27
+ expected_message = [
28
+ 'CVE-2020-12762: json-c, libfastjson: integer overflow and out-of-',
29
+ 'bounds write via a large JSON file # url: ',
30
+ 'https://avd.aquasec.com/nvd/cve-2020-12762',
31
+ ].join
32
+ assert_equal scanner.logs[0]['log']['messages']['message'], expected_message
29
33
  end
30
34
 
31
35
  test 'grype scan has valid data' do
32
36
  data = JSON.parse(File.read(File.join(ForemanCveScanner::Engine.root, 'test/fixtures/grype.json')))
33
- raw = {
34
- 'reporter' => 'cve_scan',
35
- 'scan' => data
37
+ scanner = ForemanCveScanner::CveReportScanner.new('scan' => data)
38
+ scanner.generate
39
+ assert_equal(18, scanner.logs.count)
40
+ first_severity = data.dig('matches', 0, 'vulnerability', 'severity')
41
+ expected_level = expected_level_for(first_severity)
42
+ assert_equal scanner.logs[0]['log']['level'], expected_level
43
+ expected_message = [
44
+ 'CVE-2007-0086: The Apache HTTP Server, when accessed through a TCP ',
45
+ 'connection with a large window size, allows remote attackers to cause ',
46
+ 'a denial of service (network bandwidth consumption) via a Range header ',
47
+ 'that specifies multiple copies of the same fragment. # url: ',
48
+ 'https://nvd.nist.gov/vuln/detail/CVE-2007-0086',
49
+ ].join
50
+ assert_equal scanner.logs[0]['log']['messages']['message'], expected_message
51
+ end
52
+
53
+ test 'detect_scanner returns expected scanner names' do
54
+ assert_equal 'grype', ForemanCveScanner::CveReportScanner.detect_scanner('matches' => [])
55
+ assert_equal 'trivy', ForemanCveScanner::CveReportScanner.detect_scanner('Results' => [])
56
+ assert_equal 'unknown', ForemanCveScanner::CveReportScanner.detect_scanner('foo' => 'bar')
57
+ end
58
+
59
+ private
60
+
61
+ def expected_level_for(severity)
62
+ map = {
63
+ 'CRITICAL' => 'err',
64
+ 'HIGH' => 'warning',
65
+ 'MEDIUM' => 'info',
66
+ 'LOW' => 'debug',
36
67
  }
37
- ForemanCveScanner::CveReportScanner.add_reporter_data(nil, raw)
38
- assert_equal raw['logs'].count, 18
39
- assert_equal raw['logs'][0]['log']['level'], 'info'
40
- assert_equal raw['logs'][0]['log']['messages']['message'], 'CVE-2007-0086: The Apache HTTP Server, when accessed through a TCP connection with a large window size, allows remote attackers to cause a denial of service (network bandwidth consumption) via a Range header that specifies multiple copies of the same fragment. # url: https://nvd.nist.gov/vuln/detail/CVE-2007-0086'
68
+ map.fetch(severity.to_s.strip.upcase, 'info')
41
69
  end
42
70
  end
43
71
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ module ForemanCveScanner
6
+ class ScanImporterTest < ActiveSupport::TestCase
7
+ def setup
8
+ @host = FactoryBot.create(:host)
9
+ end
10
+
11
+ test 'import_for_host! persists scan from trivy output' do
12
+ output = wrap_output(load_fixture('trivy.json'))
13
+ importer = ForemanCveScanner::ScanImporter.new(output)
14
+
15
+ count_before = ForemanCveScanner::CveScan.count
16
+ scan = importer.import_for_host!(@host)
17
+
18
+ assert_equal count_before + 1, ForemanCveScanner::CveScan.count
19
+ assert_not_nil scan
20
+ assert_equal @host.id, scan.host_id
21
+ assert_equal 'trivy', scan.scanner
22
+ end
23
+
24
+ test 'import_for_host! sets totals and findings for trivy output' do
25
+ output = wrap_output(load_fixture('trivy.json'))
26
+ importer = ForemanCveScanner::ScanImporter.new(output)
27
+
28
+ scan = importer.import_for_host!(@host)
29
+
30
+ assert_operator scan.total, :>, 0
31
+ assert_equal scan.total, scan.findings.count
32
+ end
33
+
34
+ test 'import_for_host! persists scan from proxy output' do
35
+ output = load_fixture('grype.json')
36
+ proxy_output = {
37
+ 'proxy_output' => {
38
+ 'result' => [
39
+ { 'output_type' => 'stdout', 'output' => "===START\n" },
40
+ { 'output_type' => 'stdout', 'output' => output },
41
+ { 'output_type' => 'stdout', 'output' => "\n===END\n" },
42
+ ],
43
+ },
44
+ }
45
+ importer = ForemanCveScanner::ScanImporter.new(proxy_output)
46
+
47
+ scan = importer.import_for_host!(@host)
48
+
49
+ assert_not_nil scan
50
+ assert_equal 'grype', scan.scanner
51
+ assert_operator scan.total, :>, 0
52
+ end
53
+
54
+ test 'import_for_host! returns nil when no json markers' do
55
+ importer = ForemanCveScanner::ScanImporter.new('no markers here')
56
+
57
+ scan = importer.import_for_host!(@host)
58
+
59
+ assert_nil scan
60
+ end
61
+
62
+ test 'import_for_host! returns nil when json is invalid' do
63
+ importer = ForemanCveScanner::ScanImporter.new("===START\n{bad\n===END")
64
+
65
+ scan = importer.import_for_host!(@host)
66
+
67
+ assert_nil scan
68
+ end
69
+
70
+ private
71
+
72
+ def load_fixture(name)
73
+ path = File.join(ForemanCveScanner::Engine.root, 'test/fixtures', name)
74
+ JSON.parse(File.read(path)).to_json
75
+ end
76
+
77
+ def wrap_output(json_text)
78
+ [
79
+ '===START',
80
+ json_text,
81
+ '===END',
82
+ ].join("\n")
83
+ end
84
+ end
85
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This calls the main test_helper in Foreman-core
2
4
  require 'test_helper'
3
5