From: Lovett, Trevor Date: Tue, 23 Jul 2019 23:09:09 +0000 (-0500) Subject: [VVP] Adding bandit security scans and fixes X-Git-Tag: 5.0.0~13^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?p=vvp%2Fvalidation-scripts.git;a=commitdiff_plain;h=b395eb5bb6c79558202a3d414982a56fac7c9e1d [VVP] Adding bandit security scans and fixes Issue-ID: VVP-244 Change-Id: Ia782f4cc7bf5a379ff8cdcce96cd2e7235998345 Signed-off-by: Lovett, Trevor --- diff --git a/bandit.yaml b/bandit.yaml new file mode 100644 index 0000000..46410b0 --- /dev/null +++ b/bandit.yaml @@ -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'] diff --git a/checks.py b/checks.py index cde601a..b43d6c7 100644 --- a/checks.py +++ b/checks.py @@ -35,13 +35,16 @@ # # ============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) diff --git a/ice_validator/app_tests/test_app_config.py b/ice_validator/app_tests/test_app_config.py index 223006f..a021b53 100644 --- a/ice_validator/app_tests/test_app_config.py +++ b/ice_validator/app_tests/test_app_config.py @@ -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) diff --git a/ice_validator/tests/cached_yaml.py b/ice_validator/tests/cached_yaml.py index 1b977a6..196d9b8 100644 --- a/ice_validator/tests/cached_yaml.py +++ b/ice_validator/tests/cached_yaml.py @@ -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 diff --git a/ice_validator/tests/conftest.py b/ice_validator/tests/conftest.py index e3c21e6..5653cca 100644 --- a/ice_validator/tests/conftest.py +++ b/ice_validator/tests/conftest.py @@ -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) diff --git a/ice_validator/tests/test_initial_configuration.py b/ice_validator/tests/test_initial_configuration.py index f911ce9..654d75d 100644 --- a/ice_validator/tests/test_initial_configuration.py +++ b/ice_validator/tests/test_initial_configuration.py @@ -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: diff --git a/ice_validator/vvp.py b/ice_validator/vvp.py index 547a3b4..43baee0 100644 --- a/ice_validator/vvp.py +++ b/ice_validator/vvp.py @@ -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 --- 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] diff --git a/update_reqs.py b/update_reqs.py index 304b479..0a53ec9 100644 --- a/update_reqs.py +++ b/update_reqs.py @@ -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):