[VVP] Adding bandit security scans and fixes 08/91908/3
authorLovett, Trevor <trevor.lovett@att.com>
Tue, 23 Jul 2019 23:09:09 +0000 (18:09 -0500)
committerLovett, Trevor (tl2972) <tl2972@att.com>
Wed, 24 Jul 2019 13:13:17 +0000 (08:13 -0500)
Issue-ID: VVP-244

Change-Id: Ia782f4cc7bf5a379ff8cdcce96cd2e7235998345
Signed-off-by: Lovett, Trevor <trevor.lovett@att.com>
bandit.yaml [new file with mode: 0644]
checks.py
ice_validator/app_tests/test_app_config.py
ice_validator/tests/cached_yaml.py
ice_validator/tests/conftest.py
ice_validator/tests/test_initial_configuration.py
ice_validator/vvp.py
tox.ini
update_reqs.py

diff --git a/bandit.yaml b/bandit.yaml
new file mode 100644 (file)
index 0000000..46410b0
--- /dev/null
@@ -0,0 +1,38 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#             http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#             https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END============================================
+#
+skips: ['B101']
index cde601a..b43d6c7 100644 (file)
--- a/checks.py
+++ b/checks.py
 #
 # ============LICENSE_END============================================
 #
+import contextlib
 import csv
+import io
 import json
 import os
-import subprocess
+import subprocess  #nosec
 import sys
 
 import pytest
+from flake8.main.application import Application
 
 from update_reqs import get_requirements
 
@@ -167,14 +170,24 @@ def check_non_testable_requirements_are_not_mapped():
 
 
 def check_flake8_passes():
-    result = subprocess.run(
-        ["flake8", "."],
-        encoding="utf-8",
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-    )
+    output = io.StringIO()
+    with contextlib.redirect_stdout(output), contextlib.redirect_stderr(output):
+        app = Application()
+        app.run(["ice_validator"])
+    output.seek(0)
+    lines = [f"   {l}" for l in output.readlines()]
+    return ["flake8 errors detected:"] + lines if lines else []
+
+
+def check_bandit_passes():
+    result = subprocess.run(                                            #nosec
+        ["bandit", "-c", "bandit.yaml", "-r", ".", "-x", "./.tox/**"],  #nosec
+        encoding="utf-8",                                               #nosec
+        stdout=subprocess.PIPE,                                         #nosec
+        stderr=subprocess.PIPE,                                         #nosec
+    )                                                                   #nosec
     msgs = result.stdout.split("\n") if result.returncode != 0 else []
-    return ["flake8 errors detected:"] + [f"  {e}" for e in msgs] if msgs else []
+    return ["bandit errors detected:"] + [f"  {e}" for e in msgs] if msgs else []
 
 
 if __name__ == "__main__":
@@ -184,6 +197,7 @@ if __name__ == "__main__":
         check_testable_requirements_are_mapped,
         check_non_testable_requirements_are_not_mapped,
         check_flake8_passes,
+        check_bandit_passes,
     ]
     results = [check() for check in checks]
     errors = "\n".join("\n".join(msg) for msg in results if msg)
index 223006f..a021b53 100644 (file)
@@ -62,7 +62,7 @@ settings:
 # noinspection PyShadowingNames
 @pytest.fixture(scope="module")
 def config():
-    return vvp.Config(yaml.load(StringIO(DEFAULT_CONFIG)))
+    return vvp.Config(yaml.safe_load(StringIO(DEFAULT_CONFIG)))
 
 
 def test_app_name(config):
@@ -114,7 +114,7 @@ settings:
 
 
 def test_missing_category_fields():
-    settings = yaml.load(StringIO(MISSING_CATEGORY_FIELD))
+    settings = yaml.safe_load(StringIO(MISSING_CATEGORY_FIELD))
     with pytest.raises(RuntimeError) as e:
         vvp.Config(settings)
     assert "Missing: name" in str(e)
index 1b977a6..196d9b8 100644 (file)
@@ -55,3 +55,6 @@ def load(fp):
     if abs_path not in YAML_CACHE:
         YAML_CACHE[abs_path] = yaml.safe_load(fp)
     return YAML_CACHE[abs_path]
+
+
+safe_load = load
index e3c21e6..5653cca 100644 (file)
@@ -963,7 +963,7 @@ def hash_directory(path):
     :param path: string directory containing files
     :return: string MD5 hash code (hex)
     """
-    md5 = hashlib.md5()
+    md5 = hashlib.md5()  # nosec
     for dir_path, sub_dirs, filenames in os.walk(path):
         for filename in filenames:
             file_path = os.path.join(dir_path, filename)
index f911ce9..654d75d 100644 (file)
@@ -80,7 +80,7 @@ def test_02_no_duplicate_keys_in_file(yaml_file):
 
     try:
         with open(yaml_file) as fh:
-            normal_yaml.load(fh)
+            normal_yaml.safe_load(fh)
     except ConstructorError as e:
         pytest.fail("{} {}".format(e.problem, e.problem_mark))
 
@@ -93,7 +93,7 @@ def test_03_all_referenced_resources_exists(yaml_file):
     actually exists in all yaml files
     """
     with open(yaml_file) as fh:
-        yml = yaml.load(fh)
+        yml = yaml.safe_load(fh)
 
     # skip if resources are not defined
     if "resources" not in yml:
index 547a3b4..43baee0 100644 (file)
@@ -367,7 +367,7 @@ class Config:
             self._config = config
         else:
             with open(self.DEFAULT_FILENAME, "r") as f:
-                self._config = yaml.load(f)
+                self._config = yaml.safe_load(f)
         self._user_settings = UserSettings(
             self._config["namespace"], self._config["owner"]
         )
diff --git a/tox.ini b/tox.ini
index a4217bb..84e1b14 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -50,10 +50,12 @@ commands =
     coverage xml
     flake8 --version
     flake8 ice_validator
+    bandit -c bandit.yaml -r . -x ./.tox/**,./venv-tox/**
 deps = --no-use-pep517 
     -rrequirements.txt
-    flake8==3.6.0
-    coverage==4.5.1
+    flake8
+    coverage
+    bandit
 
 
 [flake8]
index 304b479..0a53ec9 100644 (file)
@@ -54,7 +54,7 @@ THIS_DIR = os.path.dirname(os.path.abspath(__file__))
 
 def get_requirements():
     """Retrieves the binary JSON content fom REQS_URL"""
-    return request.urlopen(REQS_URL)
+    return request.urlopen(REQS_URL)  # nosec
 
 
 def write_file(contents, path):