Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Python 3.9 #650

Merged
merged 6 commits into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,23 @@ jobs:
pip install tox
- name: Run tox
run: tox -e py38

py39:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9]
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r test-requirements.txt
pip install tox
- name: Run tox
run: tox -e py39
166 changes: 4 additions & 162 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,168 +96,10 @@ run Bandit with standard input::

cat examples/imports.py | bandit -

Usage::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally tangential, I think Doug Hellman wrote a plugin to sphinx (or maybe it was Jeff Forcier) that puts the execution output of something in the docs where desired. We could take advantage of that here maybe?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need it, though


$ bandit -h
usage: bandit [-h] [-r] [-a {file,vuln}] [-n CONTEXT_LINES] [-c CONFIG_FILE]
[-p PROFILE] [-t TESTS] [-s SKIPS] [-l] [-i]
[-f {csv,custom,html,json,screen,txt,xml,yaml}]
[--msg-template MSG_TEMPLATE] [-o [OUTPUT_FILE]] [-v] [-d] [-q]
[--ignore-nosec] [-x EXCLUDED_PATHS] [-b BASELINE]
[--ini INI_PATH] [--exit-zero] [--version]
[targets [targets ...]]

Bandit - a Python source code security analyzer

positional arguments:
targets source file(s) or directory(s) to be tested

optional arguments:
-h, --help show this help message and exit
-r, --recursive find and process files in subdirectories
-a {file,vuln}, --aggregate {file,vuln}
aggregate output by vulnerability (default) or by
filename
-n CONTEXT_LINES, --number CONTEXT_LINES
maximum number of code lines to output for each issue
-c CONFIG_FILE, --configfile CONFIG_FILE
optional config file to use for selecting plugins and
overriding defaults
-p PROFILE, --profile PROFILE
profile to use (defaults to executing all tests)
-t TESTS, --tests TESTS
comma-separated list of test IDs to run
-s SKIPS, --skip SKIPS
comma-separated list of test IDs to skip
-l, --level report only issues of a given severity level or higher
(-l for LOW, -ll for MEDIUM, -lll for HIGH)
-i, --confidence report only issues of a given confidence level or
higher (-i for LOW, -ii for MEDIUM, -iii for HIGH)
-f {csv,custom,html,json,screen,txt,xml,yaml}, --format {csv,custom,html,json,screen,txt,xml,yaml}
specify output format
--msg-template MSG_TEMPLATE
specify output message template (only usable with
--format custom), see CUSTOM FORMAT section for list
of available values
-o [OUTPUT_FILE], --output [OUTPUT_FILE]
write report to filename
-v, --verbose output extra information like excluded and included
files
-d, --debug turn on debug mode
-q, --quiet, --silent
only show output in the case of an error
--ignore-nosec do not skip lines with # nosec comments
-x EXCLUDED_PATHS, --exclude EXCLUDED_PATHS
comma-separated list of paths (glob patterns
supported) to exclude from scan (note that these are
in addition to the excluded paths provided in the
config file) (default:
.svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg)
-b BASELINE, --baseline BASELINE
path of a baseline report to compare against (only
JSON-formatted files are accepted)
--ini INI_PATH path to a .bandit file that supplies command line
arguments
--exit-zero exit with 0, even with results found
--version show program's version number and exit

CUSTOM FORMATTING
-----------------

Available tags:

{abspath}, {relpath}, {line}, {test_id},
{severity}, {msg}, {confidence}, {range}

Example usage:

Default template:
bandit -r examples/ --format custom --msg-template \
"{abspath}:{line}: {test_id}[bandit]: {severity}: {msg}"

Provides same output as:
bandit -r examples/ --format custom

Tags can also be formatted in python string.format() style:
bandit -r examples/ --format custom --msg-template \
"{relpath:20.20s}: {line:03}: {test_id:^8}: DEFECT: {msg:>20}"

See python documentation for more information about formatting style:
https://docs.python.org/3/library/string.html

The following tests were discovered and loaded:
-----------------------------------------------

B101 assert_used
B102 exec_used
B103 set_bad_file_permissions
B104 hardcoded_bind_all_interfaces
B105 hardcoded_password_string
B106 hardcoded_password_funcarg
B107 hardcoded_password_default
B108 hardcoded_tmp_directory
B110 try_except_pass
B112 try_except_continue
B201 flask_debug_true
B301 pickle
B302 marshal
B303 md5
B304 ciphers
B305 cipher_modes
B306 mktemp_q
B307 eval
B308 mark_safe
B309 httpsconnection
B310 urllib_urlopen
B311 random
B312 telnetlib
B313 xml_bad_cElementTree
B314 xml_bad_ElementTree
B315 xml_bad_expatreader
B316 xml_bad_expatbuilder
B317 xml_bad_sax
B318 xml_bad_minidom
B319 xml_bad_pulldom
B320 xml_bad_etree
B321 ftplib
B322 input
B323 unverified_context
B324 hashlib_new_insecure_functions
B325 tempnam
B401 import_telnetlib
B402 import_ftplib
B403 import_pickle
B404 import_subprocess
B405 import_xml_etree
B406 import_xml_sax
B407 import_xml_expat
B408 import_xml_minidom
B409 import_xml_pulldom
B410 import_lxml
B411 import_xmlrpclib
B412 import_httpoxy
B413 import_pycrypto
B501 request_with_no_cert_validation
B502 ssl_with_bad_version
B503 ssl_with_bad_defaults
B504 ssl_with_no_version
B505 weak_cryptographic_key
B506 yaml_load
B507 ssh_no_host_key_verification
B601 paramiko_calls
B602 subprocess_popen_with_shell_equals_true
B603 subprocess_without_shell_equals_true
B604 any_other_function_with_shell_equals_true
B605 start_process_with_a_shell
B606 start_process_with_no_shell
B607 start_process_with_partial_path
B608 hardcoded_sql_expressions
B609 linux_commands_wildcard_injection
B610 django_extra_used
B611 django_rawsql_used
B701 jinja2_autoescape_false
B702 use_of_mako_templates
B703 django_mark_safe
For more usage information::

