From 0c9b9f93fcd16987a97e6e954043bba9aa2eae46 Mon Sep 17 00:00:00 2001
From: Ryan Faircloth <35384120+rfaircloth-splunk@users.noreply.github.com>
Date: Mon, 1 Jul 2019 09:54:51 -0400
Subject: [PATCH] Feature/#6 add clair scanner to ci (#7)
Fixes #6 adds vuln scanner and current approved vulns to CI
---
.circleci/config.yml | 32 +++++++++++-
.idea/modules.xml | 8 +++
.idea/splunk-connect-for-syslog.iml | 19 ++++++++
.idea/vcs.xml | 9 ++++
clair-whitelist.yml | 12 +++++
clair_to_junit_parser.py | 75 +++++++++++++++++++++++++++++
requirements.txt | 3 +-
7 files changed, 156 insertions(+), 2 deletions(-)
create mode 100644 .idea/modules.xml
create mode 100644 .idea/splunk-connect-for-syslog.iml
create mode 100644 .idea/vcs.xml
create mode 100644 clair-whitelist.yml
create mode 100644 clair_to_junit_parser.py
diff --git a/.circleci/config.yml b/.circleci/config.yml
index d6d5b9b..419b1fe 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,4 +1,8 @@
version: 2.1
+
+orbs:
+ clair_scanner: ovotech/clair-scanner@1
+
jobs:
build:
environment:
@@ -110,6 +114,27 @@ jobs:
when: always
- store_test_results:
path: test-results
+ test-scan_images:
+ environment:
+ IMAGE_NAME: rfaircloth/scs
+ executor: clair_scanner/default
+ steps:
+ - clair_scanner/scan:
+ image: $IMAGE_NAME:$CIRCLE_SHA1
+ whitelist: clair-whitelist.yml
+ - run:
+ command: |
+ mkdir -p /root/project/test-results
+ pip install -r requirements.txt
+ python clair_to_junit_parser.py "/clair-reports/$IMAGE_NAME:$CIRCLE_SHA1.json" --output test-results/results.xml
+ when: on_fail
+# - store_test_results:
+# path: test-results/results.xml
+ - store_artifacts:
+ path: test-results
+ - store_artifacts:
+ path: /clair-reports
+
publish:
environment:
IMAGE_NAME: rfaircloth/scs
@@ -138,7 +163,12 @@ workflows:
- dgoss:
requires:
- build
- - test-unit
+ - test-unit:
+ requires:
+ - build
+ - test-scan_images:
+ requires:
+ - build
- publish:
requires:
- dgoss
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..4e16e75
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/splunk-connect-for-syslog.iml b/.idea/splunk-connect-for-syslog.iml
new file mode 100644
index 0000000..3ce5619
--- /dev/null
+++ b/.idea/splunk-connect-for-syslog.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..53b20c8
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/clair-whitelist.yml b/clair-whitelist.yml
new file mode 100644
index 0000000..036c034
--- /dev/null
+++ b/clair-whitelist.yml
@@ -0,0 +1,12 @@
+generalwhitelist:
+ RHSA-2019:1619: False Positive
+ RHSA-2018:0654: False Positive
+ RHSA-2018:1967: False Positive
+ RHSA-2017:0372: False Positive
+ RHSA-2018:0502: False Positive
+ RHSA-2018:2772: False Positive
+ RHSA-2018:1374: False Positive
+ RHSA-2018:0180: False Positive
+
+images:
+ scs:
diff --git a/clair_to_junit_parser.py b/clair_to_junit_parser.py
new file mode 100644
index 0000000..e7618cd
--- /dev/null
+++ b/clair_to_junit_parser.py
@@ -0,0 +1,75 @@
+import json
+from junit_xml import TestSuite, TestCase
+import os
+import argparse
+import logging
+
+logger = logging.getLogger('clair_scanner_converter')
+logger.setLevel(logging.WARN)
+console_logger = logging.StreamHandler()
+console_logger.setLevel(logging.WARN)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+console_logger.setFormatter(formatter)
+logger.addHandler(console_logger)
+
+def parse_args():
+ parser = argparse.ArgumentParser(description="Process Json File")
+ parser.add_argument("clairfile", type=str, default=None, help="Location of clair scanner ouptut file to convert to cucumber.json")
+ parser.add_argument("--output", type=str, default=None, help="name of output file to store in new format. Defaults to clair inputfile")
+ args = parser.parse_args()
+ if not args.output:
+ logger.warning("No output file specified, replacing input file.")
+ args.output = args.clairfile
+ return args
+
+def main():
+ cwd = os.getcwd()
+ args = parse_args()
+ try:
+ if os.path.exists(args.clairfile):
+ with open(args.clairfile) as clairfile:
+ clair_parsed_file = json.load(clairfile)
+ if os.path.exists(os.path.join("clair-scanner-logs", "/clair_setup_errors.log")):
+ with open(os.path.join("clair-scanner-logs", "/clair_setup_errors.log"), 'r') as clairfile_errors:
+ clair_parsed_error_file = clairfile_errors.readlines()
+ else:
+ clair_parsed_error_file = None
+ except:
+ logger.exception("Failed to parse clair / clair_error file. Exiting.")
+
+ current_sorted_level = None
+ current_suite = None
+ test_suites = []
+ if clair_parsed_error_file:
+ current_suite = TestSuite("SetupError")
+ new_step = TestCase(name="SetupError", classname="SetupError", status="unapproved", stderr=clair_parsed_error_file)
+ new_step.log = clair_parsed_error_file
+ new_step.category = "SetupError"
+ new_step.failure_type = "unapproved"
+ new_step.failure_message = "Please have the following security issue reviewed by Splunk: {}".format(vuln["link"])
+ new_step.failure_output = clair_parsed_error_file
+ current_suite.test_cases.append(new_step)
+ test_suites.append(current_suite)
+ for vuln in clair_parsed_file["vulnerabilities"]:
+ if current_sorted_level != vuln["severity"]:
+ if current_suite:
+ test_suites.append(current_suite)
+ current_suite = TestSuite(name=vuln["severity"])
+ current_sorted_level = vuln["severity"]
+ new_step = TestCase(name=vuln["vulnerability"], classname=vuln["severity"], status="unapproved", url=vuln["link"], stderr=vuln["description"])
+ new_step.log = vuln
+ new_step.category = vuln["severity"]
+ new_step.failure_type = "unapproved"
+ new_step.failure_message = "Please have the following security issue reviewed by Splunk: {}".format(vuln["link"])
+ new_step.failure_output = vuln["description"]
+ current_suite.test_cases.append(new_step)
+ # try to write new file
+ try:
+ with open(args.output, 'w') as outfile:
+ outfile.write(TestSuite.to_xml_string(test_suites))
+ except:
+ logger.exception("Filed saving file.")
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 7b11f5e..866d712 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
-r ./tests/requirements.txt
-
+junit_xml
+argparse