diff --git a/.bandit b/.bandit new file mode 100644 index 0000000..6e4e7d2 --- /dev/null +++ b/.bandit @@ -0,0 +1,2 @@ +[bandit] +exclude: /tests diff --git a/README.md b/README.md index bebe157..3f1d813 100644 --- a/README.md +++ b/README.md @@ -94,3 +94,24 @@ flask db migrate flask db upgrade flask run ``` + +Security Scans +-------------- + +This repository uses the [bandit](https://github.com/openstack/bandit) +tool to run automated static analysis of the project code for +potential vulnerabilities. These are run automatically as part of +continuous integration to identify potential vulnerabilities when they +are introduced in pull requests. + +You can run bandit locally with the following command: + +``` shell +bandit -r . +``` + +In some cases, bandit will identify false positives, code that looks +like it could be a security vulnerability but that will likely never +be triggered in a production environment. To disable reporting of +these vulnerabilities, you can append a `#nosec` comment on the line +of code where the vulnerability was identified. diff --git a/circle.yml b/circle.yml index 66f7499..25447fd 100644 --- a/circle.yml +++ b/circle.yml @@ -19,6 +19,7 @@ test: - py.test --cov=crime_data tests/ post: - codeclimate-test-reporter + - bandit -r . deployment: production: branch: master diff --git a/crime_data/app.py b/crime_data/app.py index aa88d7a..7a195b2 100644 --- a/crime_data/app.py +++ b/crime_data/app.py @@ -26,7 +26,7 @@ from crime_data.settings import ProdConfig if __name__ == '__main__': - app.run(debug=True) + app.run(debug=True) #nosec, this isn't called on production def create_app(config_object=ProdConfig): diff --git a/crime_data/commands.py b/crime_data/commands.py index bdd113b..833ad5e 100644 --- a/crime_data/commands.py +++ b/crime_data/commands.py @@ -2,7 +2,7 @@ """Click commands.""" import os from glob import glob -from subprocess import call +from subprocess import call #nosec import click from flask import current_app @@ -43,7 +43,7 @@ def execute_tool(description, *args): """Execute a checking tool with its arguments.""" command_line = list(args) + files_and_directories click.echo('{}: {}'.format(description, ' '.join(command_line))) - rv = call(command_line) + rv = call(command_line) #nosec if rv != 0: exit(rv) diff --git a/crime_data/common/base.py b/crime_data/common/base.py index c65ec58..1bee60a 100644 --- a/crime_data/common/base.py +++ b/crime_data/common/base.py @@ -3,6 +3,7 @@ import math import os import random +from ast import literal_eval from functools import wraps import sqltap @@ -87,7 +88,7 @@ def use_follower(self): def get_bind(self, mapper=None, clause=None): if self.use_follower: - return random.choice(self.followers) + return random.choice(self.followers) #nosec return super().get_bind(mapper=mapper, clause=clause) @@ -310,7 +311,7 @@ def output_serialize(self, data, schema=None, format='csv', aggregate_many = Fal def _jsonable(self, val): if isinstance(val, Decimal): - return eval(str(val)) + return literal_eval(str(val)) elif hasattr(val, '__pow__'): # is numeric return val return str(val) @@ -325,8 +326,6 @@ def _stringify(self, data): def _as_dict(self, fieldTuple, res): return dict(zip(fieldTuple, res)) - - def _compile_query(self, query): """ Gets String representation of an SQLAlchemy query. diff --git a/requirements/dev.txt b/requirements/dev.txt index 71c395c..d4936f6 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -20,3 +20,5 @@ pep8-naming==0.3.3 codeclimate-test-reporter pytest-cov + +bandit==1.3.0