bandit -h


Baseline
--------
Expand Down
10 changes: 10 additions & 0 deletions bandit/plugins/general_hardcoded_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,22 @@ def hardcoded_password_string(context):

"""
node = context.node
print(node._bandit_parent)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left over debugging?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, yes

if isinstance(node._bandit_parent, ast.Assign):
# looks for "candidate='some_string'"
for targ in node._bandit_parent.targets:
if isinstance(targ, ast.Name) and RE_CANDIDATES.search(targ.id):
return _report(node.s)

elif (isinstance(node._bandit_parent, ast.Subscript)
and RE_CANDIDATES.search(node.s)):
# Py39+: looks for "dict[candidate]='some_string'"
# subscript -> index -> string
assign = node._bandit_parent._bandit_parent
if isinstance(assign, ast.Assign) and isinstance(assign.value,
ast.Str):
return _report(assign.value.s)

elif (isinstance(node._bandit_parent, ast.Index)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add a comment that this next block can be removed when Python 3.8 is dropped

and RE_CANDIDATES.search(node.s)):
# looks for "dict[candidate]='some_string'"
Expand Down
29 changes: 29 additions & 0 deletions examples/hardcoded-passwords.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,58 @@
# Possible hardcoded password: 'Admin'
# Severity: Low Confidence: Medium
def someFunction(user, password="Admin"):
print("Hi " + user)

def someFunction2(password):
# Possible hardcoded password: 'root'
# Severity: Low Confidence: Medium

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the way comments are done here is inconsistent (indent & before/after)
maybe these should be docstrings?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it matters that much, so long as there's context around what each one is attempting to warn about. With the exception of the first function here, functions without a real body (e.g., using pass) have the comment outside the function definition and the rest have the comments before (especially since they're call sites). Personally, given the context of this file, I don't care enough. If Eric wants to change that, it's fine that way too. I don't think this is significant enough to warrant him making a second pass though

if password == "root":
print("OK, logged in")

def noMatch(password):
# Possible hardcoded password: ''
# Severity: Low Confidence: Medium
if password == '':
print("No password!")

def NoMatch2(password):
# Possible hardcoded password: 'ajklawejrkl42348swfgkg'
# Severity: Low Confidence: Medium
if password == "ajklawejrkl42348swfgkg":
print("Nice password!")

# Possible hardcoded password: 'blerg'
# Severity: Low Confidence: Medium
def doLogin(password="blerg"):
pass

def NoMatch3(a, b):
pass

# Possible hardcoded password: 'blerg'
# Severity: Low Confidence: Medium
doLogin(password="blerg")

# Possible hardcoded password: 'blerg'
# Severity: Low Confidence: Medium
password = "blerg"

# Possible hardcoded password: 'blerg'
# Severity: Low Confidence: Medium
d["password"] = "blerg"

# Possible hardcoded password: 'secret'
# Severity: Low Confidence: Medium
EMAIL_PASSWORD = "secret"

# Possible hardcoded password: 'emails_secret'
# Severity: Low Confidence: Medium
email_pwd = 'emails_secret'

# Possible hardcoded password: 'd6s$f9g!j8mg7hw?n&2'
# Severity: Low Confidence: Medium
my_secret_password_for_email = 'd6s$f9g!j8mg7hw?n&2'

# Possible hardcoded password: '1234'
# Severity: Low Confidence: Medium
passphrase='1234'
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ classifier =
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Topic :: Security
project_urls =
Release notes = https://github.com/PyCQA/bandit/releases
Expand Down
12 changes: 0 additions & 12 deletions tests/functional/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,6 @@ def test_help_arg(self):
self.assertIn("optional arguments:", output)
self.assertIn("tests were discovered and loaded:", output)

def test_help_in_readme(self):
replace_list = [' ', '\t', '\n']
(retcode, output) = self._test_runtime(['bandit', '-h'])
for i in replace_list:
output = output.replace(i, '')
output = output.replace("'", "\'")
with open('README.rst') as f:
readme = f.read()
for i in replace_list:
readme = readme.replace(i, '')
self.assertIn(output, readme)

# test examples (use _test_example() to wrap in config location argument
def test_example_nonexistent(self):
(retcode, output) = self._test_example(
Expand Down